@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.
- package/CHANGELOG.md +31 -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/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/format.js +37 -0
- package/dist/cli/doctor/format.js.map +1 -1
- package/dist/cli/doctor/index.d.ts +10 -0
- package/dist/cli/doctor/index.js +24 -0
- 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 +11 -0
- package/dist/cli/doctor/types.js.map +1 -1
- package/dist/cli/index.js +253 -5
- 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 +3 -9
- 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/interactive.d.ts +33 -0
- package/dist/cli/init/interactive.js +399 -5
- package/dist/cli/init/interactive.js.map +1 -1
- package/dist/cli/init/profiles.d.ts +1 -1
- package/dist/cli/init/profiles.js +1 -1
- package/dist/cli/init/templates.d.ts +1 -1
- package/dist/cli/init/templates.js +64 -5
- package/dist/cli/init/templates.js.map +1 -1
- package/dist/cli/main.js +10 -0
- package/dist/cli/main.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-solution-acceptance-writeguard.js +148 -2
- package/dist/cli/pack/hook-solution-acceptance-writeguard.js.map +1 -1
- 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/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 +7 -0
- package/dist/cli/session-start/index.js +133 -38
- 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/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/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/registry.d.ts +1 -1
- package/dist/policy-packs/registry.js +12 -0
- package/dist/policy-packs/registry.js.map +1 -1
- 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/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/read-only-bash.js +118 -0
- package/dist/runtime/read-only-bash.js.map +1 -1
- package/dist/schema/index.d.ts +41 -0
- package/dist/schema/index.js +5 -0
- package/dist/schema/index.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
|
@@ -17,6 +17,40 @@
|
|
|
17
17
|
// (covers `echo >`, `$SOLUTION_VERDICT_DIR` spellings, `tee`, `mv`/`cp`/
|
|
18
18
|
// `ln`/`install`, `python3 -c '...path...'`, and `chmod`/`chattr` that
|
|
19
19
|
// would loosen perms) — or whose shell cwd is inside the dir.
|
|
20
|
+
// - Bash `cd` whose RESOLVED target is inside the verdict dir. `cd` itself
|
|
21
|
+
// is provably read-only (task fb67b402 added it to the shared
|
|
22
|
+
// read-only-bash floor: it mutates only the invoking shell's own cwd,
|
|
23
|
+
// never the filesystem), so it no longer reaches the "not read-only"
|
|
24
|
+
// checks below. But stepping into the dir is the setup half of a
|
|
25
|
+
// two-call forge (`cd <dir>` then, in a LATER un-chained Bash call,
|
|
26
|
+
// a bare relative write): this pre-check keeps that first step blocked
|
|
27
|
+
// as defense-in-depth, ahead of (not instead of) the cwd-inside check
|
|
28
|
+
// below, which is what actually closes the later relative-write call
|
|
29
|
+
// once cwd has genuinely moved. A `cd` target that `path.resolve`
|
|
30
|
+
// cannot literally evaluate does NOT get `cd`'s read-only fast path
|
|
31
|
+
// either: it falls through to the same reference-based checks as any
|
|
32
|
+
// other non-read-only Bash. `CD_TARGET_UNRESOLVABLE_CHARS` documents
|
|
33
|
+
// exactly WHICH expansions this enumerates (quoting, `$`/env-var,
|
|
34
|
+
// `~`, glob, and `{...}` brace expansion) — that list is what this
|
|
35
|
+
// check catches, not a claim that every shell-expansion class is
|
|
36
|
+
// closed. Known-open residual, pre-existing (not introduced by this
|
|
37
|
+
// branch, since it applies to `bashReferencesVerdictDir`'s textual
|
|
38
|
+
// match on ANY Bash command, not just `cd`): a backslash-escaped
|
|
39
|
+
// spelling of the leaf, e.g. `cd <parent>/solution\-verdicts`, still
|
|
40
|
+
// navigates into the dir under bash (verified against bash 3.2.57)
|
|
41
|
+
// while `bashReferencesVerdictDir` returns false — the backslash
|
|
42
|
+
// breaks the literal-leaf substring match and no metacharacter here
|
|
43
|
+
// triggers the glob/brace fallback either. Closing it needs
|
|
44
|
+
// shell-unescaping in the textual check itself, which is more than
|
|
45
|
+
// this task absorbs; do not assume the class is closed.
|
|
46
|
+
// A SECOND residual of the same class, and on a macOS operator
|
|
47
|
+
// machine the more reachable of the two: case variance.
|
|
48
|
+
// `cd <parent>/SOLUTION-VERDICTS` navigates into the dir on a
|
|
49
|
+
// case-insensitive APFS volume, but `isInsideDir` compares with a
|
|
50
|
+
// case-sensitive `path.relative` and the textual check uses a
|
|
51
|
+
// case-sensitive `includes`, so both return false. Also allowed:
|
|
52
|
+
// a trailing backslash, `cd <DIR>\`. Both pre-existing; closing
|
|
53
|
+
// them needs case-folding in the textual check.
|
|
20
54
|
//
|
|
21
55
|
// Pure reads (`cat <dir>/x.json`) are allowed so the guard is not over-broad.
|
|
22
56
|
//
|
|
@@ -30,7 +64,10 @@
|
|
|
30
64
|
// write paths above. A path constructed at runtime inside an interpreter
|
|
31
65
|
// with no textual reference is NOT caught; marker signing (a cross-repo
|
|
32
66
|
// follow-up) closes content-authenticity against an unguarded write
|
|
33
|
-
// primitive.
|
|
67
|
+
// primitive. The `cd`-target check added later (task fb67b402) has its own
|
|
68
|
+
// enumerated, not exhaustive, expansion list — see the bullet above and
|
|
69
|
+
// `CD_TARGET_UNRESOLVABLE_CHARS`'s docstring for the backslash-escaping
|
|
70
|
+
// residual specifically.
|
|
34
71
|
import { bashReferencesVerdictDir, isInsideDir, PACK_NAME, verdictDir as resolveVerdictDir, } from "../../policy-packs/builtin/solution-acceptance-runtime.js";
|
|
35
72
|
import { isReadOnlyBashCommand } from "../../runtime/read-only-bash.js";
|
|
36
73
|
import { checkHookPause, readStdin } from "./hook-bootstrap.js";
|
|
@@ -60,6 +97,94 @@ function bashCommandOf(toolInput) {
|
|
|
60
97
|
const cmd = toolInput["command"];
|
|
61
98
|
return typeof cmd === "string" ? cmd : "";
|
|
62
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Extract `cd`'s destination argument from a Bash command string, or null
|
|
102
|
+
* when the command is not a `cd` invocation or has no statically resolvable
|
|
103
|
+
* destination. Whitespace-tokenized, same as `read-only-bash.ts`'s own
|
|
104
|
+
* classifier (this hook does not shell-parse either).
|
|
105
|
+
*
|
|
106
|
+
* Deliberately narrow:
|
|
107
|
+
* - Only fires when the FIRST token is exactly `cd`. `env cd x` or a
|
|
108
|
+
* chained `foo && cd x` do not match here (tokens[0] would be `env` /
|
|
109
|
+
* `foo`); those are unaffected by this pre-check and are still governed
|
|
110
|
+
* by the existing not-read-only + `bashReferencesVerdictDir` checks
|
|
111
|
+
* below, which already close the `cd <parent> && write <relative>`
|
|
112
|
+
* descent via the leaf-segment match.
|
|
113
|
+
* - `cd`'s own flags (`-L`, `-P`, `-e`, `-@`, and combinations) are
|
|
114
|
+
* skipped to find the first positional path argument.
|
|
115
|
+
* - `cd -` (switch to `$OLDPWD`) and a bare `cd` (goes to `$HOME`) have no
|
|
116
|
+
* destination this function can resolve without ambient shell state;
|
|
117
|
+
* both return null (not flagged), the same conservative stance as the
|
|
118
|
+
* rest of this module's enumerated-path checks.
|
|
119
|
+
* - A single layer of surrounding quotes (`"..."` or `'...'`) is stripped
|
|
120
|
+
* from the returned token before the caller does anything with it, so
|
|
121
|
+
* `cd "<path>"` and `cd <path>` are treated identically (both the
|
|
122
|
+
* resolved-path inside-dir check AND the unresolvable-chars check see
|
|
123
|
+
* the same unquoted value). Without this, a quoted literal that merely
|
|
124
|
+
* shares a text prefix with the verdict dir (`cd "<dir>-decoy"`) would
|
|
125
|
+
* route to the textual leaf match and be wrongly blocked, while the
|
|
126
|
+
* unquoted `cd <dir>-decoy` correctly passes via the resolved-path
|
|
127
|
+
* check — spelling-dependent behavior for what is the same destination.
|
|
128
|
+
*/
|
|
129
|
+
function cdTargetArgument(command) {
|
|
130
|
+
const tokens = command.trim().split(/\s+/);
|
|
131
|
+
if (tokens[0] !== "cd")
|
|
132
|
+
return null;
|
|
133
|
+
for (let i = 1; i < tokens.length; i += 1) {
|
|
134
|
+
const t = tokens[i];
|
|
135
|
+
if (t === undefined)
|
|
136
|
+
break;
|
|
137
|
+
if (t === "-")
|
|
138
|
+
return null;
|
|
139
|
+
if (t.startsWith("-"))
|
|
140
|
+
continue;
|
|
141
|
+
return stripSurroundingQuotes(t);
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Strip one layer of surrounding double or single quotes from `token`, or
|
|
147
|
+
* return it unchanged if it is not fully wrapped in a matching pair. Does
|
|
148
|
+
* NOT attempt any other shell-quoting semantics (no backslash-escape
|
|
149
|
+
* handling, no nested-quote handling) — this is a narrow normalization so a
|
|
150
|
+
* simple quoted literal reads the same as its unquoted form, not a shell
|
|
151
|
+
* parser.
|
|
152
|
+
*/
|
|
153
|
+
function stripSurroundingQuotes(token) {
|
|
154
|
+
if (token.length >= 2 &&
|
|
155
|
+
((token.startsWith('"') && token.endsWith('"')) ||
|
|
156
|
+
(token.startsWith("'") && token.endsWith("'")))) {
|
|
157
|
+
return token.slice(1, -1);
|
|
158
|
+
}
|
|
159
|
+
return token;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Characters/sequences that make a `cd` destination token something
|
|
163
|
+
* `path.resolve` cannot literally evaluate: quoting (`"`, `'` — the residual
|
|
164
|
+
* case after `stripSurroundingQuotes` has already removed a clean single
|
|
165
|
+
* layer, e.g. an unbalanced or embedded quote), env-var expansion (`$`),
|
|
166
|
+
* home-directory expansion (`~`), shell globbing (`*`, `?`, `[`), and brace
|
|
167
|
+
* expansion (`{`, `}`, `,`). `path.resolve` treats the raw token as a
|
|
168
|
+
* literal path segment, so `cd "$SOLUTION_VERDICT_DIR"`, `cd
|
|
169
|
+
* ~/.../solution-verdicts`, or `cd <parent>/{solution-verdicts,x}` all
|
|
170
|
+
* resolve to a nonsense path that is never "inside" the dir even though a
|
|
171
|
+
* real shell would expand each of them TO (or, for the brace form, INTO)
|
|
172
|
+
* the dir. A `cd` target containing any of these must therefore NOT take
|
|
173
|
+
* the read-only fast path in `evaluateWriteGuard`: control must fall
|
|
174
|
+
* through to the same `bashReferencesVerdictDir` text-reference check any
|
|
175
|
+
* other non-read-only Bash command goes through, which DOES recognize
|
|
176
|
+
* these spellings (the env-var token, the `agent-grounding/solution-verdicts`
|
|
177
|
+
* tail, and — after the matching widening in
|
|
178
|
+
* `solution-acceptance-runtime.ts`'s glob-metacharacter test — glob- and
|
|
179
|
+
* brace-obscured leaf words).
|
|
180
|
+
*
|
|
181
|
+
* This list is enumerated, not exhaustive: it is exactly the expansion
|
|
182
|
+
* classes this check has been reasoned about, not a claim that every way a
|
|
183
|
+
* shell can rewrite a `cd` argument is covered. A known-open residual
|
|
184
|
+
* (pre-existing, not introduced by this check) is backslash escaping — see
|
|
185
|
+
* the module header's "Known-open residual" note.
|
|
186
|
+
*/
|
|
187
|
+
const CD_TARGET_UNRESOLVABLE_CHARS = /[$~*?[{},"']/;
|
|
63
188
|
/**
|
|
64
189
|
* Pure write-guard decision for a tool event. Exported for direct unit
|
|
65
190
|
* testing of the full forge-attempt matrix without spinning up the CLI.
|
|
@@ -100,7 +225,28 @@ export function evaluateWriteGuard(toolName, toolInput, dir, cwd) {
|
|
|
100
225
|
const command = bashCommandOf(toolInput);
|
|
101
226
|
if (command === "")
|
|
102
227
|
return { blocked: false, reason: "empty Bash command" };
|
|
103
|
-
|
|
228
|
+
// Defense-in-depth, ahead of the read-only fast path below: `cd` itself
|
|
229
|
+
// cannot write, but `cd`ing into the verdict dir is the setup half of a
|
|
230
|
+
// two-call forge (see the module header). Only a RESOLVED-path check
|
|
231
|
+
// (via the shared `isInsideDir`, not a substring match) so a sibling
|
|
232
|
+
// that merely shares a text prefix with the dir (`solution-verdicts-decoy`,
|
|
233
|
+
// or a parent directory of it) is not wrongly flagged.
|
|
234
|
+
const cdTarget = cdTargetArgument(command);
|
|
235
|
+
if (cdTarget !== null && isInsideDir(cdTarget, dir, cwd)) {
|
|
236
|
+
return {
|
|
237
|
+
blocked: true,
|
|
238
|
+
reason: `cd targets the harness-protected solution-verdict dir (${dir}); stepping into it would set up a later un-chained relative write to forge the verdict marker`,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
// A `cd` target containing one of the enumerated unresolvable
|
|
242
|
+
// expansions (see `CD_TARGET_UNRESOLVABLE_CHARS`'s docstring for the
|
|
243
|
+
// exact list and its non-exhaustive scope) must not take `cd`'s
|
|
244
|
+
// read-only fast path below: without this, `cd "$SOLUTION_VERDICT_DIR"`
|
|
245
|
+
// etc. would be waved through by `isReadOnlyBashCommand` (true for ANY
|
|
246
|
+
// `cd`, per the shared read-only-bash floor) before ever reaching the
|
|
247
|
+
// reference check that recognizes these exact spellings.
|
|
248
|
+
const cdTargetUnresolvable = cdTarget !== null && CD_TARGET_UNRESOLVABLE_CHARS.test(cdTarget);
|
|
249
|
+
if (!cdTargetUnresolvable && isReadOnlyBashCommand(command)) {
|
|
104
250
|
return { blocked: false, reason: "read-only Bash command" };
|
|
105
251
|
}
|
|
106
252
|
if (isInsideDir(".", dir, cwd)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-solution-acceptance-writeguard.js","sourceRoot":"","sources":["../../../src/cli/pack/hook-solution-acceptance-writeguard.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,sEAAsE;AACtE,EAAE;AACF,0EAA0E;AAC1E,iEAAiE;AACjE,yEAAyE;AACzE,8EAA8E;AAC9E,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,EAAE;AACF,0CAA0C;AAC1C,yEAAyE;AACzE,8BAA8B;AAC9B,uEAAuE;AACvE,yEAAyE;AACzE,6EAA6E;AAC7E,2EAA2E;AAC3E,kEAAkE;AAClE,EAAE;AACF,8EAA8E;AAC9E,EAAE;AACF,2EAA2E;AAC3E,0EAA0E;AAC1E,6EAA6E;AAC7E,8EAA8E;AAC9E,yCAAyC;AACzC,EAAE;AACF,4EAA4E;AAC5E,yEAAyE;AACzE,wEAAwE;AACxE,oEAAoE;AACpE,
|
|
1
|
+
{"version":3,"file":"hook-solution-acceptance-writeguard.js","sourceRoot":"","sources":["../../../src/cli/pack/hook-solution-acceptance-writeguard.ts"],"names":[],"mappings":"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"}
|
|
@@ -53,7 +53,7 @@ export function renderReportSchemaHint() {
|
|
|
53
53
|
// one pair implied exhaustiveness. The bullets below show the canonical
|
|
54
54
|
// names; the parser's alias-tolerance is a quiet bonus, not something
|
|
55
55
|
// the agent needs to choose between.
|
|
56
|
-
const intro = "Report format (parsed by `@lannguyensi/understanding-gate`): markdown with these ten sections, any heading level (#, ##, ###), names case-insensitive. Missing any section produces a parse-error under `.understanding-gate/parse-errors/` and the audit trail is empty even though the gate-approval marker still gets written.";
|
|
56
|
+
const intro = "Report format (parsed by `@lannguyensi/understanding-gate`): markdown with these ten sections, any heading level (#, ##, ###), names case-insensitive. Sections marked (list) need markdown list items ('- ' or '1.') in the body — a prose paragraph under a (list) heading is rejected the same as a missing section. Missing any section produces a parse-error under `.understanding-gate/parse-errors/` and the audit trail is empty even though the gate-approval marker still gets written.";
|
|
57
57
|
const bullets = UNDERSTANDING_REPORT_REQUIRED_SECTIONS.map((s) => ` - ${s}`).join("\n");
|
|
58
58
|
// Submission recipe (task 61fd36db): the Stop-hook producer fires only
|
|
59
59
|
// at END of turn — after `harness approve understanding` already ran —
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"understanding-report-schema-hint.js","sourceRoot":"","sources":["../../../src/cli/pack/understanding-report-schema-hint.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,wEAAwE;AACxE,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,sEAAsE;AACtE,wEAAwE;AACxE,uEAAuE;AACvE,+CAA+C;AAC/C,EAAE;AACF,kEAAkE;AAClE,wDAAwD;AACxD,qEAAqE;AACrE,qEAAqE;AACrE,qEAAqE;AACrE,oEAAoE;AACpE,oEAAoE;AACpE,mEAAmE;AAEnE,MAAM,CAAC,MAAM,sCAAsC,GAAG;IACpD,mCAAmC;IACnC,8BAA8B;IAC9B,sBAAsB;IACtB,4BAA4B;IAC5B,oBAAoB;IACpB,uBAAuB;IACvB,qBAAqB;IACrB,cAAc;IACd,0BAA0B;IAC1B,qEAAqE;IACrE,yDAAyD;IACzD,kEAAkE;IAClE,kEAAkE;IAClE,qCAAqC;IACrC,kBAAkB;CACV,CAAC;AAEX;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB;IACpC,uEAAuE;IACvE,wEAAwE;IACxE,+DAA+D;IAC/D,yEAAyE;IACzE,oEAAoE;IACpE,wEAAwE;IACxE,sEAAsE;IACtE,qCAAqC;IACrC,MAAM,KAAK,GACT,
|
|
1
|
+
{"version":3,"file":"understanding-report-schema-hint.js","sourceRoot":"","sources":["../../../src/cli/pack/understanding-report-schema-hint.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,wEAAwE;AACxE,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,sEAAsE;AACtE,wEAAwE;AACxE,uEAAuE;AACvE,+CAA+C;AAC/C,EAAE;AACF,kEAAkE;AAClE,wDAAwD;AACxD,qEAAqE;AACrE,qEAAqE;AACrE,qEAAqE;AACrE,oEAAoE;AACpE,oEAAoE;AACpE,mEAAmE;AAEnE,MAAM,CAAC,MAAM,sCAAsC,GAAG;IACpD,mCAAmC;IACnC,8BAA8B;IAC9B,sBAAsB;IACtB,4BAA4B;IAC5B,oBAAoB;IACpB,uBAAuB;IACvB,qBAAqB;IACrB,cAAc;IACd,0BAA0B;IAC1B,qEAAqE;IACrE,yDAAyD;IACzD,kEAAkE;IAClE,kEAAkE;IAClE,qCAAqC;IACrC,kBAAkB;CACV,CAAC;AAEX;;;;;;;;;;GAUG;AACH,MAAM,UAAU,sBAAsB;IACpC,uEAAuE;IACvE,wEAAwE;IACxE,+DAA+D;IAC/D,yEAAyE;IACzE,oEAAoE;IACpE,wEAAwE;IACxE,sEAAsE;IACtE,qCAAqC;IACrC,MAAM,KAAK,GACT,oeAAoe,CAAC;IACve,MAAM,OAAO,GAAG,sCAAsC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzF,uEAAuE;IACvE,uEAAuE;IACvE,mEAAmE;IACnE,oEAAoE;IACpE,sDAAsD;IACtD,MAAM,MAAM,GACV,yFAAyF;QACzF,sFAAsF;QACtF,4DAA4D;QAC5D,6BAA6B;QAC7B,uBAAuB;QACvB,wBAAwB,CAAC;IAC3B,OAAO,GAAG,KAAK,KAAK,OAAO,KAAK,MAAM,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type LedgerWriteFn } from "../../runtime/ledger-writer.js";
|
|
2
|
+
import { type ResolveReadSessionOptions } from "../../runtime/session-id.js";
|
|
3
|
+
import { type LoaderOptions } from "../loader.js";
|
|
4
|
+
/** Options shared by every `record` verb. */
|
|
5
|
+
export interface RecordCommonOptions extends LoaderOptions {
|
|
6
|
+
/** Working directory used for git-context resolution. Defaults to `process.cwd()`. */
|
|
7
|
+
cwd?: string;
|
|
8
|
+
/** Defaults to `process.stderr`. Warnings and error reasons land here. */
|
|
9
|
+
stderr?: NodeJS.WritableStream;
|
|
10
|
+
/** Explicit session id (overrides env + transcript discovery). */
|
|
11
|
+
session?: string;
|
|
12
|
+
/** Per-call ledger timeout in ms. */
|
|
13
|
+
ledgerTimeoutMs?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Inject the read-path session resolver (test seam). Production uses
|
|
16
|
+
* `resolveReadSessionId` from `runtime/session-id`, the same
|
|
17
|
+
* precedence chain `harness audit` / `harness explain --trace` use.
|
|
18
|
+
*/
|
|
19
|
+
resolveSession?: (explicit: string | undefined, opts: ResolveReadSessionOptions) => string;
|
|
20
|
+
/** Inject the ledger writer (test seam). */
|
|
21
|
+
writeLedger?: LedgerWriteFn;
|
|
22
|
+
}
|
|
23
|
+
/** Structured outcome of a `record` verb — testable without spawning a process. */
|
|
24
|
+
export interface RecordResult {
|
|
25
|
+
/** 0 on success; EX_USAGE (64) for a bad argument, EX_FAIL (1) for a runtime failure. */
|
|
26
|
+
exitCode: number;
|
|
27
|
+
/** Whether the ledger fact was actually written. */
|
|
28
|
+
wrote: boolean;
|
|
29
|
+
/** The exact content string written (or that would have been written); "" on early validation failure. */
|
|
30
|
+
content: string;
|
|
31
|
+
/** Resolved session id ("" only when validation failed before session resolution). */
|
|
32
|
+
sessionId: string;
|
|
33
|
+
/** Resolved branch tag ("" when the verb does not use one, or resolution failed). */
|
|
34
|
+
branch: string;
|
|
35
|
+
/** Human-readable explanation of a non-write outcome. */
|
|
36
|
+
reason?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface RecordReviewOptions extends RecordCommonOptions {
|
|
39
|
+
/** PR number (or identifier) — required, non-empty. */
|
|
40
|
+
pr: string;
|
|
41
|
+
/** Explicit base-branch override; see resolveBase() for the fallback chain. */
|
|
42
|
+
base?: string;
|
|
43
|
+
/** Explicit branch override (otherwise resolved via resolveGitContext(cwd)). */
|
|
44
|
+
branch?: string;
|
|
45
|
+
/** Free-form review summary — required, non-empty. */
|
|
46
|
+
summary: string;
|
|
47
|
+
}
|
|
48
|
+
export declare function runRecordReview(opts: RecordReviewOptions): Promise<RecordResult>;
|
|
49
|
+
export interface RecordReviewSubagentOptions extends RecordCommonOptions {
|
|
50
|
+
/** agent-tasks task id — required, non-empty. */
|
|
51
|
+
task: string;
|
|
52
|
+
/** Reviewer verdict — required, non-empty. */
|
|
53
|
+
verdict: string;
|
|
54
|
+
/** Explicit branch override (otherwise resolved via resolveGitContext(cwd)). */
|
|
55
|
+
branch?: string;
|
|
56
|
+
/** Optional free-form summary appended after the verdict. */
|
|
57
|
+
summary?: string;
|
|
58
|
+
}
|
|
59
|
+
export declare function runRecordReviewSubagent(opts: RecordReviewSubagentOptions): Promise<RecordResult>;
|
|
60
|
+
export interface RecordDogfoodOptions extends RecordCommonOptions {
|
|
61
|
+
/** End-to-end smoke summary — required, non-empty. */
|
|
62
|
+
summary: string;
|
|
63
|
+
}
|
|
64
|
+
export declare function runRecordDogfood(opts: RecordDogfoodOptions): Promise<RecordResult>;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// `harness record {review,review-subagent,dogfood}` — operator/agent-
|
|
2
|
+
// driven evidence-ledger producers for the review-before-merge,
|
|
3
|
+
// review-subagent-before-pr-create, and dogfood-before-release gate
|
|
4
|
+
// families (see src/cli/init/templates.ts for the exact policy
|
|
5
|
+
// definitions and tag shapes these verbs feed).
|
|
6
|
+
//
|
|
7
|
+
// Unlike `harness session-start preflight` (a SessionStart hook that
|
|
8
|
+
// MUST exit 0 on every path so it never breaks the session loop), the
|
|
9
|
+
// `record` verbs are INTERACTIVE: an agent or operator invokes them
|
|
10
|
+
// deliberately to attach a review verdict / dogfood summary to the
|
|
11
|
+
// ledger. A failure here (unreachable ledger, no git context, an empty
|
|
12
|
+
// summary) is a real error the caller needs to see and react to, so
|
|
13
|
+
// every verb exits non-zero with a clear stderr message on failure
|
|
14
|
+
// instead of degrading silently. Each verb still returns a structured
|
|
15
|
+
// `RecordResult` (not just a thrown error) so both paths are testable
|
|
16
|
+
// without spawning a process — same "degrade-with-reason" convention
|
|
17
|
+
// `runSessionStartPreflight` uses.
|
|
18
|
+
//
|
|
19
|
+
// Composition mirrors session-start/index.ts: build the ledger write
|
|
20
|
+
// via the manifest's declared `grounding-mcp` server (through the
|
|
21
|
+
// shared `resolveManifestLedgerWriter` — see runtime/ledger-writer.ts),
|
|
22
|
+
// resolve branch via `resolveGitContext` (the SAME function the
|
|
23
|
+
// preflight-before-* gates use) and session via `resolveReadSessionId`,
|
|
24
|
+
// with `--branch` / `--session` as explicit overrides. No new JSON-RPC
|
|
25
|
+
// or subprocess code: every ledger write goes through the existing
|
|
26
|
+
// `addLedgerFact` primitive.
|
|
27
|
+
import { findGitEntry, resolveCommonDir, resolveGitContext, resolveOriginHeadBase, } from "../../runtime/git-context.js";
|
|
28
|
+
import { resolveManifestLedgerWriter } from "../../runtime/ledger-writer.js";
|
|
29
|
+
import { resolveReadSessionId, } from "../../runtime/session-id.js";
|
|
30
|
+
import { EX_FAIL, EX_USAGE } from "../exit-codes.js";
|
|
31
|
+
import { loadManifest } from "../loader.js";
|
|
32
|
+
const LEDGER_SOURCE_REVIEW = "harness-record-review";
|
|
33
|
+
const LEDGER_SOURCE_REVIEW_SUBAGENT = "harness-record-review-subagent";
|
|
34
|
+
const LEDGER_SOURCE_DOGFOOD = "harness-record-dogfood";
|
|
35
|
+
function resolveSession(opts) {
|
|
36
|
+
const resolve = opts.resolveSession ?? resolveReadSessionId;
|
|
37
|
+
return resolve(opts.session, {});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Write one ledger fact via the manifest's declared `grounding-mcp`
|
|
41
|
+
* server (or the injected `opts.writeLedger` test seam). Mirrors the
|
|
42
|
+
* manifest-wiring block `runSessionStartPreflight` uses, factored
|
|
43
|
+
* through the shared `resolveManifestLedgerWriter` helper.
|
|
44
|
+
*/
|
|
45
|
+
async function writeLedgerFact(opts, sessionId, source, content) {
|
|
46
|
+
let writeLedger = opts.writeLedger;
|
|
47
|
+
if (!writeLedger) {
|
|
48
|
+
let manifest;
|
|
49
|
+
try {
|
|
50
|
+
manifest = loadManifest(opts).manifest;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return { ok: false, reason: `manifest load failed: ${err.message}` };
|
|
54
|
+
}
|
|
55
|
+
const resolved = resolveManifestLedgerWriter(manifest, {
|
|
56
|
+
...(opts.ledgerTimeoutMs !== undefined ? { ledgerTimeoutMs: opts.ledgerTimeoutMs } : {}),
|
|
57
|
+
});
|
|
58
|
+
if (!resolved.ok) {
|
|
59
|
+
return { ok: false, reason: `${resolved.reason}; cannot record ${source} tag` };
|
|
60
|
+
}
|
|
61
|
+
writeLedger = resolved.write;
|
|
62
|
+
}
|
|
63
|
+
const result = await writeLedger({ sessionId, content, source });
|
|
64
|
+
if (!result.ok) {
|
|
65
|
+
return { ok: false, reason: `ledger write failed: ${result.reason ?? "unknown error"}` };
|
|
66
|
+
}
|
|
67
|
+
return { ok: true };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Shared setup every verb runs first: a `note()` sink prefixed with the
|
|
71
|
+
* verb's own name (so stderr lines are attributable when several verbs
|
|
72
|
+
* run in a script), the resolved cwd, and the resolved session id.
|
|
73
|
+
* Session id is resolved this early because `record dogfood`'s content
|
|
74
|
+
* embeds it directly (`dogfood:${sessionId}`).
|
|
75
|
+
*/
|
|
76
|
+
function initRecordVerb(opts, verbName) {
|
|
77
|
+
const stderr = opts.stderr ?? process.stderr;
|
|
78
|
+
const note = (msg) => {
|
|
79
|
+
stderr.write(`harness record ${verbName}: ${msg}\n`);
|
|
80
|
+
};
|
|
81
|
+
return { note, cwd: opts.cwd ?? process.cwd(), sessionId: resolveSession(opts) };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Trim `value` and refuse it if empty (a required flag / positional
|
|
85
|
+
* argument left blank). Returns the ready-to-`return`ed EX_USAGE
|
|
86
|
+
* `RecordResult` on failure so callers do not repeat that construction
|
|
87
|
+
* — shared by every "--pr / --task / --verdict / summary must not be
|
|
88
|
+
* empty" check across the three verbs.
|
|
89
|
+
*/
|
|
90
|
+
function requireNonEmpty(value, flagLabel, sessionId, note) {
|
|
91
|
+
const trimmed = (value ?? "").trim();
|
|
92
|
+
if (trimmed.length === 0) {
|
|
93
|
+
const reason = `${flagLabel} must not be empty`;
|
|
94
|
+
note(reason);
|
|
95
|
+
return {
|
|
96
|
+
ok: false,
|
|
97
|
+
result: { exitCode: EX_USAGE, wrote: false, content: "", sessionId, branch: "", reason },
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return { ok: true, value: trimmed };
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Resolve the branch tag `review` and `review-subagent` both require:
|
|
104
|
+
* explicit `--branch` wins, otherwise `resolveGitContext(cwd)` (the SAME
|
|
105
|
+
* function the preflight-before-* gates use). Returns the ready-to-
|
|
106
|
+
* `return`ed failure `RecordResult` on the shared "cannot resolve any
|
|
107
|
+
* branch" degrade path so callers do not repeat that construction.
|
|
108
|
+
*/
|
|
109
|
+
function resolveRequiredBranch(cwd, explicitBranch, sessionId, note) {
|
|
110
|
+
const gitContext = resolveGitContext(cwd);
|
|
111
|
+
const branch = (explicitBranch ?? "").trim() || gitContext.branch;
|
|
112
|
+
if (branch.length === 0) {
|
|
113
|
+
const reason = "no branch resolvable (cwd is not inside a git work tree, or HEAD is detached); pass --branch <name>";
|
|
114
|
+
note(reason);
|
|
115
|
+
return {
|
|
116
|
+
ok: false,
|
|
117
|
+
result: { exitCode: EX_FAIL, wrote: false, content: "", sessionId, branch: "", reason },
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return { ok: true, branch };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Shared tail every verb runs last: write the fact, translate a failure
|
|
124
|
+
* into the degrade-with-reason `RecordResult` shape, or report success.
|
|
125
|
+
*/
|
|
126
|
+
async function finishRecordWrite(opts, sessionId, branch, source, content, note) {
|
|
127
|
+
const written = await writeLedgerFact(opts, sessionId, source, content);
|
|
128
|
+
if (!written.ok) {
|
|
129
|
+
note(written.reason);
|
|
130
|
+
return { exitCode: EX_FAIL, wrote: false, content, sessionId, branch, reason: written.reason };
|
|
131
|
+
}
|
|
132
|
+
return { exitCode: 0, wrote: true, content, sessionId, branch };
|
|
133
|
+
}
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Base-branch resolution for `record review` (--base flag > origin/HEAD
|
|
136
|
+
// filesystem fallback > omit with a loud stderr warning). No `gh`
|
|
137
|
+
// shell-out: everything is read straight off the `.git` directory,
|
|
138
|
+
// reusing runtime/git-context.ts's exported `findGitEntry` walk instead
|
|
139
|
+
// of re-implementing it. `resolveOriginHeadBase` / `resolveCommonDir`
|
|
140
|
+
// themselves now live in runtime/git-context.ts too (task post-merge-gate,
|
|
141
|
+
// T-001) so `policy-packs/builtin/post-merge-gate-runtime.ts` can share
|
|
142
|
+
// them without a policy-pack module reaching into `cli/`; imported here
|
|
143
|
+
// unchanged.
|
|
144
|
+
// ---------------------------------------------------------------------------
|
|
145
|
+
/**
|
|
146
|
+
* Resolve the base branch for `record review`: explicit `--base` wins,
|
|
147
|
+
* then the origin/HEAD filesystem fallback, then omission with a loud
|
|
148
|
+
* stderr warning (never a silent gap — the operator needs to know the
|
|
149
|
+
* `review:<base>` tag did not land).
|
|
150
|
+
*/
|
|
151
|
+
function resolveBase(cwd, explicitBase, note) {
|
|
152
|
+
const flag = (explicitBase ?? "").trim();
|
|
153
|
+
if (flag.length > 0)
|
|
154
|
+
return flag;
|
|
155
|
+
const gitDir = findGitEntry(cwd)?.gitDir;
|
|
156
|
+
if (gitDir) {
|
|
157
|
+
const base = resolveOriginHeadBase(resolveCommonDir(gitDir));
|
|
158
|
+
if (base)
|
|
159
|
+
return base;
|
|
160
|
+
}
|
|
161
|
+
note("no --base given and origin/HEAD could not be resolved (checked " +
|
|
162
|
+
"refs/remotes/origin/HEAD and packed-refs); omitting the review:<base> tag. " +
|
|
163
|
+
"Pass --base <branch> to record it explicitly.");
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
export async function runRecordReview(opts) {
|
|
167
|
+
const { note, cwd, sessionId } = initRecordVerb(opts, "review");
|
|
168
|
+
const summaryResult = requireNonEmpty(opts.summary, "summary", sessionId, note);
|
|
169
|
+
if (!summaryResult.ok)
|
|
170
|
+
return summaryResult.result;
|
|
171
|
+
const summary = summaryResult.value;
|
|
172
|
+
const prResult = requireNonEmpty(opts.pr, "--pr", sessionId, note);
|
|
173
|
+
if (!prResult.ok)
|
|
174
|
+
return prResult.result;
|
|
175
|
+
const pr = prResult.value;
|
|
176
|
+
const branchResult = resolveRequiredBranch(cwd, opts.branch, sessionId, note);
|
|
177
|
+
if (!branchResult.ok)
|
|
178
|
+
return branchResult.result;
|
|
179
|
+
const branch = branchResult.branch;
|
|
180
|
+
const base = resolveBase(cwd, opts.base, note);
|
|
181
|
+
const content = `review:${pr} review:${branch}${base ? ` review:${base}` : ""} — ${summary}`;
|
|
182
|
+
return finishRecordWrite(opts, sessionId, branch, LEDGER_SOURCE_REVIEW, content, note);
|
|
183
|
+
}
|
|
184
|
+
export async function runRecordReviewSubagent(opts) {
|
|
185
|
+
const { note, cwd, sessionId } = initRecordVerb(opts, "review-subagent");
|
|
186
|
+
const taskResult = requireNonEmpty(opts.task, "--task", sessionId, note);
|
|
187
|
+
if (!taskResult.ok)
|
|
188
|
+
return taskResult.result;
|
|
189
|
+
const task = taskResult.value;
|
|
190
|
+
const verdictResult = requireNonEmpty(opts.verdict, "--verdict", sessionId, note);
|
|
191
|
+
if (!verdictResult.ok)
|
|
192
|
+
return verdictResult.result;
|
|
193
|
+
const verdict = verdictResult.value;
|
|
194
|
+
const branchResult = resolveRequiredBranch(cwd, opts.branch, sessionId, note);
|
|
195
|
+
if (!branchResult.ok)
|
|
196
|
+
return branchResult.result;
|
|
197
|
+
const branch = branchResult.branch;
|
|
198
|
+
const summary = typeof opts.summary === "string" ? opts.summary.trim() : "";
|
|
199
|
+
const content = `review-subagent:${task} review-subagent:${branch} verdict:${verdict}${summary.length > 0 ? ` — ${summary}` : ""}`;
|
|
200
|
+
return finishRecordWrite(opts, sessionId, branch, LEDGER_SOURCE_REVIEW_SUBAGENT, content, note);
|
|
201
|
+
}
|
|
202
|
+
export async function runRecordDogfood(opts) {
|
|
203
|
+
const { note, sessionId } = initRecordVerb(opts, "dogfood");
|
|
204
|
+
const summaryResult = requireNonEmpty(opts.summary, "summary", sessionId, note);
|
|
205
|
+
if (!summaryResult.ok)
|
|
206
|
+
return summaryResult.result;
|
|
207
|
+
const summary = summaryResult.value;
|
|
208
|
+
const content = `dogfood:${sessionId} — ${summary}`;
|
|
209
|
+
return finishRecordWrite(opts, sessionId, "", LEDGER_SOURCE_DOGFOOD, content, note);
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/record/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -35,6 +35,13 @@ export interface SessionStartPreflightOptions extends LoaderOptions {
|
|
|
35
35
|
ledgerTimeoutMs?: number;
|
|
36
36
|
/** Inject the preflight runner (tests). */
|
|
37
37
|
runPreflight?: (cwd: string, timeoutMs: number) => Promise<RunPreflightResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Directory the not-ready diagnostic JSON is persisted to (task
|
|
40
|
+
* T-001). Test seam — production defaults to `~/.harness/logs`
|
|
41
|
+
* (`os.homedir()`-based). Always pass a tmp dir in tests so nothing
|
|
42
|
+
* ever touches the operator's real `~/.harness/logs/`.
|
|
43
|
+
*/
|
|
44
|
+
logDir?: string;
|
|
38
45
|
/** Inject the ledger writer (tests). */
|
|
39
46
|
writeLedger?: (args: {
|
|
40
47
|
sessionId: string;
|