Skip to content

feat: context links for Slack-originated HTTP sessions#13

Open
AztecBot wants to merge 11 commits intomainfrom
feat/context-links-oauth-refresh
Open

feat: context links for Slack-originated HTTP sessions#13
AztecBot wants to merge 11 commits intomainfrom
feat/context-links-oauth-refresh

Conversation

@AztecBot
Copy link
Collaborator

Summary

  • Recognize Slack URLs in link field and display as Slack origin with ↗ icon on dashboard and workspace pages
  • Promote link to slackLink when session has a Slack URL but no slack_channel metadata (e.g. AztecBot sessions triggered via HTTP /run)
  • Add hourly OAuth token refresh via systemd timer (bin/refresh-oauth.sh)

Test plan

  • Open workspace page for an AztecBot-triggered session — should show ↗ Slack link
  • Dashboard should show "slack" origin badge for sessions with Slack URL in link field
  • Slack-originated sessions still show ↗ link as before
  • GitHub PR/CI links still display correctly as context links

🤖 Generated with Claude Code

AztecBot and others added 9 commits March 10, 2026 18:55
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

This logs sensitive data returned by
an access to oauthAccount
as clear text.
This logs sensitive data returned by
an access to oauth
as clear text.

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:

  1. Keep readCredsMeta as-is so that internal logic still has full details.
  2. In credsCommand, before logging, derive a safe, redacted version of the identity:
    • If meta.email is "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.
  3. Use this redacted string in the console.log instead of the raw meta.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.

Suggested changeset 1
cli.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/cli.ts b/cli.ts
--- a/cli.ts
+++ b/cli.ts
@@ -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;
EOF
@@ -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;
Copilot is powered by AI and may make mistakes. Always verify output.
}

const meta = readCredsMeta(slot.path);
console.log(` ● Activated: ${slotName} (${meta.email})`);

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This logs sensitive data returned by
an access to oauthAccount
as clear text.
This logs sensitive data returned by
an access to oauth
as clear text.

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 readCredsMeta as-is; it still returns email for internal use if needed in the future.

  • Update the console.log on 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.


Suggested changeset 1
cli.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/cli.ts b/cli.ts
--- a/cli.ts
+++ b/cli.ts
@@ -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;
EOF
@@ -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;
Copilot is powered by AI and may make mistakes. Always verify output.
}

const meta = readCredsMeta(slotDir);
console.log(` Saved current credentials → ${slotName} (${meta.email})`);

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This logs sensitive data returned by
an access to oauthAccount
as clear text.
This logs sensitive data returned by
an access to oauth
as clear text.

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.

Suggested changeset 1
cli.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/cli.ts b/cli.ts
--- a/cli.ts
+++ b/cli.ts
@@ -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;
   }
EOF
@@ -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;
}
Copilot is powered by AI and may make mistakes. Always verify output.
AztecBot and others added 2 commits March 10, 2026 19:09
- 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant