feat: ship Slice K3 — cabinet-style auth migration (delete packages/core/src/auth/)#90
Merged
Merged
Conversation
…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.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Mission Control no longer reimplements Claude Code OAuth. The Claude Agent SDK's bundled
claudebinary (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 confirmedquery()succeeds withCLAUDE_CODE_OAUTH_TOKEN,ANTHROPIC_API_KEY, andANTHROPIC_AUTH_TOKENall unset.Net diff: 49 files, +212 / -2309 lines.
What deleted
packages/core/src/auth/entire tree —refresher.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}— themc auth bootstrapcommand. 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 ofCLAUDE_CODE_OAUTH_TOKEN, boot probe, auth-alert wiring,onReadyboot-race recovery (~110 lines).compose.ts:oauthRefresherfield,auth-refresherDaemonServicelifecycle.paths.ts:credentialsJsonPath.services.ts:credentials.jsonmtime poll (one fewer syscall per config-watcher tick).What stayed (refactored)
packages/core/src/agent/auth-required-error.ts— small sentinelAuthRequiredErrorclass. Replaces the deletedisAuthRequiredErrorhelper +RefreshToken*Error/NotBootstrappedErrorhierarchy.sdk-source.ts— drops refresher injection + retry-loop. Streams eagerly; on 401-result, throwsAuthRequiredError. K2 chat-lane fail-fast path takes over. Memory: O(1) on hot path instead of O(messages-per-run buffered).runner.ts—err instanceof AuthRequiredErrorreplaces the deleted helper.chat-bridge.ts—CHAT_AUTH_REQUIRED_REPLYdropsmc auth bootstrapreference; "expired" → "failed" (we only see 401, can't distinguish expiry from revocation).BootstrapInstructionStep— dropped the 2s status poll (claudeCode is permanently'ready'now); Continue is always enabled.mc auth bootstrapstrings in dashboard updated toclaude login.Test plan
pnpm typecheckcleanpnpm buildclean (all 7 workspaces)biome check .clean (366 files, 0 errors)pnpm test1395/1395 + dashboard 145/145setReadyhelper instead ofset('claudeCode', { status: 'ready', ... }), "expired" → "failed" wording, droppedBootstrapInstructionSteppollingclaude loginstate → succeedsclaude logoutfirst) → chat lane returnsCHAT_AUTH_REQUIRED_REPLYwithin ~30sWhy 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; settingCLAUDE_CODE_OAUTH_TOKENwas just shadowing what the bundledclaudebinary 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
useSetupAlertsandClaudeCodeStatusPanelretaindisabled/error/expiresAtpaths. Unreachable in production but cheap and defensive — kept for future-proofing if a probe is reintroduced.