19 Commits
Author SHA1 Message Date
cliffhallandClaude Opus 5.5 fd55745f66 fix(scripts): double backslashes before a quote in win-shell-args
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>
2026-10-13 00:48:54 -04:00
cliffhallandClaude Opus 5.5 e5ca90c71e ci(everything): run the interface diff as an npm script on v2/main (#4860)
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>
2026-10-09 23:24:48 -04:00
cliffhallandClaude Opus 5.5 acbae3534e Order PEP 440 local version labels, and ignore them in specifier matching as packaging does
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
2026-10-07 14:44:10 -04:00
cliffhallandClaude Opus 5.5 c47051ab76 Treat npm outdated's exit 1 without a payload as a failure; compare epochs in PEP 440 prefix matching
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
2026-10-07 13:38:46 -04:00
cliffhallandClaude Opus 5.5 715bde0d9d Apply PEP 440's exclusive-bound rules; preview the supersession note in a dry run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
2026-10-07 13:25:45 -04:00
cliffhallandClaude Opus 5.5 2b728ecbbf Route sweep warnings through an injectable sink, so tests keep them off the console
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
2026-10-07 12:45:12 -04:00
cliffhallandClaude Opus 5.5 abb1c902bf Replace Dependabot PRs with issue-filing sweeps; add the SDK watch and the factory overview
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>
2026-10-07 12:42:49 -04:00
cliffhallandClaude Opus 5.5 45d059d5d8 Add a DCO signoff check to CI and the gate (#4919)
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>
2026-10-05 01:28:32 -04:00
cliffhallandClaude Opus 5.5 38f9e6dfec fix(coverage-py): refuse a report measured without branch coverage
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>
2026-10-04 19:05:19 -04:00
cliffhallandClaude Opus 5.5 1cdd4a7038 chore(python): per-file coverage gate in CI and local:gate
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>
2026-10-04 19:05:19 -04:00
cliffhallandClaude Opus 5.5 f149a2a61f ci(coverage): enforce the TypeScript per-file coverage gate in CI and local:gate
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>
2026-10-04 18:31:00 -04:00
cliffhallandClaude Opus 5.5 4a62f9fdca feat: verify:action-pins, a SHA-pin guard for credentialed workflow jobs
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>
2026-10-01 09:45:15 -04:00
97bf8fcb8f feat: publish from a maintainer-published GitHub Release
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>
2026-10-01 09:45:14 -04:00
cliffhallandClaude Opus 5.5 7fd3201561 fix: no lifecycle hooks around the gate; workspaces drift; POSIX-only signal tests
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>
2026-09-30 21:57:49 -04:00
cliffhallandClaude Opus 5.5 b916f29600 fix: derive CI parity from the workflows; smoke runs the bin itself
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>
2026-09-30 21:22:08 -04:00
cliffhallandClaude Opus 5.5 727cf5ade0 feat: local:gate, the gate lease, boot smoke and the pre-push-gate skill
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>
2026-09-30 20:45:18 -04:00
cliffhallandClaude Opus 5.5 a9cf19e162 feat: coverage and lockstep guards, root validate, per-package CI legs
- 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>
2026-09-29 00:10:03 -04:00
cliffhallandClaude Opus 5.5 bb5591850d fix: refuse masked intermediate hops and unusable eval counts
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>
2026-09-29 00:10:03 -04:00
cliffhallandClaude Opus 5.5 a5c40bf838 feat: port the skills harness (verify:skills, verify:skills:cli, skills:eval)
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>
2026-09-29 00:10:03 -04:00