An argument ending in a backslash was quoted as "...\\", which the CRT
parser reads as an escaped quote, swallowing the rest of the command line.
Backslash runs before an embedded quote or the closing quote are now doubled,
with tests including a round trip through a reference CRT parser.
Closes#5111
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Adapt #3260's workflow for v2/main:
- Run the check as `npm run interface-diff` (scripts/interface-diff.mjs),
driving the mcp-server-diff 3.0.0 CLI as an exact-pinned root
devDependency instead of the SHA-pinned v2.3.5 action. The same script
is a new last stage of local:gate, which workflow-gate.test.mjs now
requires, so the gate keeps running every check CI runs.
- Choose the base per event (the PR's base, the commit before a push, the
previous release tag, or a dispatch input) instead of the tool's
default merge-base with origin/main, which is wrong for v2/main PRs.
- Trigger pushes on main and v2/main, PRs on any base, and published
Releases instead of the retired typescript-servers-* tags.
- Run the PR's code only in a read-only job with no persisted
credentials; post the sticky comment from a separate job that holds
pull-requests: write, runs no PR code, and only runs for same-repo PRs.
Fork PRs keep the job summary and the report artifact.
- Give every job a timeout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Three scheduled workflows replace Dependabot's PRs, ported from the MCP
Inspector and extended to this repo's second ecosystem:
- dependency-refresh (monthly): one tracking issue covering npm outdated
across the root and workspaces, each Python server's uv lock --upgrade
dry run, and every workflow uses: ref, with SHA pins ranked by their
# vX.Y.Z comment through scripts/lib/action-refs.mjs.
- dependabot-alerts (daily): one issue per vulnerable package per
lockfile, npm and pip, re-checked against v2/main, targeting the highest
patched version of the advisories that apply.
- sdk-watch (nightly): one issue per MCP SDK group behind its registry
(npm @modelcontextprotocol/*, PyPI mcp), with the Inspector's hardened
three-job Claude analysis kept unchanged.
Shared plumbing (the trust rule, milestone pick, scope labels and a writer
whose --dry-run writes nothing) lives in scripts/lib/sweep.mjs, with PEP 440
and uv.lock readers beside it. No sweep writes the board: GITHUB_TOKEN cannot
hold organization projects: write, so issues arrive labeled and milestoned
for issue-triage, and boarding from the workflows waits on a GitHub App
(#5061).
Deletes .github/dependabot.yml, removes the temporary Dependabot exception
from AGENTS.md and adds the issue-driven dependency rules, and adds
docs/ai-software-factory.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
The probot DCO app never ran on this repo, so nothing failed an unsigned
commit. Replace it with a check we own:
- scripts/verify-dco.mjs (+ tests): every commit in <base>..<head> needs a
Signed-off-by trailer matching its author or committer; merge and
bot-authored commits are exempt. A failure names each commit and the
`git rebase --signoff` repair.
- .github/workflows/dco.yml: runs it on pull requests over
base.sha..head.sha, contents: read only, with a timeout.
- `verify:dco` joins local:gate:stages, over origin/v2/main..HEAD.
- AGENTS.md states the signoff rule; pr-flow step 3 describes the job
instead of the app; quality-gate.md and pre-push-gate cover the stage;
the skills-index table is Prettier-clean.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
coverage.py writes num_branches: 0 for every file when branch measurement
is off, which the per-file check counted as 100% on branches, so removing
`branch = true` would have let every file pass that dimension. Require
meta.branch_coverage === true and fail with a message pointing at
[tool.coverage.run] branch = true. Regression tests for false, a missing
flag and a missing meta.
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add `npm run coverage:py` (scripts/coverage-py.mjs): for each Python
server, a locked sync, then `uv run --frozen pytest --cov
--cov-report=term-missing --cov-report=json`, then a per-file check of
coverage.json (scripts/lib/py-coverage.mjs) that fails any file below 90%
on lines or on branches. coverage.py's fail_under is global, hence the
script. Discovery, server selection and the carry-on-after-a-failure shape
are shared with validate-py.mjs.
Wire it in as a parallel `coverage` matrix job in python.yml and as a
stage of local:gate:stages after validate:py, and document it in
docs/quality-gate.md, AGENTS.md (the Python half of the coverage rule),
CONTRIBUTING.md and the pre-push-gate and testing skills.
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds a parallel `coverage` job to typescript.yml (one leg per TypeScript
server, beside `validate`, as the Inspector's CI does) and a `coverage` stage
to `local:gate:stages` right after `validate`. The workflow guard derives the
stage from the new CI job, and its stage list now pins `coverage` by name.
Documents the stage in docs/quality-gate.md, the TypeScript half of the
coverage rule in AGENTS.md, how to diagnose a red coverage stage in the
pre-push-gate skill, and the in-process harness and coverage gate in the
testing skill. The docs describe the state after the four per-server
coverage PRs for #4854 land, which add the 90/90/90/90 per-file thresholds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Ported from the Inspector (inspector#2484). A job that can mint an OIDC token
or push a package, is handed a secret other than GITHUB_TOKEN, or uploads an
artifact such a job downloads, may only use actions pinned to a commit SHA
with the release in a trailing comment. The SHA matcher lives in
scripts/lib/action-refs.mjs so the dependency sweep planned in #4874 can
share it.
claude.yml (id-token: write, ANTHROPIC_API_KEY) is pinned here; release.yml
is pinned with its split in the next commit, and the guard joins
validate:guards there, once the tree passes it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
release.yml now runs on release: published and publishes every package whose
version is not on its registry yet. No job computes, stamps or tags a version.
The npm registry-diff guard is scripts/npm-publish-guard.mjs: it asks the
registry directly, skips (not fails) a published version, and treats a
never-published package as 'publish it'. scripts/release.py, removed with the
changesets commit, served the dispatch flow this replaces.
Ported from #4604, retargeted at v2/main.
Co-authored-by: olaservo <olahungerford@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 7 on #4920:
- The script tests assert that no pre/post npm hook exists for
local:gate or local:gate:stages.
- verify:install-fresh compares the root's `workspaces` patterns with
the lockfile's record of them.
- The lease's signal tests are skipped on Windows, which cannot send
those signals.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Copilot round 3 on #4920 (four findings in unchanged code):
- The gate's CI parity is derived: every npm script and scripts/*.mjs a
push or pull-request workflow runs must be reached by local:gate.
- The smoke executes dist/index.js through its shebang on POSIX, as the
installed command is, so a lost shebang or executable bit fails it.
- verify:no-test-retries scans workflows for a test runner's retry flag.
- docs/quality-gate.md no longer says the lease never fails the gate: a
waiter that gives up does.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Adds `npm run local:gate`, the one command that runs every check CI runs
for both languages, under a machine-wide lease so gates started in
separate worktrees queue instead of contending.
- scripts/gate-lease.mjs: the lease, ported from the MCP Inspector.
- verify:install-fresh: the gate's first stage; node_modules must match
package-lock.json.
- scripts/smoke-servers.mjs (`npm run smoke`): boots all seven servers
from the artifact a user launches, over each transport they implement
(stdio for all; SSE and Streamable HTTP for everything), and calls one
tool. Also a CI job.
- verify:no-test-retries: no Vitest retry, no pytest rerun plugin.
- scripts/lib/workflow-gate.mjs: no workflow may invoke a local:* script,
every CI job declares timeout-minutes, and local:gate stays exactly the
lease wrapper around its stages.
- timeout-minutes on every job in all four workflows.
- Removes the last temporary wiring allowance from verify:skills.
- docs/quality-gate.md, the pre-push-gate skill with eval cases, and the
AGENTS.md pre-push rule.
Per-file coverage is not part of this change: #4871 was rescoped so the
gate does not wait on the spec refactor's test suites. #4854 and #4855
add their coverage stages to the gate built here.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
- verify:format-coverage and verify:typecheck-coverage ported from the
Inspector, with the Inspector's tsc-program and resolve-node-bin libs
(+ tests), adapted to npm workspaces via a new lib/workspaces.mjs that
reads the root workspaces patterns from disk and checks the root
validate still runs `npm run validate --workspaces`.
- verify:dep-lockstep: every shared toolchain devDependency (typescript,
vitest, @vitest/coverage-v8, prettier, @types/node) is declared with one
range everywhere, or once at the root.
- Root validate = validate:guards (root format/lint, the guards,
test:scripts) + npm run validate --workspaces.
- typescript.yml: each matrix leg runs only its own package's validate;
the root-guards job runs validate:guards.
- Removes #4863's temporary verify:format-coverage wiring allowance, and
fixes the four root-lint findings in the skills scripts.
Refs #4864
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
scriptChainRuns no longer follows an intermediate segment carrying a pipe
or ||, so a target reached through a masked stage does not vouch as run.
skills:eval rejects a non-positive-integer CHAIN_MAX_TURNS, RUNS or
CONCURRENCY, which would otherwise remove Copilot's turn cap.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Port the MCP Inspector's skills infrastructure for #4858 Part 3:
- scripts/verify-skills.mjs, verify-skills-cli.mjs, skill-eval.mjs and
scripts/lib/{skill-manifest,claude-cli,npm-scripts,win-shell-args}.mjs,
with all their *.test.mjs files
- root npm scripts verify:skills, verify:skills:cli, skills:eval and
test:scripts; yaml as a root devDependency
- docs/skill-authoring.md, with paths and provenance adapted
- a root-guards job in typescript.yml running verify:skills and
verify:skills:cli on every push and pull request
- .claude/skills/ (kept by a .gitkeep until the first skill lands)
- un-ignore scripts/lib/, which the Python `lib/` pattern swallowed
Adapted to this repo: checkWiring reads typescript.yml, and carries two
temporary allowances (validate -> verify:format-coverage, removed by
#4864; local:gate -> verify:skills:cli, removed by #4871) that excuse a
link only while its pending script is absent and fail as stale once it
exists. The "no skills found" failure is kept, with a temporary
EMPTY_SKILLS_BOOTSTRAP allowance that fails as stale once a skill exists.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>