@lannguyensi/harness 0.51.0 → 0.53.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 (95) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/dist/cli/approve/understanding.d.ts +46 -0
  3. package/dist/cli/approve/understanding.js +50 -22
  4. package/dist/cli/approve/understanding.js.map +1 -1
  5. package/dist/cli/audit.d.ts +29 -0
  6. package/dist/cli/audit.js +130 -17
  7. package/dist/cli/audit.js.map +1 -1
  8. package/dist/cli/delegate/index.d.ts +63 -0
  9. package/dist/cli/delegate/index.js +313 -0
  10. package/dist/cli/delegate/index.js.map +1 -0
  11. package/dist/cli/doctor/auto-approve-mode.d.ts +37 -0
  12. package/dist/cli/doctor/auto-approve-mode.js +80 -0
  13. package/dist/cli/doctor/auto-approve-mode.js.map +1 -0
  14. package/dist/cli/doctor/bypass-without-auto-approve.d.ts +38 -0
  15. package/dist/cli/doctor/bypass-without-auto-approve.js +89 -0
  16. package/dist/cli/doctor/bypass-without-auto-approve.js.map +1 -0
  17. package/dist/cli/doctor/codex-config-drift.d.ts +28 -0
  18. package/dist/cli/doctor/codex-config-drift.js +240 -0
  19. package/dist/cli/doctor/codex-config-drift.js.map +1 -0
  20. package/dist/cli/doctor/format.js +39 -1
  21. package/dist/cli/doctor/format.js.map +1 -1
  22. package/dist/cli/doctor/index.js +68 -7
  23. package/dist/cli/doctor/index.js.map +1 -1
  24. package/dist/cli/doctor/settings-drift.d.ts +6 -0
  25. package/dist/cli/doctor/settings-drift.js +20 -6
  26. package/dist/cli/doctor/settings-drift.js.map +1 -1
  27. package/dist/cli/doctor/types.d.ts +54 -0
  28. package/dist/cli/doctor/types.js.map +1 -1
  29. package/dist/cli/doctor/ug-auto-approvals.js +18 -43
  30. package/dist/cli/doctor/ug-auto-approvals.js.map +1 -1
  31. package/dist/cli/doctor/ug-delegations.d.ts +26 -0
  32. package/dist/cli/doctor/ug-delegations.js +112 -0
  33. package/dist/cli/doctor/ug-delegations.js.map +1 -0
  34. package/dist/cli/doctor/understanding-mode-env.d.ts +2 -0
  35. package/dist/cli/doctor/understanding-mode-env.js +5 -2
  36. package/dist/cli/doctor/understanding-mode-env.js.map +1 -1
  37. package/dist/cli/gc/index.d.ts +13 -2
  38. package/dist/cli/gc/index.js +203 -1
  39. package/dist/cli/gc/index.js.map +1 -1
  40. package/dist/cli/index.js +133 -7
  41. package/dist/cli/index.js.map +1 -1
  42. package/dist/cli/init/composer.js +9 -0
  43. package/dist/cli/init/composer.js.map +1 -1
  44. package/dist/cli/init/profiles.d.ts +2 -2
  45. package/dist/cli/init/profiles.js +11 -0
  46. package/dist/cli/init/profiles.js.map +1 -1
  47. package/dist/cli/init/templates.d.ts +1 -1
  48. package/dist/cli/init/templates.js +11 -0
  49. package/dist/cli/init/templates.js.map +1 -1
  50. package/dist/cli/pack/approve-escape.js +16 -7
  51. package/dist/cli/pack/approve-escape.js.map +1 -1
  52. package/dist/cli/pack/auto-approve-path.d.ts +17 -0
  53. package/dist/cli/pack/auto-approve-path.js +56 -3
  54. package/dist/cli/pack/auto-approve-path.js.map +1 -1
  55. package/dist/cli/pack/hook-pre-tool-use.d.ts +25 -0
  56. package/dist/cli/pack/hook-pre-tool-use.js +335 -3
  57. package/dist/cli/pack/hook-pre-tool-use.js.map +1 -1
  58. package/dist/cli/pack/index.d.ts +1 -0
  59. package/dist/cli/pack/index.js +1 -0
  60. package/dist/cli/pack/index.js.map +1 -1
  61. package/dist/cli/pack/transcript-report-scan.d.ts +71 -0
  62. package/dist/cli/pack/transcript-report-scan.js +359 -0
  63. package/dist/cli/pack/transcript-report-scan.js.map +1 -0
  64. package/dist/cli/pack/upgrade.d.ts +32 -0
  65. package/dist/cli/pack/upgrade.js +273 -0
  66. package/dist/cli/pack/upgrade.js.map +1 -0
  67. package/dist/cli/smoke/index.d.ts +18 -1
  68. package/dist/cli/smoke/index.js +54 -0
  69. package/dist/cli/smoke/index.js.map +1 -1
  70. package/dist/io/read-json-dir-entries.d.ts +36 -0
  71. package/dist/io/read-json-dir-entries.js +38 -0
  72. package/dist/io/read-json-dir-entries.js.map +1 -0
  73. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.d.ts +35 -0
  74. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js +86 -0
  75. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve-default.js.map +1 -0
  76. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.d.ts +76 -2
  77. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js +139 -2
  78. package/dist/policy-packs/builtin/understanding-before-execution/auto-approve.js.map +1 -1
  79. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.d.ts +237 -0
  80. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js +647 -0
  81. package/dist/policy-packs/builtin/understanding-before-execution/delegation-markers.js.map +1 -0
  82. package/dist/policy-packs/builtin/understanding-before-execution/index.d.ts +4 -1
  83. package/dist/policy-packs/builtin/understanding-before-execution/index.js +26 -1
  84. package/dist/policy-packs/builtin/understanding-before-execution/index.js.map +1 -1
  85. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.d.ts +71 -0
  86. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js +169 -0
  87. package/dist/policy-packs/builtin/understanding-before-execution/permission-mode-observations.js.map +1 -0
  88. package/dist/policy-packs/builtin/understanding-before-execution.d.ts +19 -0
  89. package/dist/policy-packs/builtin/understanding-before-execution.js +29 -0
  90. package/dist/policy-packs/builtin/understanding-before-execution.js.map +1 -1
  91. package/dist/runtime/approval-signing.js +28 -0
  92. package/dist/runtime/approval-signing.js.map +1 -1
  93. package/dist/runtime/git-context.js +7 -1
  94. package/dist/runtime/git-context.js.map +1 -1
  95. package/package.json +1 -1
