@lannguyensi/harness 0.41.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +9 -0
  3. package/dist/cli/adopt/derive.d.ts +15 -0
  4. package/dist/cli/adopt/derive.js +34 -7
  5. package/dist/cli/adopt/derive.js.map +1 -1
  6. package/dist/cli/adopt/index.d.ts +30 -0
  7. package/dist/cli/adopt/index.js +23 -3
  8. package/dist/cli/adopt/index.js.map +1 -1
  9. package/dist/cli/apply/generate-settings.d.ts +14 -1
  10. package/dist/cli/apply/generate-settings.js +7 -3
  11. package/dist/cli/apply/generate-settings.js.map +1 -1
  12. package/dist/cli/approve/stdin-report.js +2 -0
  13. package/dist/cli/approve/stdin-report.js.map +1 -1
  14. package/dist/cli/doctor/claude-mcp.d.ts +50 -0
  15. package/dist/cli/doctor/claude-mcp.js +170 -0
  16. package/dist/cli/doctor/claude-mcp.js.map +1 -0
  17. package/dist/cli/doctor/format.js +37 -0
  18. package/dist/cli/doctor/format.js.map +1 -1
  19. package/dist/cli/doctor/index.d.ts +10 -0
  20. package/dist/cli/doctor/index.js +24 -0
  21. package/dist/cli/doctor/index.js.map +1 -1
  22. package/dist/cli/doctor/npm-bin-path.js +42 -0
  23. package/dist/cli/doctor/npm-bin-path.js.map +1 -1
  24. package/dist/cli/doctor/types.d.ts +11 -0
  25. package/dist/cli/doctor/types.js.map +1 -1
  26. package/dist/cli/index.js +253 -5
  27. package/dist/cli/index.js.map +1 -1
  28. package/dist/cli/init/agent-tasks-auth.js +32 -0
  29. package/dist/cli/init/agent-tasks-auth.js.map +1 -1
  30. package/dist/cli/init/composer.js +3 -9
  31. package/dist/cli/init/composer.js.map +1 -1
  32. package/dist/cli/init/dependencies.js +21 -0
  33. package/dist/cli/init/dependencies.js.map +1 -1
  34. package/dist/cli/init/detect.d.ts +20 -3
  35. package/dist/cli/init/detect.js +34 -36
  36. package/dist/cli/init/detect.js.map +1 -1
  37. package/dist/cli/init/interactive.d.ts +33 -0
  38. package/dist/cli/init/interactive.js +399 -5
  39. package/dist/cli/init/interactive.js.map +1 -1
  40. package/dist/cli/init/profiles.d.ts +1 -1
  41. package/dist/cli/init/profiles.js +1 -1
  42. package/dist/cli/init/templates.d.ts +1 -1
  43. package/dist/cli/init/templates.js +64 -5
  44. package/dist/cli/init/templates.js.map +1 -1
  45. package/dist/cli/main.js +10 -0
  46. package/dist/cli/main.js.map +1 -1
  47. package/dist/cli/pack/hook-post-merge-gate-record.d.ts +30 -0
  48. package/dist/cli/pack/hook-post-merge-gate-record.js +153 -0
  49. package/dist/cli/pack/hook-post-merge-gate-record.js.map +1 -0
  50. package/dist/cli/pack/hook-post-merge-gate.d.ts +28 -0
  51. package/dist/cli/pack/hook-post-merge-gate.js +244 -0
  52. package/dist/cli/pack/hook-post-merge-gate.js.map +1 -0
  53. package/dist/cli/pack/hook-solution-acceptance-writeguard.js +148 -2
  54. package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +1 -1
  55. package/dist/cli/pack/understanding-report-schema-hint.js +1 -1
  56. package/dist/cli/pack/understanding-report-schema-hint.js.map +1 -1
  57. package/dist/cli/record/index.d.ts +64 -0
  58. package/dist/cli/record/index.js +211 -0
  59. package/dist/cli/record/index.js.map +1 -0
  60. package/dist/cli/session-start/index.d.ts +7 -0
  61. package/dist/cli/session-start/index.js +133 -38
  62. package/dist/cli/session-start/index.js.map +1 -1
  63. package/dist/cli/session-start/toolchain-parity.d.ts +149 -0
  64. package/dist/cli/session-start/toolchain-parity.js +618 -0
  65. package/dist/cli/session-start/toolchain-parity.js.map +1 -0
  66. package/dist/cli/uninstall/index.d.ts +73 -1
  67. package/dist/cli/uninstall/index.js +134 -2
  68. package/dist/cli/uninstall/index.js.map +1 -1
  69. package/dist/io/claude-mcp.d.ts +258 -0
  70. package/dist/io/claude-mcp.js +544 -0
  71. package/dist/io/claude-mcp.js.map +1 -0
  72. package/dist/policies/ledger-client.d.ts +34 -1
  73. package/dist/policies/ledger-client.js +21 -16
  74. package/dist/policies/ledger-client.js.map +1 -1
  75. package/dist/policy-packs/builtin/post-merge-gate-runtime.d.ts +195 -0
  76. package/dist/policy-packs/builtin/post-merge-gate-runtime.js +290 -0
  77. package/dist/policy-packs/builtin/post-merge-gate-runtime.js.map +1 -0
  78. package/dist/policy-packs/builtin/post-merge-gate.d.ts +56 -0
  79. package/dist/policy-packs/builtin/post-merge-gate.js +291 -0
  80. package/dist/policy-packs/builtin/post-merge-gate.js.map +1 -0
  81. package/dist/policy-packs/builtin/solution-acceptance-runtime.js +28 -13
  82. package/dist/policy-packs/builtin/solution-acceptance-runtime.js.map +1 -1
  83. package/dist/policy-packs/registry.d.ts +1 -1
  84. package/dist/policy-packs/registry.js +12 -0
  85. package/dist/policy-packs/registry.js.map +1 -1
  86. package/dist/runtime/git-context.d.ts +50 -0
  87. package/dist/runtime/git-context.js +108 -1
  88. package/dist/runtime/git-context.js.map +1 -1
  89. package/dist/runtime/hermetic-spawn-guard.d.ts +25 -0
  90. package/dist/runtime/hermetic-spawn-guard.js +136 -0
  91. package/dist/runtime/hermetic-spawn-guard.js.map +1 -0
  92. package/dist/runtime/ledger-writer.d.ts +27 -0
  93. package/dist/runtime/ledger-writer.js +46 -0
  94. package/dist/runtime/ledger-writer.js.map +1 -0
  95. package/dist/runtime/read-only-bash.js +118 -0
  96. package/dist/runtime/read-only-bash.js.map +1 -1
  97. package/dist/schema/index.d.ts +41 -0
  98. package/dist/schema/index.js +5 -0
  99. package/dist/schema/index.js.map +1 -1
  100. package/dist/schema/toolchain-parity.d.ts +18 -0
  101. package/dist/schema/toolchain-parity.js +35 -0
  102. package/dist/schema/toolchain-parity.js.map +1 -0
  103. package/package.json +4 -2
