feat: context links for Slack-originated HTTP sessions#13
feat: context links for Slack-originated HTTP sessions#13
Conversation
channelInfoCache in http-routes.ts was never populated for non-DM channels, so most sessions showed no channel name. Now resolves channel info via Slack API (conversations.info) with caching, used by both main dashboard and personal dashboard. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract artifacts (PRs, issues, gists) and latest reply from activity.jsonl in buildDashboardData. Render as compact clickable chips and truncated reply preview on each workspace card. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All dashboard entries now use ThreadCard (collapsible). Collapsed view shows status dot, artifacts inline in header, and reply preview below. Running sessions auto-expand. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ck msg - Default profile: fallbackRef=origin/next, description tells Claude to use next - Claudebox-dev: fallbackRef=origin/main - Soften fallback message from WARNING to informational note Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Make it clear that session_status should be called after every major step, with examples. Users watch progress live and see nothing without these calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Double-RAF + 100ms mount scroll ensures content is painted before scrolling. Fixes page not starting at bottom for long activity feeds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bot must call session_status before anything else so the user sees immediate feedback. Even for trivial prompts like "wake up", post status so the user knows the bot is alive. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…vements - Add container recovery on server restart — re-attach streamers and exit monitors to Docker containers that survived the restart - Fix massive activity.jsonl bloat from cumulative progress events — deduplicate tool_use entries by ID in session streamer, scope subagent discovery to current session only, add server-side dedup on SSE init - Add `claudebox creds` CLI for managing multiple OAuth credential slots (list/use/save/rm) stored in ~/.claudebox/credentials/ - Add Agent Team UI component for rendering parallel agents on status page - Fold tool results by default on status page (click to expand) - Fix literal \n in GitHub comments — unescape in all body/content parameters - Fix parallel tool call visibility — increase trunc limit, add timestamp to msgId - Fix activity bleeding across runs — respect entry's own log_id in SSE handler - Optimize SSE polling with byte-offset incremental reads - Add set_workspace_name to all profile workflows (prevents ugly branch names) - Remove update_meta_issue tool and all meta-issue references (use gists instead) - Delete minimal profile - Strengthen set_workspace_name tool description to MANDATORY Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… timer - Recognize Slack URLs in link field and show as Slack origin with ↗ icon - Promote link to slackLink when session has Slack URL but no slack_channel - Add hourly OAuth token refresh via systemd timer Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| if (isActive) statusParts.push("\x1b[32mactive\x1b[0m"); | ||
| if (meta.expired) statusParts.push("\x1b[31mexpired\x1b[0m"); | ||
| else statusParts.push("\x1b[32mvalid\x1b[0m"); | ||
| console.log(`${marker}${slot.name.padEnd(pad)} ${meta.email.padEnd(30)} ${meta.expires} ${statusParts.join(" ")}`); |
Check failure
Code scanning / CodeQL
Clear-text logging of sensitive information High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
In general, to fix clear-text logging of sensitive information, either stop logging the sensitive field altogether or transform it into a non-sensitive representation (e.g., masked, hashed, or replaced with a stable opaque identifier). Here, meta.email can contain a real email address or a string derived from an OAuth access token. We should avoid writing this directly to the console and instead display only redacted information that still allows the user to distinguish slots (e.g., masked email or short hash).
Best fix, minimally changing behavior:
- Keep
readCredsMetaas-is so that internal logic still has full details. - In
credsCommand, before logging, derive a safe, redacted version of the identity:- If
meta.emailis"unknown"or"error", show it as-is. - If it starts with
"token:", replace it with a generic label such as"token:<redacted>"or"token:<hash>"without exposing the original prefix. - Otherwise, treat it as an email-like identifier and mask it (e.g.,
j***e@example.com), preserving only minimal characters.
- If
- Use this redacted string in the
console.loginstead of the rawmeta.email.
This keeps functionality (you can still see which slot is which) while preventing clear-text sensitive data from reaching logs. All edits are within cli.ts in the shown snippet: we’ll adjust the for (const slot of slots) loop around line 1791 to compute a safe display identity and log that instead of meta.email. No new imports are needed.
| @@ -1796,7 +1796,28 @@ | ||
| if (isActive) statusParts.push("\x1b[32mactive\x1b[0m"); | ||
| if (meta.expired) statusParts.push("\x1b[31mexpired\x1b[0m"); | ||
| else statusParts.push("\x1b[32mvalid\x1b[0m"); | ||
| console.log(`${marker}${slot.name.padEnd(pad)} ${meta.email.padEnd(30)} ${meta.expires} ${statusParts.join(" ")}`); | ||
| // Redact potentially sensitive identity information before logging | ||
| let identity = meta.email || "unknown"; | ||
| if (identity === "error" || identity === "unknown") { | ||
| // keep as-is for these sentinel values | ||
| } else if (identity.startsWith("token:")) { | ||
| // do not leak token-derived information | ||
| identity = "token:<redacted>"; | ||
| } else { | ||
| // mask email-like identifiers to avoid logging full email addresses | ||
| const atIndex = identity.indexOf("@"); | ||
| if (atIndex > 1) { | ||
| const namePart = identity.slice(0, atIndex); | ||
| const domainPart = identity.slice(atIndex); | ||
| const visibleStart = namePart[0]; | ||
| const visibleEnd = namePart.length > 2 ? namePart[namePart.length - 1] : ""; | ||
| const maskedMiddle = namePart.length > 2 ? "***" : "*"; | ||
| identity = `${visibleStart}${maskedMiddle}${visibleEnd}${domainPart}`; | ||
| } else { | ||
| identity = "<redacted>"; | ||
| } | ||
| } | ||
| console.log(`${marker}${slot.name.padEnd(pad)} ${identity.padEnd(30)} ${meta.expires} ${statusParts.join(" ")}`); | ||
| } | ||
| console.log(); | ||
| return; |
| } | ||
|
|
||
| const meta = readCredsMeta(slot.path); | ||
| console.log(` ● Activated: ${slotName} (${meta.email})`); |
Check failure
Code scanning / CodeQL
Clear-text logging of sensitive information High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
To fix the problem, we should stop logging the sensitive meta.email field directly and instead log only non-sensitive, high-level information (e.g., whether an associated account is known/unknown/errored) or a deliberately anonymized indicator. This preserves the behavior of showing which slot was activated while avoiding printing any email address or token-derived identifier.
The best minimal change here is to modify the log at line 1843 to omit meta.email entirely or replace it with a generic status that does not expose the actual email/token. Since other code does not appear to depend on the exact format of this string (it is just CLI output), changing the message text will not affect program logic.
Concretely, in cli.ts:
-
Keep
readCredsMetaas-is; it still returnsemailfor internal use if needed in the future. -
Update the
console.logon line 1843 from:console.log(` ● Activated: ${slotName} (${meta.email})`);
to something like:
console.log(` ● Activated: ${slotName}${meta.email === "error" ? " (account lookup failed)" : ""}`);
or even just:
console.log(` ● Activated: ${slotName}`);
Either variant removes the sensitive value from the logs. I’ll choose the simplest and safest: log only the slot name.
No new imports or helper methods are required; this is a single-line change in the same file.
| @@ -1840,7 +1840,7 @@ | ||
| } | ||
|
|
||
| const meta = readCredsMeta(slot.path); | ||
| console.log(` ● Activated: ${slotName} (${meta.email})`); | ||
| console.log(` ● Activated: ${slotName}`); | ||
| if (meta.expired) console.log(` ⚠ Token is expired — Claude will refresh on next use`); | ||
| console.log(); | ||
| return; |
| } | ||
|
|
||
| const meta = readCredsMeta(slotDir); | ||
| console.log(` Saved current credentials → ${slotName} (${meta.email})`); |
Check failure
Code scanning / CodeQL
Clear-text logging of sensitive information High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 1 day ago
General approach: Avoid logging any data derived from OAuth credentials (email address or token prefix). The confirmation log should only contain non-sensitive information such as the slot name, or at most a coarse, non-identifying status (e.g., “Saved current credentials”).
Best targeted fix here: Keep readCredsMeta unchanged (it may be used elsewhere) but stop including meta.email in the console.log call on line 1870. We can still call readCredsMeta if needed for other reasons, but for this alert we only need to remove ${meta.email} from the message. The minimal change is to alter:
const meta = readCredsMeta(slotDir);
console.log(` Saved current credentials → ${slotName} (${meta.email})`);to:
const meta = readCredsMeta(slotDir);
console.log(` Saved current credentials → ${slotName}`);This preserves behavior (credentials are still saved, meta is still computed if needed later) while eliminating clear-text logging of sensitive data. No new imports or helper functions are needed.
| @@ -1867,7 +1867,7 @@ | ||
| } | ||
|
|
||
| const meta = readCredsMeta(slotDir); | ||
| console.log(` Saved current credentials → ${slotName} (${meta.email})`); | ||
| console.log(` Saved current credentials → ${slotName}`); | ||
| console.log(); | ||
| return; | ||
| } |
- Show elapsed time since session start in every session_status update - Include elapsed in GitHub completion comment (e.g. "✅ Run #1 — completed (12m)") - Include elapsed in Slack status footer - Compute from session.started or first activity timestamp Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- app_mention handler now skips bot_id and subtype messages - Replace regex with indexOf for Slack URL check in dashboard template literal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
linkfield and display as Slack origin with ↗ icon on dashboard and workspace pageslinktoslackLinkwhen session has a Slack URL but noslack_channelmetadata (e.g. AztecBot sessions triggered via HTTP/run)bin/refresh-oauth.sh)Test plan
🤖 Generated with Claude Code