@@ -0,0 +1,359 @@
1
+ // Session-scoped, role-aware transcript scan for the child's own
2
+ // Understanding Report: slice 3 of
3
+ // docs/decisions/2026-08-27-ug-auto-mode-approval.md ("Report capture
4
+ // under `-p`", agent-tasks 37ad0b05).
5
+ //
6
+ // WHY THIS EXISTS. Under `claude -p` there is no operator to run
7
+ // `harness approve understanding`, and the Stop hook fires only at the
8
+ // end of the run, so neither channel can supply key two (the child's own
9
+ // report) at the instant the first gated tool call is decided. The
10
+ // session transcript is the remaining channel, and it LAGS: at the
11
+ // PreToolUse instant the report the agent just emitted is not in the
12
+ // JSONL yet; it lands tens of milliseconds later (measured, see
13
+ // `docs/okf/understanding-gate-auto-mode-signals.md` and
14
+ // `dogfood/ug-auto-mode-signals/`). This module is the bounded poll the
15
+ // ADR chose over a lone block-and-retry: it waits for the flush itself,
16
+ // for at most `auto_approve.report_scan.max_wait`, and then gives up.
17
+ //
18
+ // FAIL CLOSED. There is no branch here that turns an absent report into
19
+ // anything but `found: false`. The caller blocks on that; the timeout is
20
+ // a block, never an allow.
21
+ //
22
+ // WHAT IT WILL NOT DO, AND WHY EACH REFUSAL IS LOAD-BEARING:
23
+ //
24
+ // - It opens exactly ONE file, the `transcript_path` the payload names,
25
+ // and never a directory. A directory scan could reach another
26
+ // session's transcript, and (per the ADR's subagent measurement) the
27
+ // separate `agent-<agent_id>.jsonl` a subagent's turns live in.
28
+ // - Only `type: "assistant"` entries count. A report the agent quoted
29
+ // back inside a user message is the PROMPT's text, not the model's
30
+ // own report, and adopting it would let the launcher's prompt supply
31
+ // key two.
32
+ // - Only entries whose own `sessionId` equals the session being decided
33
+ // count. The payload names the file, but a file can hold entries from
34
+ // more than one session id (a resumed / forked transcript), and an
35
+ // entry stamped with a foreign id is not this session's report.
36
+ // - `isSidechain: true` entries are excluded. The measured shape never
37
+ // puts one in the payload's own transcript (subagent turns live in a
38
+ // separate file), so this is defence in depth against a shape the
39
+ // measurement did not produce, not the mechanism the separation
40
+ // relies on.
41
+ // - EACH TRANSCRIPT ENTRY IS ADOPTED AT MOST ONCE PER SESSION: the
42
+ // caller passes the entry ids it has already spent (`adopted`) and
43
+ // this scan returns the newest NON-adopted hit, so one report cannot
44
+ // mint a second marker after the first one expired or a task boundary
45
+ // cleared it. Without that rule the delegation's TTL would silently
46
+ // replace the marker's, which is the lifetime the ADR's two-key
47
+ // design deliberately keeps short.
48
+ //
49
+ // HOW IT READS. The first poll reads the whole file; every later poll
50
+ // reads only the bytes appended since the previous one, carrying a
51
+ // partial trailing line over, and keeps the best hit found so far. A
52
+ // transcript that SHRANK between polls (truncated or replaced by a
53
+ // shorter file), or whose underlying file identity changed (inode/device,
54
+ // from `fs.fstatSync`, even when the new file is the same size or LARGER,
55
+ // as in a rename swapping in a different file in place), resets the
56
+ // reader and it is re-read from the top. Size alone cannot catch the
57
+ // second case: a same-size-or-larger replacement passes the size check
58
+ // but its bytes at the old offset are not a continuation of anything
59
+ // this reader has seen.
60
+ //
61
+ // The clock and the sleep are injected so the tests drive the poll
62
+ // deterministically and never sleep for real.
63
+ import * as fs from "node:fs";
64
+ import { sha256Hex } from "../../runtime/approval-signing.js";
65
+ /**
66
+ * The report heading the scan looks for, anchored to a whole line.
67
+ *
68
+ * ANY heading level, `#` through `######`: the deny text the child is
69
+ * given (`renderReportSchemaHint`) says "any heading level (#, ##, ###)"
70
+ * and shows a `##` example, so a scan that accepted only `#` would refuse
71
+ * exactly the shape its own instruction asked for.
72
+ *
73
+ * Deliberately `[ \t]` rather than `\s` around the words: `\s` matches
74
+ * newlines, so `^#\s*Understanding Report\s*$` under the `m` flag would
75
+ * also match a bare `#` on one line followed by the words on the next,
76
+ * which is not a heading. Case-insensitive on the words themselves (an
77
+ * agent that writes `# UNDERSTANDING REPORT` has still emitted the
78
+ * section the deny text asked for); a trailing `\r` is tolerated for a
79
+ * CRLF-written transcript.
80
+ */
81
+ const REPORT_HEADING = /^#{1,6}[ \t]*understanding[ \t]+report[ \t]*\r?$/i;
82
+ /**
83
+ * The text blocks of one entry's `message.content`, in order. A string
84
+ * `content` counts as exactly one text block; in the array shape only
85
+ * `{ type: "text", text: <string> }` blocks contribute, so `tool_use` and
86
+ * `thinking` blocks are ignored (a report the model only ever "thought"
87
+ * is not a report it emitted).
88
+ */
89
+ function textBlocksOf(entry) {
90
+ const message = entry.message;
91
+ if (message === null || typeof message !== "object" || Array.isArray(message))
92
+ return [];
93
+ const content = message.content;
94
+ if (typeof content === "string")
95
+ return [content];
96
+ if (!Array.isArray(content))
97
+ return [];
98
+ const blocks = [];
99
+ for (const block of content) {
100
+ if (block === null || typeof block !== "object" || Array.isArray(block))
101
+ continue;
102
+ const b = block;
103
+ if (b.type !== "text")
104
+ continue;
105
+ if (typeof b.text !== "string")
106
+ continue;
107
+ blocks.push(b.text);
108
+ }
109
+ return blocks;
110
+ }
111
+ /** The report markdown inside one text block, or null when it carries no heading. */
112
+ function reportInBlock(block) {
113
+ const lines = block.split("\n");
114
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
115
+ if (REPORT_HEADING.test(lines[i])) {
116
+ return lines.slice(i).join("\n");
117
+ }
118
+ }
119
+ return null;
120
+ }
121
+ /** Longest `uuid` accepted verbatim as an adoption id; anything longer falls back to the digest. */
122
+ const ENTRY_UUID_MAX_LENGTH = 200;
123
+ /**
124
+ * Stable identity of one adopted entry. The transcript's own `uuid` is
125
+ * preferred (Claude Code stamps one on every entry, and it survives the
126
+ * file being rewritten or resumed); a value that is missing, empty,
127
+ * over-long, or carries a line break (all of which would corrupt the
128
+ * caller's one-id-per-line ledger) falls back to a digest of the adopted
129
+ * markdown plus its line index. The two forms are namespaced so a crafted
130
+ * `uuid` cannot impersonate a digest id.
131
+ */
132
+ function entryIdFor(entry, markdown, lineIndex) {
133
+ const uuid = entry.uuid;
134
+ if (typeof uuid === "string" &&
135
+ uuid.length > 0 &&
136
+ uuid.length <= ENTRY_UUID_MAX_LENGTH &&
137
+ !/[\r\n]/.test(uuid)) {
138
+ return `uuid:${uuid}`;
139
+ }
140
+ return `sha256:${sha256Hex(`${lineIndex}\n${markdown}`)}`;
141
+ }
142
+ /**
143
+ * The eligible report on ONE JSONL line, or null. Unparseable and blank
144
+ * lines yield null rather than aborting the scan: a transcript being
145
+ * written while it is read can end in a half-flushed line, and refusing
146
+ * the whole file for that would turn a routine race into a block.
147
+ */
148
+ function reportHitInLine(line, lineIndex, sessionId) {
149
+ const trimmed = line.trim();
150
+ if (trimmed.length === 0)
151
+ return null;
152
+ let entry;
153
+ try {
154
+ entry = JSON.parse(trimmed);
155
+ }
156
+ catch {
157
+ return null;
158
+ }
159
+ if (entry === null || typeof entry !== "object" || Array.isArray(entry))
160
+ return null;
161
+ if (entry.type !== "assistant")
162
+ return null;
163
+ if (entry.isSidechain === true)
164
+ return null;
165
+ if (entry.sessionId !== sessionId)
166
+ return null;
167
+ const blocks = textBlocksOf(entry);
168
+ for (let b = blocks.length - 1; b >= 0; b -= 1) {
169
+ const markdown = reportInBlock(blocks[b]);
170
+ if (markdown !== null) {
171
+ return { markdown, lineIndex, entryId: entryIdFor(entry, markdown, lineIndex) };
172
+ }
173
+ }
174
+ return null;
175
+ }
176
+ const DEFAULT_POLL_MS = 50;
177
+ const NEWLINE = 0x0a;
178
+ const CLOSING_BRACE = 0x7d;
179
+ const EMPTY_ADOPTED = new Set();
180
+ function newScanState() {
181
+ return {
182
+ offset: 0,
183
+ carry: Buffer.alloc(0),
184
+ lineIndex: 0,
185
+ best: null,
186
+ tentative: null,
187
+ adoptedSkipped: false,
188
+ ino: null,
189
+ dev: null,
190
+ };
191
+ }
192
+ /** A hit the caller may still take: skips (and records) an already-adopted one. */
193
+ function eligible(hit, adopted, state) {
194
+ if (hit === null)
195
+ return null;
196
+ if (adopted.has(hit.entryId)) {
197
+ state.adoptedSkipped = true;
198
+ return null;
199
+ }
200
+ return hit;
201
+ }
202
+ /** Read `length` bytes from `offset`, tolerating a short `readSync`. */
203
+ function readAt(fd, offset, length) {
204
+ const buf = Buffer.allocUnsafe(length);
205
+ let read = 0;
206
+ while (read < length) {
207
+ const n = fs.readSync(fd, buf, read, length - read, offset + read);
208
+ if (n <= 0)
209
+ break;
210
+ read += n;
211
+ }
212
+ return read === length ? buf : buf.subarray(0, read);
213
+ }
214
+ /**
215
+ * The trailing, newline-less bytes as a PROVISIONAL hit for this poll
216
+ * only. A writer that has flushed a complete JSONL entry but not yet its
217
+ * newline is the one case the append-only reader would otherwise miss
218
+ * until the next flush, and the whole-file reader this replaced did see
219
+ * it. Only attempted when the carry ends in `}`, which both keeps the
220
+ * cost off every poll's partial line and guarantees the decoded bytes end
221
+ * on a character boundary.
222
+ */
223
+ function scanCarry(state, sessionId, adopted) {
224
+ const carry = state.carry;
225
+ if (carry.length === 0 || carry[carry.length - 1] !== CLOSING_BRACE)
226
+ return;
227
+ state.tentative = eligible(reportHitInLine(carry.toString("utf8"), state.lineIndex, sessionId), adopted, state);
228
+ }
229
+ /**
230
+ * Consume everything appended to the transcript since the previous poll,
231
+ * updating `state` in place.
232
+ *
233
+ * ENOENT is "not there YET": under `-p` the hook can fire before the
234
+ * transcript file exists, and it may appear inside the bound. Every other
235
+ * failure, and anything at that path that is not a regular file, means
236
+ * something IS there and cannot be read as a transcript, which is a
237
+ * distinct, immediately-reported condition rather than something waiting
238
+ * will fix.
239
+ */
240
+ function pollTranscript(transcriptPath, state, sessionId, adopted) {
241
+ // Provisional only for the poll that produced it: a file that vanished
242
+ // (or shrank) between polls must not leave a hit behind.
243
+ state.tentative = null;
244
+ let fd;
245
+ try {
246
+ fd = fs.openSync(transcriptPath, "r");
247
+ }
248
+ catch (err) {
249
+ if (err.code === "ENOENT")
250
+ return "absent";
251
+ return "unreadable";
252
+ }
253
+ try {
254
+ const stat = fs.fstatSync(fd);
255
+ if (!stat.isFile())
256
+ return "unreadable";
257
+ // Identity change: the file at this path was replaced (rename, or a
258
+ // recreate) between polls. Checked BEFORE the size comparison and
259
+ // independently of it, because a replacement can be the same size or
260
+ // larger, which the size check alone would read straight through as
261
+ // ordinary growth.
262
+ const identityChanged = state.ino !== null && (stat.ino !== state.ino || stat.dev !== state.dev);
263
+ if (identityChanged || stat.size < state.offset) {
264
+ // The file shrank, or was replaced in place: truncated, or a
265
+ // different file now sits at this path. The bytes the offset
266
+ // pointed past are stale (shrink) or belong to a different file
267
+ // entirely (identity change), so start over from the top.
268
+ Object.assign(state, newScanState());
269
+ }
270
+ state.ino = stat.ino;
271
+ state.dev = stat.dev;
272
+ if (stat.size > state.offset) {
273
+ const chunk = readAt(fd, state.offset, stat.size - state.offset);
274
+ state.offset += chunk.length;
275
+ const data = state.carry.length > 0 ? Buffer.concat([state.carry, chunk]) : chunk;
276
+ let start = 0;
277
+ for (;;) {
278
+ const nl = data.indexOf(NEWLINE, start);
279
+ if (nl === -1)
280
+ break;
281
+ const hit = eligible(reportHitInLine(data.subarray(start, nl).toString("utf8"), state.lineIndex, sessionId), adopted, state);
282
+ if (hit !== null)
283
+ state.best = hit;
284
+ state.lineIndex += 1;
285
+ start = nl + 1;
286
+ }
287
+ state.carry = start < data.length ? Buffer.from(data.subarray(start)) : Buffer.alloc(0);
288
+ }
289
+ scanCarry(state, sessionId, adopted);
290
+ return "ok";
291
+ }
292
+ catch {
293
+ return "unreadable";
294
+ }
295
+ finally {
296
+ fs.closeSync(fd);
297
+ }
298
+ }
299
+ function defaultSleep(ms) {
300
+ return new Promise((resolve) => {
301
+ setTimeout(resolve, ms);
302
+ });
303
+ }
304
+ /**
305
+ * Poll the payload's own transcript for this session's Understanding
306
+ * Report until it appears or `maxWaitMs` elapses. See the module header
307
+ * for the filters and why each one is there.
308
+ *
309
+ * The poll timer is deliberately NOT `unref`'d. A hook process whose
310
+ * stdin has been drained has no other ref'd handle, so an unref'd timer
311
+ * lets Node exit mid-poll: the process would end with an empty stdout,
312
+ * which Claude Code reads as ALLOW: a silent fail-open on precisely the
313
+ * delegation path this scan exists for. The loop is bounded twice over
314
+ * (`maxWaitMs`, itself capped by the config's 5 s ceiling, and the
315
+ * `maxPolls` count below), so it can never hold the process open beyond
316
+ * the bound.
317
+ */
318
+ export async function scanTranscriptForReport(args) {
319
+ const now = args.now ?? (() => Date.now());
320
+ const sleep = args.sleep ?? defaultSleep;
321
+ const pollMs = args.pollMs !== undefined && args.pollMs > 0 ? args.pollMs : DEFAULT_POLL_MS;
322
+ const maxWaitMs = Number.isFinite(args.maxWaitMs) && args.maxWaitMs > 0 ? args.maxWaitMs : 0;
323
+ const adopted = args.adopted ?? EMPTY_ADOPTED;
324
+ const start = now();
325
+ // Belt and braces against a clock that does not advance (an injected
326
+ // one that forgets to, a suspended VM): the poll count is bounded on
327
+ // its own, so this can never become an unbounded loop inside a hook.
328
+ // Generous enough that it never pre-empts the real time bound.
329
+ const maxPolls = Math.ceil(maxWaitMs / pollMs) + 2;
330
+ const state = newScanState();
331
+ for (let poll = 0;; poll += 1) {
332
+ const outcome = pollTranscript(args.transcriptPath, state, args.sessionId, adopted);
333
+ if (outcome === "unreadable") {
334
+ return { found: false, reason: "unreadable", waitedMs: now() - start };
335
+ }
336
+ // The provisional trailing-line hit is newer than any complete one.
337
+ const hit = state.tentative ?? state.best;
338
+ if (hit !== null) {
339
+ return {
340
+ found: true,
341
+ markdown: hit.markdown,
342
+ lineIndex: hit.lineIndex,
343
+ entryId: hit.entryId,
344
+ waitedMs: now() - start,
345
+ };
346
+ }
347
+ const elapsed = now() - start;
348
+ if (elapsed >= maxWaitMs || poll >= maxPolls) {
349
+ return {
350
+ found: false,
351
+ reason: "timeout",
352
+ ...(state.adoptedSkipped ? { adoptedOnly: true } : {}),
353
+ waitedMs: elapsed,
354
+ };
355
+ }
356
+ await sleep(pollMs);
357
+ }
358
+ }
359
+ //# sourceMappingURL=transcript-report-scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-report-scan.js","sourceRoot":"","sources":["../../../src/cli/pack/transcript-report-scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /** Pack names this verb knows how to upgrade. Grows as more upgrades ship. */
2
+ export type PackUpgradeName = "understanding-before-execution";
3
+ export interface PackUpgradeOptions {
4
+ configPath?: string;
5
+ homeDir?: string;
6
+ dryRun?: boolean;
7
+ }
8
+ export interface PackUpgradeResult {
9
+ path: string;
10
+ name: string;
11
+ diff: string;
12
+ /** True when the manifest was actually written. */
13
+ applied: boolean;
14
+ /** True when the block was already present: a byte-identical no-op. */
15
+ alreadyPresent: boolean;
16
+ }
17
+ export type ApplyAutoApproveUpgradeResult = {
18
+ ok: true;
19
+ text: string;
20
+ changed: boolean;
21
+ } | {
22
+ ok: false;
23
+ error: string;
24
+ };
25
+ export declare function applyAutoApproveUpgrade(original: string): ApplyAutoApproveUpgradeResult;
26
+ /**
27
+ * `harness pack upgrade <name>` implementation. `name` is validated
28
+ * against the (currently one-entry) set of known upgrades before any
29
+ * file I/O; an unknown name refuses with `EX_FAIL` rather than silently
30
+ * doing nothing.
31
+ */
32
+ export declare function packUpgrade(name: string, opts?: PackUpgradeOptions): Promise<PackUpgradeResult>;