@@ -0,0 +1,30 @@
1
+ import { type LedgerWriteFn } from "../../runtime/ledger-writer.js";
2
+ import type { Manifest } from "../../schema/index.js";
3
+ import { type LoaderOptions } from "../loader.js";
4
+ export interface PackHookPostMergeGateRecordOptions extends LoaderOptions {
5
+ /** Defaults to process.stdin. */
6
+ stdin?: NodeJS.ReadableStream;
7
+ /** Defaults to process.stderr. stdout is never written (PostToolUse). */
8
+ stderr?: NodeJS.WritableStream;
9
+ /** Override cwd resolution (test injection). Falls back to event.cwd then process.cwd(). */
10
+ cwd?: string;
11
+ /** Per-call ledger timeout in ms. */
12
+ ledgerTimeoutMs?: number;
13
+ /** Inject a manifest (test). Bypasses loadManifest. */
14
+ manifest?: Manifest;
15
+ /** Override the harness.generated/ directory used by the pause check (test injection). */
16
+ generatedDir?: string;
17
+ /** Override "now" for the fact's `at:<iso>` audit timestamp (test injection). */
18
+ now?: Date;
19
+ /** Inject the ledger writer (test). */
20
+ writeLedger?: LedgerWriteFn;
21
+ }
22
+ export interface PackHookPostMergeGateRecordResult {
23
+ /** Always 0 — PostToolUse hooks must never break the session loop. */
24
+ exitCode: number;
25
+ /** Whether the merged-tag ledger fact was actually written. */
26
+ wrote: boolean;
27
+ /** Human-readable explanation, always populated (even on a write). */
28
+ diagnostic: string;
29
+ }
30
+ export declare function runPackHookPostMergeGateRecordCli(opts?: PackHookPostMergeGateRecordOptions): Promise<PackHookPostMergeGateRecordResult>;
@@ -0,0 +1,153 @@
1
+ // `harness pack hook post-merge-gate-record` — PostToolUse producer for
2
+ // the `post-merge-gate` policy pack.
3
+ //
4
+ // Receives Claude Code's PostToolUse event JSON on stdin. Fires only when
5
+ // the just-completed tool was Bash AND the command matched `gh pr merge`
6
+ // AND the merge is CONFIRMED by one of two contracts (see
7
+ // `resolveMergeConfirmation` in post-merge-gate-runtime.ts, "PAYLOAD
8
+ // REALITY" follow-up):
9
+ //
10
+ // Contract A (original, unchanged): `tool_output.exit_code === 0`.
11
+ // Contract B (2.1.218 payload reality): `tool_response` present with
12
+ // `interrupted === false` AND `stdout`+`stderr` containing `gh pr
13
+ // merge`'s own past-tense success sentence (all three merge methods).
14
+ //
15
+ // Contract A wins whenever it resolves to any definite verdict (success
16
+ // OR failure); Contract B is consulted only when Contract A's exit_code
17
+ // is entirely unresolvable. On a confirmed merge, records a
18
+ // `post-merge-gate:merged:<repo>:<branch>:<sha>` fact (plus PR number and
19
+ // timestamp, audit-only) to the evidence ledger via the same
20
+ // Trusted-Writer path `harness session-start branch-check` /
21
+ // `harness record *` use (`resolveManifestLedgerWriter` /
22
+ // `addLedgerFact`) — never an agent-issued `ledger_add`.
23
+ //
24
+ // `<sha>` is the LOCAL branch tip observed right after the tool ran:
25
+ // `gh pr merge` merges the PR on the remote side and does not itself move
26
+ // the local branch pointer, so this IS the exact commit that got merged
27
+ // (see post-merge-gate-runtime.ts's header for the full squash-fest
28
+ // rationale — no ancestry walk, no `git` subprocess).
29
+ //
30
+ // Every non-match / failure path is a no-op: wrong tool, non-matching
31
+ // command, neither contract confirms, an unresolvable git context, no
32
+ // session id, a manifest/ledger failure. `PostToolUse` is `blocking:false`
33
+ // by contract (see the pack's Hook entry) so none of these ever break the
34
+ // session; the only observable effect of a miss is that the blocker has
35
+ // no merged-tip fact to compare against for this particular merge.
36
+ import { buildMergedTagContent, GH_PR_MERGE_BASH_RE, PACK_NAME, resolveMergeConfirmation, } from "../../policy-packs/builtin/post-merge-gate-runtime.js";
37
+ import { resolveGitContext } from "../../runtime/git-context.js";
38
+ import { resolveManifestLedgerWriter } from "../../runtime/ledger-writer.js";
39
+ import { checkHookPause, loadManifestOrInjected, readStdin } from "./hook-bootstrap.js";
40
+ const LEDGER_SOURCE = "harness-pack-hook-post-merge-gate-record";
41
+ function bashCommandOf(toolInput) {
42
+ if (typeof toolInput !== "object" || toolInput === null)
43
+ return "";
44
+ const cmd = toolInput["command"];
45
+ return typeof cmd === "string" ? cmd : "";
46
+ }
47
+ export async function runPackHookPostMergeGateRecordCli(opts = {}) {
48
+ const stdin = opts.stdin ?? process.stdin;
49
+ const stderr = opts.stderr ?? process.stderr;
50
+ const note = (msg) => {
51
+ stderr.write(`harness pack hook post-merge-gate-record: ${msg}\n`);
52
+ };
53
+ const raw = await readStdin(stdin);
54
+ let event = {};
55
+ try {
56
+ event = JSON.parse(raw.trim() || "{}");
57
+ }
58
+ catch {
59
+ const diagnostic = "malformed event JSON, skipping";
60
+ note(diagnostic);
61
+ return { exitCode: 0, wrote: false, diagnostic };
62
+ }
63
+ // Pause sentinel — mirrors every other pack hook's operator kill-switch.
64
+ if (checkHookPause(PACK_NAME, stderr, opts, opts.generatedDir).paused) {
65
+ const diagnostic = "harness paused; post-merge-gate-record skipping without evaluating.";
66
+ note(diagnostic);
67
+ return { exitCode: 0, wrote: false, diagnostic };
68
+ }
69
+ const toolName = typeof event.tool_name === "string" ? event.tool_name : "";
70
+ if (toolName !== "Bash") {
71
+ const diagnostic = `tool ${toolName || "(unknown)"} is not Bash, skipping`;
72
+ note(diagnostic);
73
+ return { exitCode: 0, wrote: false, diagnostic };
74
+ }
75
+ const command = bashCommandOf(event.tool_input);
76
+ if (!command || !GH_PR_MERGE_BASH_RE.test(command)) {
77
+ const diagnostic = "command did not match gh pr merge, skipping";
78
+ note(diagnostic);
79
+ return { exitCode: 0, wrote: false, diagnostic };
80
+ }
81
+ // The confirmed-success gate: neither contract confirming — including
82
+ // any unresolvable / unexpected payload shape on either — writes NO
83
+ // fact. Fail-safe against a false "merged" record, which would be a
84
+ // self-lock in the wrong direction (03-decisions.md). See
85
+ // resolveMergeConfirmation's own doc comment for the dual-contract /
86
+ // "Contract A wins" ordering decision.
87
+ const confirmation = resolveMergeConfirmation(event.tool_output, event.tool_response, command);
88
+ if (!confirmation.confirmed) {
89
+ const diagnostic = `not a confirmed merge success (${confirmation.reason}); skipping (no fact written)`;
90
+ note(diagnostic);
91
+ return { exitCode: 0, wrote: false, diagnostic };
92
+ }
93
+ const cwd = typeof opts.cwd === "string" && opts.cwd.length > 0
94
+ ? opts.cwd
95
+ : typeof event.cwd === "string" && event.cwd.length > 0
96
+ ? event.cwd
97
+ : process.cwd();
98
+ const { repo, branch, sha } = resolveGitContext(cwd);
99
+ if (repo === "" || branch === "" || sha === "") {
100
+ const diagnostic = `cannot resolve git context for ${cwd} ` +
101
+ `(repo=${JSON.stringify(repo)} branch=${JSON.stringify(branch)} sha=${JSON.stringify(sha)}); ` +
102
+ `skipping (no fact written)`;
103
+ note(diagnostic);
104
+ return { exitCode: 0, wrote: false, diagnostic };
105
+ }
106
+ const sessionId = (typeof event.session_id === "string" && event.session_id.length > 0
107
+ ? event.session_id
108
+ : undefined) ??
109
+ process.env.CLAUDE_CODE_SESSION_ID ??
110
+ process.env.CLAUDE_SESSION_ID ??
111
+ "";
112
+ if (sessionId === "") {
113
+ const diagnostic = "no session_id resolvable from stdin or $CLAUDE_CODE_SESSION_ID/$CLAUDE_SESSION_ID; skipping (no fact written)";
114
+ note(diagnostic);
115
+ return { exitCode: 0, wrote: false, diagnostic };
116
+ }
117
+ // PR number: resolveMergeConfirmation already applied the binding
118
+ // resolution order (command-first, gh-success-sentence fallback only
119
+ // for Contract B; Contract A stays command-only, unchanged).
120
+ const whenIso = (opts.now ?? new Date()).toISOString();
121
+ const content = buildMergedTagContent({ repo, branch, sha, pr: confirmation.pr, whenIso });
122
+ let writeLedger = opts.writeLedger;
123
+ if (!writeLedger) {
124
+ let manifest;
125
+ try {
126
+ ({ manifest } = loadManifestOrInjected(opts, opts.manifest));
127
+ }
128
+ catch (err) {
129
+ const diagnostic = `manifest load failed (${err.message}); skipping (no fact written)`;
130
+ note(diagnostic);
131
+ return { exitCode: 0, wrote: false, diagnostic };
132
+ }
133
+ const resolved = resolveManifestLedgerWriter(manifest, {
134
+ ...(opts.ledgerTimeoutMs !== undefined ? { ledgerTimeoutMs: opts.ledgerTimeoutMs } : {}),
135
+ });
136
+ if (!resolved.ok) {
137
+ const diagnostic = `${resolved.reason}; cannot record ${content}`;
138
+ note(diagnostic);
139
+ return { exitCode: 0, wrote: false, diagnostic };
140
+ }
141
+ writeLedger = resolved.write;
142
+ }
143
+ const result = await writeLedger({ sessionId, content, source: LEDGER_SOURCE });
144
+ if (!result.ok) {
145
+ const diagnostic = `ledger write failed: ${result.reason ?? "unknown error"}`;
146
+ note(diagnostic);
147
+ return { exitCode: 0, wrote: false, diagnostic };
148
+ }
149
+ const diagnostic = `recorded ${content} for session ${sessionId}`;
150
+ note(diagnostic);
151
+ return { exitCode: 0, wrote: true, diagnostic };
152
+ }
153
+ //# sourceMappingURL=hook-post-merge-gate-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-post-merge-gate-record.js","sourceRoot":"","sources":["../../../src/cli/pack/hook-post-merge-gate-record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type LedgerEntry } from "../../policies/index.js";
2
+ import { type Manifest } from "../../schema/index.js";
3
+ import { type LoaderOptions } from "../loader.js";
4
+ export interface PackHookPostMergeGateOptions extends LoaderOptions {
5
+ /** Defaults to process.stdin. */
6
+ stdin?: NodeJS.ReadableStream;
7
+ /** Defaults to process.stdout. */
8
+ stdout?: NodeJS.WritableStream;
9
+ /** Defaults to process.stderr. */
10
+ stderr?: NodeJS.WritableStream;
11
+ /** Override cwd resolution (test injection). Falls back to event.cwd then process.cwd(). */
12
+ cwd?: string;
13
+ /** Per-call ledger timeout in ms. */
14
+ ledgerTimeoutMs?: number;
15
+ /** Inject a manifest (test). */
16
+ manifest?: Manifest;
17
+ /** Inject a fake ledger query (test). */
18
+ ledgerQuery?: (sessionId: string) => Promise<LedgerEntry[] | {
19
+ degraded: string;
20
+ }>;
21
+ }
22
+ export interface PackHookPostMergeGateResult {
23
+ exitCode: number;
24
+ blocked: boolean;
25
+ /** Diagnostic line emitted to stderr (always, even on allow). */
26
+ diagnostic: string;
27
+ }
28
+ export declare function runPackHookPostMergeGateCli(opts?: PackHookPostMergeGateOptions): Promise<PackHookPostMergeGateResult>;
@@ -0,0 +1,244 @@
1
+ // `harness pack hook post-merge-gate` — PreToolUse blocker for the
2
+ // `post-merge-gate` policy pack.
3
+ //
4
+ // Receives Claude Code's PreToolUse event JSON on stdin and emits a
5
+ // `{ decision: "block" }` envelope when a CURATED history-mutating Bash
6
+ // command is about to run on a branch whose current tip exactly matches
7
+ // a merged-tip fact the producer recorded (see hook-post-merge-gate-record.ts).
8
+ //
9
+ // Evaluation order — deliberate, and pinned by the self-lock test suite:
10
+ //
11
+ // 1. Parse stdin. Malformed JSON, a non-Bash tool, or an empty command
12
+ // all ALLOW immediately (nothing to classify).
13
+ // 2. Pause sentinel (operator kill-switch) — same convention as every
14
+ // other pack hook.
15
+ // 3. ESCAPE ALLOWLIST — checked BEFORE manifest load, pack lookup, or
16
+ // any ledger query. `git switch`/`checkout`/`pull`/`fetch`,
17
+ // `git branch -d`/`-D`, `git stash list`/`show`, and any
18
+ // `harness ...` command ALWAYS pass, unconditionally, with NO
19
+ // dependency on whether the manifest or the ledger are reachable.
20
+ // This is the recovery path the deny message itself recommends; it
21
+ // must never be starved by an unrelated failure (the incident class
22
+ // this guards against: a different gate once got blocked alongside
23
+ // its own recovery command, and only the operator could unstick it).
24
+ // 4. CURATED MUTATION MATCH — commands outside the curated list
25
+ // (git commit/add/push/merge/rebase/cherry-pick/revert/reset/
26
+ // stash pop|apply, gh pr create/merge) pass through untouched.
27
+ // 5. Manifest load, pack-enabled check, git-context resolution
28
+ // (detached HEAD / no-repo ALLOWS — nothing to compare), then the
29
+ // ledger query.
30
+ // 6. DENY only when the current branch tip exactly matches a recorded
31
+ // `post-merge-gate:merged:<repo>:<branch>:<sha>` fact.
32
+ //
33
+ // Fail posture: OPEN. A manifest-load failure or a degraded ledger both
34
+ // ALLOW (with a stderr warning) — the inverse of branch-protection's
35
+ // fail-closed contract. Without the ledger, "merged" and "not merged" are
36
+ // indistinguishable, and fail-closed here would block ordinary git
37
+ // history work on every branch whenever grounding-mcp hiccups. See
38
+ // post-merge-gate-runtime.ts's header for the full rationale.
39
+ import { isCuratedMutationCommand, isEscapeCommand, MERGED_TAG_PREFIX, mergedTagMatchKey, PACK_NAME, resolveDefaultBranchName, } from "../../policy-packs/builtin/post-merge-gate-runtime.js";
40
+ import { queryLedgerByTag } from "../../policies/index.js";
41
+ import { resolveGitContext } from "../../runtime/git-context.js";
42
+ import { renderAgentFacing } from "../../runtime/agent-facing.js";
43
+ import { POLICY_DECISION_TYPE } from "../../runtime/ledger-record.js";
44
+ import { checkHookPause, loadManifestOrInjected, parseConfigUx, readStdin } from "./hook-bootstrap.js";
45
+ const DEFAULT_BRANCH_PLACEHOLDER = "<default-branch>";
46
+ function bashCommandOf(toolInput) {
47
+ if (typeof toolInput !== "object" || toolInput === null)
48
+ return "";
49
+ const cmd = toolInput["command"];
50
+ return typeof cmd === "string" ? cmd : "";
51
+ }
52
+ function findGroundingMcp(manifest) {
53
+ return manifest.tools.mcp.find((m) => m.name === "grounding-mcp") ?? null;
54
+ }
55
+ function evaluateEntries(entries, matchKey) {
56
+ for (const e of entries) {
57
+ // Skip policy_decision audit rows — a past DENIED decision this very
58
+ // pack recorded would otherwise incidentally carry the match key in
59
+ // its serialized payload, falsely satisfying itself. Same two-tier
60
+ // filter branch-protection's blocker uses (type first, legacy
61
+ // content-prefix backstop second).
62
+ if (e.type === POLICY_DECISION_TYPE)
63
+ continue;
64
+ if (e.content.startsWith(`${POLICY_DECISION_TYPE}:`))
65
+ continue;
66
+ if (e.content.includes(matchKey)) {
67
+ return { merged: true, matchedContent: e.content, degraded: null };
68
+ }
69
+ }
70
+ return { merged: false, matchedContent: null, degraded: null };
71
+ }
72
+ async function probeLedger(manifest, sessionId, matchKey, opts) {
73
+ if (opts.ledgerQuery) {
74
+ const r = await opts.ledgerQuery(sessionId);
75
+ if ("degraded" in r) {
76
+ return { merged: false, matchedContent: null, degraded: r.degraded };
77
+ }
78
+ return evaluateEntries(r, matchKey);
79
+ }
80
+ if (!manifest) {
81
+ return { merged: false, matchedContent: null, degraded: "manifest unavailable" };
82
+ }
83
+ const server = findGroundingMcp(manifest);
84
+ if (!server) {
85
+ return { merged: false, matchedContent: null, degraded: "grounding-mcp not declared in manifest" };
86
+ }
87
+ const command = Array.isArray(server.command)
88
+ ? server.command
89
+ : server.command.trim().split(/\s+/);
90
+ const env = server.env ?? undefined;
91
+ const timeoutMs = opts.ledgerTimeoutMs ?? server.health?.timeout_ms ?? 5_000;
92
+ const result = await queryLedgerByTag({
93
+ mcpCommand: command,
94
+ ...(env && { mcpEnv: env }),
95
+ sessionId,
96
+ timeoutMs,
97
+ });
98
+ if (result.kind === "degraded") {
99
+ return { merged: false, matchedContent: null, degraded: result.reason };
100
+ }
101
+ return evaluateEntries(result.entries, matchKey);
102
+ }
103
+ function blockJson(toolName, command, branch, defaultBranch, matchedContent, ux, sessionId) {
104
+ let reasonText;
105
+ if (ux) {
106
+ reasonText = renderAgentFacing(ux, {
107
+ BRANCH: branch,
108
+ DEFAULT_BRANCH: defaultBranch,
109
+ TOOL_NAME: toolName,
110
+ SESSION_ID: sessionId,
111
+ });
112
+ }
113
+ else {
114
+ reasonText =
115
+ `post-merge-gate: refusing ${toolName} ("${command}") on branch "${branch}" — ` +
116
+ `its current tip was already merged (recorded: ${matchedContent}).\n` +
117
+ `Further history-mutating commands on an already-merged branch usually mean stale local state.\n` +
118
+ `\n` +
119
+ `To proceed:\n` +
120
+ ` git switch ${defaultBranch}\n` +
121
+ ` git pull --ff-only\n` +
122
+ ` git branch -d ${branch} # optional cleanup\n` +
123
+ `\n` +
124
+ `If you have NEW work to continue on this branch (not leftover local state): make a commit first —` +
125
+ ` this gate only fires while the branch tip still exactly matches the merged commit, so a new commit` +
126
+ ` moves the tip and this check no longer applies.\n` +
127
+ `\n` +
128
+ `Escape hatches (always allowed, independent of this gate): git switch/checkout, git pull/fetch,` +
129
+ ` git branch -d/-D, git stash list/show, and any \`harness ...\` command.`;
130
+ }
131
+ return JSON.stringify({
132
+ decision: "block",
133
+ reason: reasonText,
134
+ hookSpecificOutput: {
135
+ hookEventName: "PreToolUse",
136
+ permissionDecision: "deny",
137
+ permissionDecisionReason: reasonText,
138
+ },
139
+ });
140
+ }
141
+ export async function runPackHookPostMergeGateCli(opts = {}) {
142
+ const stdin = opts.stdin ?? process.stdin;
143
+ const stdout = opts.stdout ?? process.stdout;
144
+ const stderr = opts.stderr ?? process.stderr;
145
+ const note = (msg) => {
146
+ stderr.write(`harness pack hook post-merge-gate: ${msg}\n`);
147
+ };
148
+ const raw = await readStdin(stdin);
149
+ let event = {};
150
+ try {
151
+ event = JSON.parse(raw.trim() || "{}");
152
+ }
153
+ catch {
154
+ const diagnostic = "malformed event JSON, cannot classify; allowing";
155
+ note(diagnostic);
156
+ return { exitCode: 0, blocked: false, diagnostic };
157
+ }
158
+ // Pause sentinel — even this gate yields to an operator pause.
159
+ if (checkHookPause(PACK_NAME, stderr, opts).paused) {
160
+ const diagnostic = "harness paused; post-merge-gate allowing without evaluating.";
161
+ return { exitCode: 0, blocked: false, diagnostic };
162
+ }
163
+ const sessionId = (typeof event.session_id === "string" ? event.session_id : undefined) ??
164
+ process.env.CLAUDE_CODE_SESSION_ID ??
165
+ process.env.CLAUDE_SESSION_ID ??
166
+ "";
167
+ const toolName = typeof event.tool_name === "string" ? event.tool_name : "(unknown)";
168
+ const cwd = typeof opts.cwd === "string" && opts.cwd.length > 0
169
+ ? opts.cwd
170
+ : typeof event.cwd === "string" && event.cwd.length > 0
171
+ ? event.cwd
172
+ : process.cwd();
173
+ if (toolName !== "Bash") {
174
+ const diagnostic = `${toolName} is not Bash; allowing`;
175
+ note(diagnostic);
176
+ return { exitCode: 0, blocked: false, diagnostic };
177
+ }
178
+ const command = bashCommandOf(event.tool_input);
179
+ if (command === "") {
180
+ const diagnostic = "no resolvable command text; allowing";
181
+ note(diagnostic);
182
+ return { exitCode: 0, blocked: false, diagnostic };
183
+ }
184
+ // ESCAPE ALLOWLIST — checked FIRST, unconditionally, before manifest
185
+ // load, pack lookup, or any ledger query. See module header.
186
+ if (isEscapeCommand(command)) {
187
+ const diagnostic = `escape command matched; allowing regardless of ledger/manifest state`;
188
+ note(diagnostic);
189
+ return { exitCode: 0, blocked: false, diagnostic };
190
+ }
191
+ if (!isCuratedMutationCommand(command)) {
192
+ const diagnostic = `command is not in the curated v1 deny-scope; allowing`;
193
+ note(diagnostic);
194
+ return { exitCode: 0, blocked: false, diagnostic };
195
+ }
196
+ // Fail-open manifest load (opposite of branch-protection's fail-closed):
197
+ // without the manifest we cannot tell if the pack is even enabled, and
198
+ // this pack's whole posture is advisory, not a hard security boundary.
199
+ let manifest;
200
+ try {
201
+ ({ manifest } = loadManifestOrInjected(opts, opts.manifest));
202
+ }
203
+ catch (err) {
204
+ const diagnostic = `manifest load failed (${err.message}); post-merge-gate fails open, allowing`;
205
+ note(diagnostic);
206
+ return { exitCode: 0, blocked: false, diagnostic };
207
+ }
208
+ const pack = manifest.policy_packs.find((p) => p.name === PACK_NAME);
209
+ if (!pack) {
210
+ const diagnostic = `pack "${PACK_NAME}" not declared in manifest, allowing`;
211
+ note(diagnostic);
212
+ return { exitCode: 0, blocked: false, diagnostic };
213
+ }
214
+ if (!pack.enabled) {
215
+ const diagnostic = `pack "${PACK_NAME}" is enabled:false, allowing`;
216
+ note(diagnostic);
217
+ return { exitCode: 0, blocked: false, diagnostic };
218
+ }
219
+ const { repo, branch, sha } = resolveGitContext(cwd);
220
+ if (branch === "" || sha === "" || repo === "") {
221
+ const diagnostic = `cannot resolve git context for ${cwd} (detached HEAD, outside a git work tree, or unresolvable sha); allowing`;
222
+ note(diagnostic);
223
+ return { exitCode: 0, blocked: false, diagnostic };
224
+ }
225
+ const configUx = parseConfigUx(pack.config["ux"], stderr, "harness pack hook post-merge-gate");
226
+ const matchKey = mergedTagMatchKey(repo, branch, sha);
227
+ const check = await probeLedger(manifest, sessionId, matchKey, opts);
228
+ if (check.degraded !== null) {
229
+ const diagnostic = `ledger degraded (${check.degraded}); post-merge-gate fails open, allowing`;
230
+ note(diagnostic);
231
+ return { exitCode: 0, blocked: false, diagnostic };
232
+ }
233
+ if (!check.merged) {
234
+ const diagnostic = `no recorded ${MERGED_TAG_PREFIX} fact for ${repo}:${branch} at tip ${sha.slice(0, 7)}; allowing`;
235
+ note(diagnostic);
236
+ return { exitCode: 0, blocked: false, diagnostic };
237
+ }
238
+ const defaultBranch = resolveDefaultBranchName(cwd) ?? DEFAULT_BRANCH_PLACEHOLDER;
239
+ const diagnostic = `BLOCK — branch tip ${sha.slice(0, 7)} matches a recorded merged tip (${check.matchedContent ?? matchKey})`;
240
+ note(diagnostic);
241
+ stdout.write(`${blockJson(toolName, command, branch, defaultBranch, check.matchedContent ?? matchKey, configUx, sessionId)}\n`);
242
+ return { exitCode: 0, blocked: true, diagnostic };
243
+ }
244
+ //# sourceMappingURL=hook-post-merge-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-post-merge-gate.js","sourceRoot":"","sources":["../../../src/cli/pack/hook-post-merge-gate.ts"],"names":[],"mappings":"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"}