Repository navigation
chore(release): merge v2/main into main for v2.10.0 - #2637
Conversation
…imulator The secure-add behavior case composes a requireAuth+DCR streamable-http server and measures the full headless auth flow: non-TTY connect exits 0 with the sign-in link, and the agent is expected to relay it and finish the tools/call once access is granted. The harness plays the human: cases opting in with autoConsent get a watcher that polls the shim transcript for /oauth/authorize URLs and approves each once (GET consent page, POST approve, follow the redirect to the detached auth helper's loopback callback), after which the agent's next call revives the connection. Also: missed samples now dump a compact transcript (argv, exit, first 300 chars of each stream) as the failure diagnostic, and CASE_MATCH filters cases by prompt substring for one-case iteration (labeled a dev probe, not a measurement). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…fixture tool collect_elicitation can only exercise the elicitation wire: the caller composes the message and schema, so an agent can trivially satisfy it. Measuring elicitation BEHAVIOR needs a tool whose elicitation is intrinsic — the elicited fields deliberately absent from the input schema, so the only way to a result is answering the mid-call request. New submit_ticket preset: takes only a summary, elicits contact name/email over legacy elicitation/create, and returns a ticket id derived from the accepted content (decline/cancel: ticket not filed). The helpdesk eval case gives the agent the contact facts in a natural prompt and asserts the parked tools/call (exit 0, elicitationPending) followed by an elicitation/respond returning the ticket number. No harness user-simulator involved — the agent itself is the answerer. First probe (claude, 3 runs): 3/3 with the current SKILL.md — the pending output's in-band answer guidance is sufficient. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
SKILL.md body rewrite (description frontmatter unchanged): - command summary opens with servers/list; canonical flow spelled out (servers/list -> connect -> @entry <command>) - new 'How to think about mcpdo' section: connections extend the toolset, answer capability questions with them, don't auto-connect, inspect via commands not the filesystem - new 'The catalog' section: writable ~/.mcp-inspector/mcp.json, --catalog / MCP_CATALOG_PATH, servers/* vs connections/*, edit by file - Conventions: connection self-healing and the [legacy]/[modern] era tag - 'Auth': non-TTY connect exits 0 with pendingAuth + authUrl; relay the link, then retry the command with short sleeps (measured: 'wait for the user' wording made agents end their turn — 0/3; retry wording 3/3) - 'Elicitations': parking + elicitation/respond, decline/cancel/--done, TTL and one-parked-call limit Four regression behavior cases appended to evals.json (each guards a fixed skill gap): connections-awareness, catalog-discovery, explicit-connection (two-server catalog, matcher pins the connection), helpdesk-decline (asserted via stdoutMatch since boolean flags don't surface in parsed argv). All baselined 3/3 pre-edit; post-edit full suite: trigger 8/8 at 100%, behavior 8/8 at 3/3 incl. secure-add 2/3 -> 3/3. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
- `agent-help` (default, or explicit `--skill`) now prints the SKILL.md body with frontmatter stripped, so an agent without the skill installed can pull guidance usable exactly as if the skill had loaded. - `--instructions` prints a short always-on snippet to append to a project's CLAUDE.md/AGENTS.md, so agents treat open mcpdo connections as part of their toolset on every turn (skills load only on demand). - `--skill-path` (replaces `--path`) prints the installable SKILL.md location for skill runtimes. Flags are mutually exclusive. - SKILL.md gains a "Make it always-on (optional)" bullet pointing at `agent-help --instructions`. - Test hygiene from ed06480: fix `createStyle` calls to the real `(ansi: boolean)` signature and a prefer-const slip; neither changed runtime behavior, both now caught by full validate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…e artifacts Harness fixes (both produced silent never-authorized misses): - Concurrent samples' detached auth helpers all defaulted to callback port 6276 and collided (EADDRINUSE, or consent redirected to a dead helper). Each sample now sets MCP_OAUTH_CALLBACK_URL=http://127.0.0.1:0/oauth/callback — ephemeral ports are already supported end-to-end by the product. - The consent clicker scanned each stream chunk separately, so an authorize URL split across chunks was never detected. It now scans joined per-stream text (streamText), like the rest of the matchers; unit test covers a mid-URL split. Clicks are now logged. Runner UX: - AGENT defaults to "all": trigger + behavior suites run for claude and copilot back to back (AGENT=claude|copilot still selects one). - On a behavior miss the sample's hermetic env dir is preserved under ~/.cache/mcpdo-skill-eval/failures/ (raw agent stream, shim transcript, case, catalog, server configs) and the miss report prints its path. - Miss diagnostics show per-call timing offsets. Validated: full AGENT=all suite green — both agents 8/8 trigger @100% and 8/8 behavior @3/3, including the secure-add OAuth case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
CI coverage fell below the 90% per-file gates in four files touched by recent auth/elicitation work. Cover the gaps: - auth-helper: stdio configs (no marker), non-Error flow failures, stdin error/timeout, stdout EPIPE guard, helper spawn failure, and noise lines (blank/malformed/unknown events) before the auth URL. - authorize: non-EMA connect failures rethrown unchanged; caller-provided makeNavigation overrides the CLI default navigation. - format-human: colorLevel warning/debug/notice buckets and empty-URI passthrough via formatStreamEventHuman. - elicitation-park: waitForElicitation with an already-pending frame; forClient/cancelForConnection ignoring non-matching entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…er's Review finding (PR #1783): the behavior evals' shell allow-list looked like a containment boundary but is not one — approval patterns prefix-match (`mcpdo x && anything` passes) and `mcpdo connect` launches arbitrary stdio commands by design. The agent under test is a nondeterministic model with shell access; its actions are untrusted. - runPrompt no longer spreads process.env into the agent: agentEnv() picks process basics (PATH, HOME, locale, proxies) plus only the agent's own auth/config vars (ANTHROPIC_/CLAUDE_ for claude, GITHUB_/GH_/COPILOT_ for copilot). Exported credentials for anything else stay out. - The behaviorAgentArgs doc now states the real model: approval scoping is drift reduction for a cooperating model, env is minimized, and hard isolation is the runner's job (container/VM/dedicated user of choice — there is no portable OS sandbox worth shipping here). Validated: harness unit tests (93) green; live helpdesk 3/3 and secure-add OAuth 1/1 on both agents under the minimal env. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
Review finding (PR #1783): the accept-path helpdesk case measured only the call sequence — any summary and any contact details produced elicitationPending then TCK-. Its stated point is mapping known facts into the requested schema, so assert them: `summary` on the tools/call and `contact_name`/`contact_email` on the elicitation/respond. valuesMatch is spelling-agnostic (key:=value, JSON positional, --tool-args-json all land in parsed args; plain key=value is rejected by the CLI itself). Re-baselined 3/3 on both claude and copilot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
Post-format edit slipped past a re-check before push; format:check:scripts now clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
Two review findings (PR #1783): - The pending-marker check and helper spawn were not atomic: two concurrent non-TTY connects for the same server could both pass the check and spawn helpers that contend for the OAuth callback port. A per-server lock file (wx-exclusive create) now reserves the flow before spawning; the loser polls for the winner's marker (published before the helper reports its URL) and reuses it. Stale locks from a crashed reserver are stolen after the URL wait window, so a crash cannot wedge sign-in. - connect's sign-in block emitted the server-controlled OAuth authUrl as an OSC 8 hyperlink unconditionally. It now goes through the same isSafeLinkTarget scheme allowlist as every other server-supplied link; unsafe targets render as plain text. Validated: full validate green, per-file coverage thresholds met, live secure-add OAuth eval passing on both claude and copilot. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…l atomic Address Copilot review round 3 on the sign-in reservation code: - waitForPendingAuthUrl: don't unref the poll timer — for a reservation loser it can be the only live handle, and an unref'ed timer let Node exit mid-wait without ever printing the authorization URL. - readLivePendingAuthMarker: stop deleting stale/dead markers at read time; the unlink-by-pathname raced a just-spawned helper's fresh marker (TOCTOU). Stale markers are inert and writers replace them with rm+wx. - tryReserveAuthFlow: steal stale locks via an atomic rename-claim to a per-pid path so concurrent stealers cannot both win, with a post-rename staleness recheck. POSIX has no compare-and-delete; the rename makes the claim exclusive, which is what prevents double helper spawns. Tests updated for the no-delete-on-read semantics plus a claim- contention back-off case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…pt corruption Address Copilot review round 4: - readTranscript (eval harness): a malformed record before the final line now throws with its line number instead of being silently dropped, matching the function's stated contract — only a torn final line (a kill artifact) is tolerated. - connect: snapshot the SDK's default-inherited environment (PATH, HOME, SHELL, ...) from the calling shell and merge it under any configured env before the config crosses to the daemon. The transport otherwise evaluates getDefaultEnvironment() inside the persistent daemon, handing servers the environment of whichever shell first spawned it. Extracted the cwd/command/env pinning into an exported pinStdioConfigToCaller, which now also treats a type-less config as stdio (stdio is the implicit default). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…ng, spec doc Address Copilot review round 5: - form-schema/form-prompt: minLength/maxLength are measured in Unicode code points per JSON Schema, not UTF-16 units — a valid astral-char default (or answer) was rejected / trapped in the re-prompt loop. Shared codePointLength() applied at all four bound checks. - test-server-fixtures: submit_ticket ids now hash the full submission (djb2) instead of summary/email lengths, which collided whenever only contact_name changed; comment made honest about the 4-digit space. - specification/v2_cli_tui_launcher.md: 'Shared core consumption' and the summary now count daemon-cli among the core consumers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…marker cleanup Address Copilot review round 6: - resources/subscribe: the resourceUpdated listener now attaches before the subscribe handshake and buffers matching updates until the consumer's start() — a server notifying immediately after (or with) its subscribe response no longer loses that update in the window before the stream starts. The subscribe-failure path detaches the listener; ipc-glue already guarantees every stream outcome is started and stopped, so no leak on vanished callers. - auth helper exit: marker cleanup now verifies the on-disk marker's pid is this helper's before deleting (removeOwnPendingAuthMarker) — past the 15-minute TTL a replacement flow's fresh marker at the same pathname would otherwise be deleted out from under its callers. The residual read-to-rm window is documented; losing it costs one extra sign-in prompt, never a wrong URL. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…uto-decline The README still said --format json auto-declines forms and every other non-TTY caller gets a real prompt. Actual behavior since the parking change: non-interactive callers (--format json or no TTY) get the elicitation parked, the RPC returns an elicitationPending payload, and the answer comes via elicitation/respond (auto-cancel after 10 minutes). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…t/use annotate progress A non-TTY connect hands OAuth to the detached helper and registers a pending-auth entry, but connections/show never completed it: pollers following connect's own "check with connections/show" guidance saw "Sign-in: pending" forever (with the Auth line contradictorily flipped to authorized), until some real op revived the entry. - connections/show: when the entry is pendingAuth and the disk tokens are usable, run the same revive the first op would — show now observes (and performs) the completion. Revive failure falls back to the honest pending snapshot; a raced disconnect surfaces as the usual unknown-connection error. - connections/list / connections/use / daemon/status stay read-only (no dial) but annotate pending entries whose sign-in finished: pendingAuthSignedIn: true, live auth, and "signed in — completing on next use" in human output, so a poller knows the user's part is done. - Docs: README auth blurb, SKILL.md auth section, protocol/mcp comments. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
The daemon-cli lockfile still resolved esbuild 0.27.7 via tsup, which is affected by GHSA-g7r4-m6w7-qqqr. Add the same esbuild override the web, cli and tui packages already carry, and refresh the lockfile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…, lock race Four fixes from maintainer review round 2 on #1783: - disconnectAll settles each teardown independently: one failed disconnect (e.g. a connection_not_found race) no longer abandons the remaining connections and their stdio children, or makes daemon shutdown reject before the socket server closes. - Both daemon socket clients now setEncoding("utf8") so a multi-byte UTF-8 character split across TCP chunks is reassembled by the stream's StringDecoder instead of being mangled into U+FFFD per chunk. - An already-aborted signal no longer leaks a live socket: connect() was still called after onAbort() destroyed the socket, silently un-destroying it and pinning the event loop. - acquireLock treats a pidless daemon.lock younger than a 2s grace period as held (a concurrent starter between its O_EXCL create and pid write) instead of stealing it, which could let two daemons both win and permanently poison daemon.token. Symmetrically, a young pidless lock renamed aside mid-reclaim is restored, not reclaimed. Regression tests for all four (the UTF-8 test verified to fail without its fix); coverage thresholds hold. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
Elicitation prompts previously created a fresh readline interface per exchange, so answers piped up front (e.g. printf "a\nb\n" | mcpdo ...) were buffered into the first interface and discarded when it closed — only the first answer survived. Replace per-exchange readline usage with a shared persistent PromptReader that queues incoming lines and hands them to questions as they are asked, across questions and elicitation rounds. 'Input closed' now means truly exhausted (EOF and empty queue), so a completable form is never cancelled while queued answers remain. Verified against the reviewer's repro: pre-fix the second piped answer was dropped and the form cancelled; post-fix all answers are consumed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
- logging/tail: object `data` in a log notification now renders as JSON
instead of "[object Object]" (format-human.ts).
- Sign-in helper: listen for "close" instead of "exit" so a final
buffered stdout line (e.g. {"event":"error"}) is parsed before the
failure path runs (auth-helper.ts).
- Failure paths now sanitize server-influenced text the same way the
success path does: helper error messages and tool names interpolated
into error envelopes get C0/C1 controls replaced with visible
stand-ins (auth-helper.ts, format-connection.ts).
- Document why mcp-bin.ts and daemon/run.ts are excluded from coverage
(vitest.config.ts).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…ails - Eval matcher: parse the `--flag=value` spelling; `--connection=x` no longer reads as an unknown boolean flag that drops the value (false hits/misses in eval scores). - Eval shim: exit via process.exitCode instead of process.exit(), which discarded queued stdout writes and truncated large JSON results. - skills:eval env allowlist: pass AWS_*/GOOGLE_*/CLOUD_ML_* through for claude — Bedrock/Vertex runs need them to authenticate. - verify:skills: also validate shipped skills under `skills/` (frontmatter/structure only; no eval-case or listing-budget rules) so a truncated skills/mcpdo/SKILL.md cannot ship silently. - skills/mcpdo/SKILL.md: clarify that a parked elicitation means the command has already exited (exit 0) while the MCP tool call waits daemon-side — agents must not wait on or time-box the command. - daemon-cli README: note private mode separates daemons from each other, not from same-UID processes that learn the daemon dir. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
…s out stopping daemons Two review findings from cliffhall's round 2 on the daemon lifecycle: Park teardown owns the unwire (F6): a parked call's expiry or cancel closed the elicitation channel without removing the call's subscriber, while the server-side call kept running. Its stale subscriber stayed first in line and could swallow a later call's elicitation. ParkedCall now carries the unwire handle and every teardown path (respond, expiry, cancel, cancelForConnection) detaches the subscriber immediately. ensureDaemon vs. shutting-down daemon (F9): ping now reports a stopping flag (and daemon status surfaces it, with a "(shutting down)" marker in human output). When ensureDaemon reaches a stopping daemon it waits for the old process to exit (pid-based, since the socket closes before the lock is released) and then spawns a fresh one, instead of surfacing a daemon_stopping failure to the user. Ping itself always succeeds; observing a shutdown never restarts the daemon. Adds regression tests for both: stale-subscriber swallow, registry unwire on expiry/cancelAll, stopping ping/status, waitForDaemonExit (dead pid, live-pid timeout, socket fallback), and a full ensureDaemon wait-then-respawn integration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
Eval harness containment (F14, review round 2): a rejecting behavior sample used to reject the whole pool and exit the process while sibling samples' finally blocks (daemon stop, sandbox removal) were still pending — detached eval daemons genuinely leak that way. pool() now takes an optional onError mapper: the behavior section records an errored sample as a scored miss (failures note, zero calls) and keeps going. Without onError the pool stops taking new items, lets in-flight work finish its cleanup, then rethrows the first error. A throw from makeBehaviorEnv now also reclaims the sample's sandbox dir. Pool semantics pinned by unit tests. New smoke: `npm run smoke:mcpdo` (wired into `npm run smoke`, G1) drives the built daemon CLI end to end in a hermetic sandbox — catalog connect, tools/call, elicitation park + respond round-trip, daemon status, disconnect, daemon stop with verified process exit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bob Dickinson <bob.dickinson@gmail.com>
Step 3 of the release skill said only "generate the notes and publish". It is now three parts: - 3a, draft the release notes: What's Changed from the generate-notes API, the smoke-ledger line, any known issue, and a "Thanks for helping us improve" section crediting the community members whose issues the release addresses (maintainers and bots excluded by permission). The recipe reproduces 2.9.0's published Thanks section exactly. @-mentions feed the release's Contributors strip. - 3b, tag and publish: the existing UI steps, plus gh release create with the notes file. Editing published notes is safe, since every tag's main.yml fires only on release: [published]. - 3c, if the release run fails: a release runs the workflow from the tag's commit, so fix it on v2/main, merge to main, delete the Release AND its tag, and re-cut. This is what 2.9.0 needed (#2551). The AGENTS.md skills-index row for release is updated to match. Closes #2554 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
- PREV is now the highest strict x.y.z tag below VERSION. The old glob also matched 2.0.0-rc.N, x.y.z-hotfix and x.y.z-amended tags, so cutting a stable release after an RC would pick the RC and drop changes (for VERSION=2.0.0 it picked 2.0.0-rc.3; now 1.0.2). - thanks.md is truncated before the optional append, so a rerun with no eligible reporters never keeps a stale section. - A re-cut re-runs the whole 3a recipe, since a fix PR can close a community-reported issue and change the Thanks section too. - The re-cut no longer waives verification: gate and smoke a fix wherever it can be run, and only a release-only path takes the re-cut run as its first evidence. Refs #2554 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
…older (Copilot) - The body-reference extraction did scan(...)[] | .[0], which with gh's jq indexes the first CHARACTER of each captured string: "Closes #2554" became issue 2. It is now scan(...) | .[0]. Verified with gh --jq: "Closes #2554 … Fixes #12 … resolves #999" gave [2,1,9] before and [2554,12,999] after. The 2.9.0 check missed it because every PR there also carried a manual closing link. - <assembled-notes.md> inside a shell block is input redirection, so --notes-file lost its argument. It is now a NOTES variable. Cross-checked: the fixed recipe reproduces the published Thanks lists of 2.9.0, 2.8.0, 2.5.0 and 2.4.0 exactly (26 reporters; three of those lists were built independently). Refs #2554 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
The re-cut deleted only the remote tag. The 3b manual path creates a local tag, which would stay pointed at the broken commit: the re-tag aborts, and a later git fetch --tags refuses to clobber it. Delete it locally as well. Refs #2554 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
… failures (Copilot) - Never infer "unpublished" from dist-tags. During the 2.9.0 re-cut, 2.9.0 existed (Validating) while dist-tags still said latest 2.8.0. Wait out validation and treat only an exact-version 404 as unpublished. - When npm published but a downstream job (such as GHCR) failed, re-run only the failed job for a transient fault, and fix forward only a defect that cannot pass on retry. Never re-cut a version npm owns. Refs #2554 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
…se-notes-step docs(release): add the release-notes step and the re-cut procedure
…acting display boundary (#2638) #2490 made the TUI show caught error text only through errorText's errorMessage(), which redacts URL query secrets. The Tasks tab, Subscriptions tab and Roots editor added by #2432 still rendered err.message directly (TasksTab through its own unredacted copy), so a server error quoting an OAuth URL reached the screen verbatim. All three now use the shared errorMessage(); TasksTab's copy is gone. Each suite gains a test that throws an error quoting ?code=s3cret and asserts the secret never reaches the display; all three fail with the source change reverted. Found by Copilot on the v2.10.0 milestone merge (#2637). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
run.ts wrote its startup diagnostic and called process.exit(1) at once. On a pipe or file stderr is asynchronous, so exit could discard the message. Await the write via core/cli's awaitableError, the same flush-then-exit the shared CLI error handler uses. Found by Copilot on the v2.10.0 milestone merge (#2637). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
- #78: zshDescribeEntry escaped ':' but not '\' in a _describe name. Escape backslashes first, then colons; a test renders a name holding both. Flag names never contain either today, so this was unreachable. - #80, #81: the mcpdo stored-auth test matched its server with url.includes("example.com"); compare the full URL instead. - #79: the namespace-ledger test's sentinel edit is an anchored /^\{/ replace, with an assertion that the sentinel really differs, so the 'no rewrite' check can never pass vacuously. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…required-ruleset ci: make DCO a required status check on v2/main (#2621)
…2546) dependabot-alerts.mjs (twice) and sdk-watch.mjs escaped | in Markdown table cells but not \, so a value ending in a backslash re-exposed the pipe and broke the row (CodeQL js/incomplete-sanitization #74-#76). One shared helper, scripts/lib/markdown-cell.mjs, escapes backslashes first, then pipes; both scripts import it. Its test covers a trailing backslash and checks every pipe in the output sits behind an odd run of backslashes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
…2640) docs/environment-variables.md claims every runtime variable but never mentioned mcpdo, which ships for the first time in 2.10.0. - A new 'mcpdo connection daemon' section documents MCP_INSPECTOR_DAEMON_DIR, MCP_INSPECTOR_DAEMON_TOKEN and MCP_ALLOW_DEFAULT_CONNECTION from daemon/paths.ts, daemon/auth.ts and connection/dispatch.ts; they were only in the spec. - mcpdo is named in the Read-by legend and in the 16 rows it reads through core/: each name was checked against the built mcpdo bundle (the proxy rows through EnvHttpProxyAgent in core/mcp/node/proxyFetch). Raised by Copilot on the v2.10.0 milestone merge (#2637). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
…lags (#2640) Copilot on #2641, verified in source: - mcpdo does not honour HTTPS_PROXY/HTTP_PROXY/NO_PROXY. Its two InspectorClient environments (connection/authorize.ts, daemon/connections.ts) omit fetch, so InspectorClient wraps global fetch (inspectorClient.ts:846) and the transport never reaches createProxyFetch(). The variable names are in the mcpdo bundle, but that code is never called on these paths. - mcpdo has no --callback-url or --client-config flag; say the flag overrides apply to the CLI and TUI only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
…llback (#2640) Copilot round 2 on #2641, verified in source: - MCP_AUTO_OPEN_ENABLED: with no TTY and no --stored-auth-only, mcpdo connect returns a pending connection and authUrl instead of the CLI's auth-required error; true keeps the blocking flow (connection/mcp.ts). - USERPROFILE: the daemon directory falls back to os.homedir(), not the working directory, when neither HOME nor USERPROFILE is set (daemon/paths.ts). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: cliffhall <cliff@futurescale.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
| // truncated SKILL.md would otherwise ship silently — but no eval-case or | ||
| // listing-budget requirements: they are not part of this repo's own | ||
| // agent skill listing. | ||
| if (!override && existsSync(path.join(ROOT, "skills"))) { |
There was a problem hiding this comment.
A real gap in repo tooling, but nothing in the published package depends on it, so it does not block the release. Filed as #2644 for v2.11.0.
|
Copilot round 3: both new items are filed for v2.11.0 instead of growing the release merge.
|
|
Copilot review loop closed after round 3. Its two new items are filed for v2.11.0 (#2643 and #2644, with the reasons above), and the one finding it still lists as open was already fixed by #2639. Final tree |


Closes #2623
Milestone merge of
v2/mainintomainfor the v2.10.0 release, which is step 2 of thereleaseskill.This is a pure merge
No commits of its own, only merge commits:
The merged tree is byte-identical to
origin/v2/main. The tree reads 2.10.0, bumped onv2/mainin #2622 / PR #2627.Verification
Ledger: https://claude.ai/artifact/KQe73j1A6QcGvnpAXfx2Hb (for maintainer review; one row per closed milestone issue, with what was run and what was observed)
npm run local:gateon the final tree passes every stage exceptsmoke:web:firefox. That stage cannot launch Playwright's Firefox on macOS 27 (smoke:web:firefox cannot launch Playwright's Firefox on macOS 27 #2625), so the three Firefox smokes were run from a clean export of this exact tree in the Linux Playwright container instead, and all passed. Storybook (529) was run separately, since the Firefox failure stops the gate chain before that stage.npm run pack:verify: OK (27 files, 5.70 MB unpacked).npm audit: 0 vulnerabilities in all six installs.Found during the release, fixed on
v2/mainTUI useCopyKeys save-path test fails on macOS's long default TMPDIR #2609 → PR test(tui): stop parsing the wrapped frame for the saved-copy path #2626: a TUI test failed on macOS's long default
TMPDIR(found by release prep).CLI shell completion omits servers/add, servers/edit, servers/remove and --output-format values #2629 → PR fix(cli): complete servers/add|edit|remove and --output-format values #2634: shell completion (CLI has no shell completion (bash/zsh/fish) #2434) omitted the new
servers/add|edit|removemethods (CLI has no write path for the server catalog (add/remove/edit servers) #2433) and the--output-formatvalues (found by this smoke).Fix the v2.10.0 milestone-merge review findings: TUI error redaction bypass, mcpdo daemon stderr flush, CodeQL #78-#81 #2638 → PR fix: v2.10.0 merge review findings — TUI error redaction, mcpdo daemon flush, CodeQL #78-#81 #2639: found by this PR'"'"'s review.
Fix code-scanning alerts #74-#76: Markdown cell escaping misses backslashes in the sweep scripts #2546 + docs/environment-variables.md omits mcpdo: its daemon variables and Read-by entries #2640 → PR fix: sweep table-cell escaping (CodeQL #74-#76) and document mcpdo's environment variables #2641: CodeQL Skip the dist/index.js bit #74–Improve Windows Support #76 in the sweep scripts, and mcpdo missing from
docs/environment-variables.md(found by this PR's CodeQL check and Copilot's round 2).CodeQL on this PR: 0 open alerts.
Follow-ups filed for v2.11.0: #2624, #2625, #2628, #2630, #2631, #2632, #2633, #2642, #2643, #2644, #2645, #2646, #2647, #2648, #2649, #2650.
🤖 Generated with Claude Code