Skip to content

feat: ship Slice K3 — cabinet-style auth migration (delete packages/core/src/auth/)#90

Merged
joedanz merged 1 commit into
mainfrom
slice/K3-cabinet-style-auth-delete
May 6, 2026
Merged

feat: ship Slice K3 — cabinet-style auth migration (delete packages/core/src/auth/)#90
joedanz merged 1 commit into
mainfrom
slice/K3-cabinet-style-auth-delete

Conversation

@joedanz
Copy link
Copy Markdown
Owner

@joedanz joedanz commented May 6, 2026

Summary

Mission Control no longer reimplements Claude Code OAuth. The Claude Agent SDK's bundled claude binary (node_modules/@anthropic-ai/claude-agent-sdk-<platform>/claude, 216 MB) handles keychain reads, refresh-token rotation, and the OAuth POST itself when spawned as a subprocess. K3's research spike confirmed query() succeeds with CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_API_KEY, and ANTHROPIC_AUTH_TOKEN all unset.

Net diff: 49 files, +212 / -2309 lines.

What deleted

  • packages/core/src/auth/ entire treerefresher.ts, credential-store.ts, credential-bundle.ts, credential-reader.ts, reader-factory.ts, index.ts, every reader (mac-keychain.ts, linux-fs.ts, linux-libsecret.ts, composite-linux.ts, parse-claude-credentials.ts), and all matching *.test.ts.
  • packages/cli/src/commands/auth.{ts,test.ts} — the mc auth bootstrap command. Removed from CLI entrypoint.
  • packages/daemon/src/bin/auth-alert.{ts,test.ts} — K1.5 Discord DM alerter (no refresher → no 'expiring'/'error' transitions).
  • packages/daemon/src/claude-code-refresh.smoke.test.ts — refresher smoke probe.
  • mcd-main.ts: OAuthRefresher construction, env-seed of CLAUDE_CODE_OAUTH_TOKEN, boot probe, auth-alert wiring, onReady boot-race recovery (~110 lines).
  • compose.ts: oauthRefresher field, auth-refresher DaemonService lifecycle.
  • paths.ts: credentialsJsonPath.
  • services.ts: credentials.json mtime poll (one fewer syscall per config-watcher tick).

