Repository navigation
chore(core): promote the CLI surface mcpdo shares into core/cli (#2461) - #2613
Conversation
mcpdo compiled against clients/cli/src through a temporary build-time @inspector/cli alias. Move the shared node-only closure it reached for — error-handler, awaitable-log, style, cliOAuth, cli-oauth-navigation and the handlers run-method / method-types / output-file / format-output / collect-app-info / skills-verify / servers-list / connect-timeout — into core/cli/, keeping the same layout, and import it through the ordinary @inspector/core alias from both clients. - Drop the @inspector/cli alias from mcpdo's tsup, vitest and tsconfigs. - Keep core/cli under clients/cli's per-file coverage gate (its suites still exercise it); web's core/* whitelist deliberately omits it. - CliExitCodeError drops parameter properties: core/ is typechecked under web's erasableSyntaxOnly. - Update AGENTS.md, the project-structure skill, the mcpdo README and the specs that pointed at the old paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The relocation, consumer imports, and coverage configuration are consistent, with no blocking defects identified.
Review effort: Balanced
Findings: 1
What changed in this PR
Moves the Node-only functionality shared by the one-shot CLI and mcpdo into core/cli/, removing their dependency on CLI-internal source paths.
Changes:
- Relocates shared handlers, OAuth helpers, error handling, and output utilities.
- Rewires consumers and tests through
@inspector/core, removing@inspector/cliconfiguration. - Preserves CLI coverage gating and updates ownership documentation.
| File | Description |
|---|---|
| specification/v2_cli_v2.md | Updates shared-module paths and coverage documentation. |
| specification/v2_auth_mid_session.md | Updates OAuth source paths. |
| scripts/smoke-cli.mjs | Updates a comment’s source path. |
| core/mcp/uriTemplate.ts | Updates a comment’s handler path. |
| core/cli/utils/awaitable-log.ts | Relocates stream-output helpers. |
| core/cli/style.ts | Relocates styling helpers. |
| core/cli/handlers/skills-verify.ts | Uses relative core imports. |
| core/cli/handlers/servers-list.ts | Uses relative core imports. |
| core/cli/handlers/run-method.ts | Uses relative core imports. |
| core/cli/handlers/output-file.ts | Uses relative core imports. |
| core/cli/handlers/method-types.ts | Uses relative core type imports. |
| core/cli/handlers/format-output.ts | Relocates result formatting. |
| core/cli/handlers/connect-timeout.ts | Uses relative core imports. |
| core/cli/handlers/collect-app-info.ts | Uses relative core imports. |
| core/cli/error-handler.ts | Relocates errors; uses explicit class fields. |
| core/cli/cliOAuth.ts | Relocates shared OAuth flow. |
| core/cli/cli-oauth-navigation.ts | Relocates OAuth navigation. |
| core/auth/node/runner-interactive-oauth.ts | Updates a comment’s error-handler path. |
| clients/mcpdo/vitest.config.ts | Removes the temporary test alias. |
| clients/mcpdo/tsup.config.ts | Removes the temporary build alias. |
| clients/mcpdo/tsconfig.test.json | Removes the temporary test path mapping. |
| clients/mcpdo/tsconfig.json | Removes the temporary source path mapping. |
| clients/mcpdo/src/mcp-bin.ts | Imports shared error handling. |
| clients/mcpdo/src/daemon/stream-client.ts | Imports shared errors. |
| clients/mcpdo/src/daemon/server.ts | Imports shared handlers and errors. |
| clients/mcpdo/src/daemon/protocol.ts | Imports shared method types. |
| clients/mcpdo/src/daemon/ensure.ts | Imports shared errors. |
| clients/mcpdo/src/daemon/elicitation-park.ts | Imports shared errors. |
| clients/mcpdo/src/daemon/connections.ts | Imports shared errors. |
| clients/mcpdo/src/daemon/client.ts | Imports shared errors. |
| clients/mcpdo/src/daemon/auth.ts | Imports shared errors. |
| clients/mcpdo/src/connection/stored-auth.ts | Imports shared errors. |
| clients/mcpdo/src/connection/mcp.ts | Imports the shared CLI surface. |
| clients/mcpdo/src/connection/format-human.ts | Imports shared styling. |
| clients/mcpdo/src/connection/format-connection.ts | Imports shared output helpers and types. |
| clients/mcpdo/src/connection/form-prompt.ts | Imports the shared style type. |
| clients/mcpdo/src/connection/ema.ts | Imports shared OAuth navigation and errors. |
| clients/mcpdo/src/connection/elicitation-prompt.ts | Imports the shared style type. |
| clients/mcpdo/src/connection/dispatch.ts | Imports shared types and styling. |
| clients/mcpdo/src/connection/authorize.ts | Imports shared OAuth helpers. |
| clients/mcpdo/src/connection/auth-names.ts | Imports shared catalog types. |
| clients/mcpdo/src/connection/auth-helper.ts | Imports shared errors. |
| clients/mcpdo/README.md | Documents shared core ownership. |
| clients/mcpdo/__tests__/mcp-auth-coverage.test.ts | Updates error imports. |
| clients/mcpdo/__tests__/helpers/mcp-runner.ts | Updates error-formatter imports. |
| clients/mcpdo/__tests__/format-connection.test.ts | Updates error and styling imports. |
| clients/mcpdo/__tests__/form-prompt.test.ts | Updates styling imports. |
| clients/mcpdo/__tests__/ema.test.ts | Updates error imports. |
| clients/mcpdo/__tests__/ema-commands.test.ts | Updates styling imports. |
| clients/mcpdo/__tests__/elicitation-prompt.test.ts | Updates styling imports. |
| clients/mcpdo/__tests__/daemon-stream.test.ts | Updates error imports. |
| clients/mcpdo/__tests__/daemon-rpc-abort.test.ts | Retargets the handler mock. |
| clients/mcpdo/__tests__/daemon-private.test.ts | Updates error imports. |
| clients/mcpdo/__tests__/daemon-paths.test.ts | Updates formatter imports. |
| clients/mcpdo/__tests__/daemon-elicitation-park.test.ts | Retargets the handler mock. |
| clients/mcpdo/__tests__/daemon-coverage.test.ts | Updates error imports. |
| clients/mcpdo/__tests__/daemon-connections.test.ts | Updates error imports. |
| clients/mcpdo/__tests__/connection-stored-auth.test.ts | Updates error imports. |
| clients/mcpdo/__tests__/authorize.test.ts | Retargets OAuth mocks. |
| clients/mcpdo/__tests__/auth-names.test.ts | Updates catalog type imports. |
| clients/mcpdo/__tests__/auth-names-commands.test.ts | Updates imports and catalog mocks. |
| clients/cli/vitest.config.ts | Gates coverage for relocated modules. |
| clients/cli/src/index.ts | Imports shared error handling. |
| clients/cli/src/handlers/schema-lint-report.ts | Imports shared output helpers and types. |
| clients/cli/src/handlers/emit-result.ts | Imports shared result-writing dependencies. |
| clients/cli/src/handlers/consume-outcome.ts | Imports shared output and error helpers. |
| clients/cli/src/completion.ts | Imports shared methods and logging. |
| clients/cli/src/cli.ts | Consumes and re-exports relocated modules. |
| clients/cli/__tests__/style.test.ts | Targets relocated styling helpers. |
| clients/cli/__tests__/skills-verify-cli.test.ts | Updates exit-code imports. |
| clients/cli/__tests__/servers-list.test.ts | Targets relocated catalog helpers. |
| clients/cli/__tests__/schema-lint-report.test.ts | Updates error imports. |
| clients/cli/__tests__/run-method.test.ts | Targets the relocated handler. |
| clients/cli/__tests__/run-method-skills.test.ts | Targets relocated skill handlers. |
| clients/cli/__tests__/run-method-mocks.test.ts | Targets the relocated handler. |
| clients/cli/__tests__/README.md | Documents shared-module coverage. |
| clients/cli/__tests__/output-file.test.ts | Targets relocated file-output helpers. |
| clients/cli/__tests__/oauth-interactive.test.ts | Targets relocated OAuth helpers. |
| clients/cli/__tests__/method-types.test.ts | Targets relocated method definitions. |
| clients/cli/__tests__/helpers/oauth-test-fakes.ts | Updates OAuth type imports. |
| clients/cli/__tests__/helpers/cli-runner.ts | Updates imports and coverage comments. |
| clients/cli/__tests__/format-output.test.ts | Targets relocated formatting. |
| clients/cli/__tests__/error-handler.test.ts | Targets relocated error handling. |
| clients/cli/__tests__/emit-result.test.ts | Updates error imports. |
| clients/cli/__tests__/consume-outcome-stream.test.ts | Updates outcome type imports. |
| clients/cli/__tests__/completion.test.ts | Updates method-definition imports. |
| clients/cli/__tests__/cliOAuth.test.ts | Targets relocated OAuth helpers. |
| clients/cli/__tests__/cli-oauth-navigation.test.ts | Targets relocated OAuth navigation. |
| AGENTS.md | Documents ownership and test-placement rules. |
| .claude/skills/project-structure/SKILL.md | Documents the shared surface and coverage ownership. |
…ion (#2461) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
|
Copilot round 1: one low-severity finding. |
|
Copilot review loop closed. Round 2 came back clean: no findings, no inline comments, and nothing suppressed. The one finding from round 1 shows as resolved. The loop stops on the first clean round. |
✅ Verdict: MergeableI smoke tested head Automated (fresh detached worktree, clean
|
| Check | Result |
|---|---|
smoke:cli |
✅ pass |
smoke:mcpdo |
✅ pass (connect → calls → disconnect → daemon stop, socket released) |
verify:bundle-externals |
✅ 4 bundles, nothing externalized was inlined |
clients/cli check + test:coverage |
✅ 581 passed / 2 skipped; core/cli 99.1/95.2/97.7/100, core/cli/handlers 99.5/95.8/100/99.5. Every file is ≥90 on all four dimensions |
clients/mcpdo check + test:coverage |
✅ 490 passed |
| Stale references | ✅ none: no @inspector/cli anywhere, no core/ → clients/ import, no doc still pointing at the old clients/cli/src/... paths |
| Rename fidelity | ✅ all 13 moves are pure relocations. The content diffs are only @inspector/core/... → relative imports, plus the documented CliExitCodeError parameter-property → field change |
Manual: one-shot CLI (clients/cli/build, and mcp-inspector --cli via the launcher)
- stdio and streamable-HTTP:
initialize,tools/list(auto-paginates 12 tools),tools/callvia--tool-argand--tool-args-json,resources/list|read,resources/templates/list, an RFC 6570 template read with a percent-encoded reserved char,prompts/list|get, structured output, andlogging/setLevel(legacy). The modern era correctly rejectssetLevel. - Error envelope / exit codes (
error-handler):tool_is_error→ 5,tool_not_found→ 5,no_app→ 2,auth_required→ 3,unreachable→ 4 (refused, and a blackholed--connect-timeout 1500cut off at ~1.6s),--strict→ 6, skills--verify→ 7. Usage errors (unknown method/server,--tool-arg+--tool-args-json,--strictwith the wrong method,rawwithtools/list) → 1. output-file:--outputjson and raw (tool text and resource text); a missing parent dir →output_write_failed.collect-app-info:--app-infoontools/list(NDJSON) and on a single tool.skills-verify: per-skill reports, and the summary on the skills showcase.servers-list,--completion zsh,--print-handoff,--list-stored-auth.- Interactive OAuth (
cliOAuth+cli-oauth-navigation), driven through a pty with auto-open disabled: DCR → consent → loopback callback →Authorization complete.→ the call succeeds. A non-TTY run is correctly refused.--stored-auth-onlyreuses the persisted token afterwards, and--reloginclears it.
Manual: mcpdo (private token-gated daemon)
servers/list|show, thenconnectof 11 entries (stdio + HTTP, legacy + modern, plus an ad-hoc URL with--era legacy),connections/list|show|use,@nameand--connaddressing, and the non-TTYconnection_requiredguard.tools/list|call(key:=valueand a JSON object), with the same error codes and exit codes as the CLI (the sharederror-handler). Alsoresources/*, templates,prompts/get|complete, structured output,--app-info(exit 2 onno_app),logging/setLevel, andlogging/tailreceiving asend_notificationline.- Tasks + elicitation: a modern task with
--taskcompletes.modern_input_taskparkselicitationPending(form),elicitation/respond … approved:=truecompletes it, and a stale ID →elicitation_not_found. URL-mode elicitation over stdio → form submitted →--done→Collected value: smoke-value. roots/set|list,skills/list|get.- OAuth:
connect oauthexits 0 withpendingAuth+authUrl. A call while pending →auth_required(3) with the re-show hint. After approval,connections/showcompletes the sign-in and calls succeed.auth/listshows it● live, and the one-shot CLI reuses the token mcpdo stored.auth/clear,disconnect(plus the unknown-connection error), anddaemon stopall work.
Not exercised
- The step-up
[y/N]confirmer.oauth-step-up-demo.json's first grant already requests every supported scope, soget_tempnever needs step-up.cliOAuth.test.tscovers it, and that suite passes. - EMA (
auth/ema-*): it needs an IdP fixture.
Observations (none caused by this PR)
Each of these now has a follow-up issue, linked under the item.
-
The
DCOcheck isn't running on any v2 PR.dco.ymlwas added in ci: replace the suspended DCO app with a signoff check we own #2603 and triggers onpull_request_target. GitHub now sources those workflows from the default branch, anddco.ymlisn't onmainyet. Its only recorded run is apull_requestevent on ci: replace the suspended DCO app with a signoff check we own #2603's own branch (v2/chore/2566-dco-signoff-check). No PR since then has aDCOcheck, including ci: replace the suspended DCO app with a signoff check we own #2603 itself at merge, test(web): subscribe the fetch log before connecting in timeout-diagnostics (#2580) #2612, and this one. It should start working after the next milestone merge intomain. Until then the required-check guarantee isn't in force. Both commits here are signed off.Follow-up: ci: run the DCO check on PRs into v2/main now, plus a post-merge backstop on v2/main #2616, fixed by PR ci: run the DCO check on every v2 PR now, before push, and after merge (#2616) #2619 (the check now runs on every v2 PR, before push, and after merge). The 10 historic unsigned commits it surfaced are tracked in docs: record retroactive DCO signoffs for the 10 unsigned commits on v2/main #2617 (retroactive signoff record, PR docs: retroactive DCO signoffs for the 10 unsigned commits on v2/main (#2617) #2618).
-
Not from this PR:
-qstill prints theWrote N bytes … to <path>status line on stderr when--outputis used. The help for-qsays status lines are suppressed.output-file.tsmoved unchanged, so this predates the PR.Follow-up: CLI: -q does not suppress the "Wrote N bytes … to <path>" status line when --output is used #2614.
-
Not from this PR: the CLI's connect-timeout message says to raise the timeout "in Server Settings", which is web UI wording.
--connect-timeoutis the CLI's knob.Follow-up: CLI/mcpdo: connect-timeout error tells the user to change "Server Settings", which only the web UI has #2615.
🤖 Generated with Claude Code

Closes #2461
What
clients/mcpdocompiled againstclients/cli/srcthrough a temporary build-time@inspector/clialias. This moves the shared, Node-only closure it reached for into a newcore/cli/area, with the same internal layout, and both clients now import it through the ordinary@inspector/corealias.core/cli/error-handler.tsCliExitCodeError, the error envelopecliOAuth.ts,cli-oauth-navigation.tsstyle.ts,utils/awaitable-log.tshandlers/run-method,method-types,output-file,format-output,collect-app-info,skills-verify,servers-list,connect-timeoutoutput-file,collect-app-infoandskills-verifyweren't named in the issue, butrun-method/method-typesimport them, so they're part of the same closure. One-shot-only output (emit-result,consume-outcome,schema-lint-report,servers-write,cli.ts,completion.ts) stays inclients/cli/src.Also changed
tsup.config.ts,vitest.config.ts,tsconfig.jsonandtsconfig.test.json, andnoExternaldrops/^@inspector\/cli/.core/cli/**is added toclients/cli's coverageinclude(withallowExternal, since it sits outside that project's root). The cli suites still exercise it, so it stays under the per-file ≥90 gate. Current numbers:core/cli99.1/95.2/97.7/100 andcore/cli/handlers99.5/95.8/100/99.5 (stmts/branch/funcs/lines). Web'score/*whitelist leaves it out on purpose, because no web test reaches it.clients/cli/__tests__/. They drive these modules through the cli runner. AGENTS.md's test-placement rule and theproject-structureskill now recordcore/cli/as the one exception to "core tests live inclients/web/src/test/core/".CliExitCodeErroruses plain fields instead of parameter properties. Everything undercore/is typechecked by web'stsc -b, and web setserasableSyntaxOnly. Behavior is unchanged.core/cli/, self-imports are now relative (../mcp/…), matching the rest ofcore/.project-structureskill, the mcpdo README layout note, cli test docs, and the specs and code comments that pointed at the old paths.Not in this PR
The issue's note about the TUI reusing this surface is left for a separate pass. The TUI doesn't import any of these modules today, and moving its own copies is a behavior change, not a relocation.
Verification
npm run local:gate: every stage up to the Firefox smoke passed. That coversvalidateand its guards, coverage on all five clients,verify:build-gate,verify:bundle-externals, and the launcher/cli/mcpdo/tui/web/chromium smokes. I ranlocal:storybookon its own afterwards and it passed (123 files). Two local environment issues to flag:smoke:web:firefoxcouldn't launch Firefox under the sandbox this session ran in (sandbox_extension_issue_file_to_process … Operation not permitted). It's a browser-launch failure, not an app failure, and this diff doesn't touch web. CI runs that smoke.useCopyKeys"W saves…" test fails on macOS's long default$TMPDIR. That's already tracked in TUI useCopyKeys save-path test fails on macOS's long default TMPDIR #2609, and it fails the same way on unmodifiedv2/main. The gate passed it withTMPDIR=/tmp.🤖 Generated with Claude Code