What stayed (refactored)

  • New packages/core/src/agent/auth-required-error.ts — small sentinel AuthRequiredError class. Replaces the deleted isAuthRequiredError helper + RefreshToken*Error / NotBootstrappedError hierarchy.
  • sdk-source.ts — drops refresher injection + retry-loop. Streams eagerly; on 401-result, throws AuthRequiredError. K2 chat-lane fail-fast path takes over. Memory: O(1) on hot path instead of O(messages-per-run buffered).
  • runner.tserr instanceof AuthRequiredError replaces the deleted helper.
  • chat-bridge.tsCHAT_AUTH_REQUIRED_REPLY drops mc auth bootstrap reference; "expired" → "failed" (we only see 401, can't distinguish expiry from revocation).
  • Dashboard BootstrapInstructionStep — dropped the 2s status poll (claudeCode is permanently 'ready' now); Continue is always enabled.
  • All mc auth bootstrap strings in dashboard updated to claude login.

Test plan

  • Gate 1pnpm typecheck clean
  • Gate 2pnpm build clean (all 7 workspaces)
  • Gate 3biome check . clean (366 files, 0 errors)
  • Gate 4pnpm test 1395/1395 + dashboard 145/145
  • /simplify ran 3 reviewers in parallel — applied: setReady helper instead of set('claudeCode', { status: 'ready', ... }), "expired" → "failed" wording, dropped BootstrapInstructionStep polling
  • Research spike: live SDK probe with all three auth env vars unset returned a successful Haiku result in 8.2s
  • Manual smoke: send a Discord chat message with current claude login state → succeeds
  • Manual smoke: with stale auth (run claude logout first) → chat lane returns CHAT_AUTH_REQUIRED_REPLY within ~30s

Why it matters

K1, K1.5, K2 fixed three concrete bugs in MC's reimplementation of Claude Code OAuth. The deeper issue was that MC was reimplementing it at all. Cabinet (hilash/cabinet) showed the alternative — shell out and trust the binary. K3's spike confirmed the SDK already does this internally; setting CLAUDE_CODE_OAUTH_TOKEN was just shadowing what the bundled claude binary would have resolved on its own.

Eliminated: hard-coded CLAUDE_CODE_CLIENT_ID (Bug 4 from K1's diagnosis), three error class hierarchies, a 5-min refresh ticker, a credentials-watch mtime poll, a daemon-respawn-on-credentials-change path, a Discord DM alerting helper, four reader implementations across two platforms.

Onboarding gate is now a single text instruction: "run claude login."

Deferred

  • Linux/Windows verification — the probe ran on darwin-arm64. The SDK ships parallel platform binaries, but the smoke test wasn't run there.
  • Defensive dashboard branchesuseSetupAlerts and ClaudeCodeStatusPanel retain disabled/error/expiresAt paths. Unreachable in production but cheap and defensive — kept for future-proofing if a probe is reintroduced.

…ore/src/auth/

Mission Control no longer reimplements Claude Code OAuth. The Claude
Agent SDK's bundled `claude` binary (216 MB, ships at
node_modules/@anthropic-ai/claude-agent-sdk-<platform>/claude) handles
keychain reads, refresh-token rotation, and the OAuth POST itself when
spawned as a subprocess. K3's research spike confirmed `query()`
succeeds with all three auth env vars unset.

Deleted (~2000 LOC):
- packages/core/src/auth/ — entire tree (refresher, credential-store,
  credential-bundle, credential-reader, reader-factory, all readers,
  index.ts, all matching *.test.ts).
- packages/cli/src/commands/auth.{ts,test.ts} — `mc auth bootstrap`
  command and its CLI registration.
- packages/daemon/src/bin/auth-alert.{ts,test.ts} — K1.5 Discord DM
  alerter (no MC-side refresher → no 'expiring' / 'error' transitions).
- packages/daemon/src/claude-code-refresh.smoke.test.ts — refresher
  smoke probe.
- mcd-main.ts: OAuthRefresher construction, env-seed of
  CLAUDE_CODE_OAUTH_TOKEN, boot probe, auth-alert wiring, onReady
  boot-race recovery (~110 lines).
- compose.ts: `oauthRefresher` field, `auth-refresher` DaemonService.
- paths.ts: `credentialsJsonPath`.
- services.ts: credentials.json mtime poll (one fewer syscall/tick).

Refactored:
- New packages/core/src/agent/auth-required-error.ts — small sentinel
  AuthRequiredError class. Replaces the deleted isAuthRequiredError
  helper + RefreshToken*Error / NotBootstrappedError class hierarchy.
- sdk-source.ts: drops refresher injection + retry-loop. Streams
  eagerly; on 401-result, throws AuthRequiredError. K2 chat-lane
  fail-fast path takes over from there. Net: O(1) memory on hot path
  instead of O(messages-per-run buffered).
- runner.ts: replaces isAuthRequiredError(err) with
  err instanceof AuthRequiredError.
- chat-bridge.ts: CHAT_AUTH_REQUIRED_REPLY drops `mc auth bootstrap`
  reference; "expired" → "failed" (we only see 401, not expiry
  specifically).
- Dashboard wizard's BootstrapInstructionStep: dropped the dead-weight
  2s status poll; Continue is always enabled.
- All `mc auth bootstrap` strings in dashboard updated to `claude
  login`.

Net diff: 49 files changed, +212 / -2309.
@joedanz joedanz merged commit d8c666f into main May 6, 2026
3 checks passed
joedanz added a commit that referenced this pull request May 6, 2026
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