opencode-swarm 7.200.9 → 7.200.11

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 (119) hide show
  1. package/.opencode/skills/ci-fix-monitor/SKILL.md +49 -0
  2. package/.opencode/skills/swarm-pr-review/references/lane-output-recoverability.md +11 -2
  3. package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
  4. package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
  5. package/dist/background/completion-observer.d.ts +2 -1
  6. package/dist/background/pending-delegations.d.ts +9 -1
  7. package/dist/background/pr-review-contract.d.ts +8 -0
  8. package/dist/cli/{attest-task-79gp34gf.js → attest-task-y0n69zgb.js} +78 -76
  9. package/dist/cli/{auto-checkpoint-kt9mr7ma.js → auto-checkpoint-hyaksmtg.js} +12 -12
  10. package/dist/cli/{capability-probe-dwqn2609.js → capability-probe-qjndmx6z.js} +1 -1
  11. package/dist/cli/{checkpoint-e7t1zbz2.js → checkpoint-t0p781sc.js} +23 -23
  12. package/dist/cli/{coder-settlement-rehndcey.js → coder-settlement-nh88s6es.js} +14 -13
  13. package/dist/cli/{config-doctor-hcemxnra.js → config-doctor-sf7hc0q4.js} +19 -19
  14. package/dist/cli/{core-k8mvhsty.js → core-p168fw3r.js} +6 -3
  15. package/dist/cli/{curation-policy-gy868ec3.js → curation-policy-1a23ftnv.js} +6 -6
  16. package/dist/cli/{curator-ayenbz0y.js → curator-5ayzhk7v.js} +53 -52
  17. package/dist/cli/{curator-drift-fwzrv9tw.js → curator-drift-jx9kyndc.js} +10 -10
  18. package/dist/cli/curator-llm-factory-ytfkvtxs.js +83 -0
  19. package/dist/cli/{doctor-knowledge-receipt-phase-id-jdy6651j.js → doctor-knowledge-receipt-phase-id-2gjvxndy.js} +10 -10
  20. package/dist/cli/{evidence-summary-service-4jm1hd1r.js → evidence-summary-service-972sqht5.js} +26 -25
  21. package/dist/cli/{gate-evidence-anef2bqv.js → gate-evidence-n1m842gj.js} +10 -9
  22. package/dist/cli/guardrail-explain-6yv78gmk.js +84 -0
  23. package/dist/cli/{guardrail-log-pv3bq9hj.js → guardrail-log-z5pzgkcv.js} +8 -8
  24. package/dist/cli/{guardrail-reset-k8b9yrec.js → guardrail-reset-w0nxcs6a.js} +53 -52
  25. package/dist/cli/{hive-promoter-zqscx6pb.js → hive-promoter-3q0738xg.js} +53 -52
  26. package/dist/cli/{index-4krkevgc.js → index-001tkp0j.js} +1 -1
  27. package/dist/cli/{index-zy943kpp.js → index-0an54fza.js} +18 -13
  28. package/dist/cli/{index-czsx86m5.js → index-0g0x9ets.js} +53 -52
  29. package/dist/cli/{index-rdyfrdcp.js → index-2n7a184b.js} +201 -33
  30. package/dist/cli/{index-4fr3r8k5.js → index-2vj8d8te.js} +1 -1
  31. package/dist/cli/{index-hhq5f82z.js → index-5k88v1e7.js} +81 -36
  32. package/dist/cli/{index-c2k7q723.js → index-6cppzd9c.js} +1 -1
  33. package/dist/cli/{index-yyrnkc3a.js → index-6m551cng.js} +2 -2
  34. package/dist/cli/{index-y16v2q1x.js → index-814q5t5s.js} +5 -5
  35. package/dist/cli/{index-08jd4gz2.js → index-8g9rn3rp.js} +121 -40
  36. package/dist/cli/{index-8srvdpw6.js → index-8xtdxy91.js} +2 -2
  37. package/dist/cli/{index-mn75z39t.js → index-9qy3tzt5.js} +1 -1
  38. package/dist/cli/{index-6q2s7r67.js → index-aj41bscz.js} +8 -8
  39. package/dist/cli/{index-2c4hjeea.js → index-bnbhqvsn.js} +8 -8
  40. package/dist/cli/{index-9jty56xr.js → index-bv9tqmpm.js} +5 -5
  41. package/dist/cli/{index-casbh4y7.js → index-ce6qarfq.js} +13032 -12437
  42. package/dist/cli/{index-y7c4hqcj.js → index-ck7jpn0y.js} +1 -1
  43. package/dist/cli/{index-p2dst45x.js → index-ckq78kq1.js} +1 -1
  44. package/dist/cli/{index-8mrentmw.js → index-dp6hy23p.js} +58 -53
  45. package/dist/cli/{index-4fkxdnc7.js → index-erp7fk72.js} +1 -1
  46. package/dist/cli/{index-qawbxp81.js → index-gkvk9et2.js} +17 -17
  47. package/dist/cli/{index-kxp43wbw.js → index-h1chaf63.js} +29 -29
  48. package/dist/cli/{index-4ya4krts.js → index-hhzwfyd7.js} +611 -1376
  49. package/dist/cli/{index-x3rxa3sh.js → index-jt9j02tm.js} +6 -6
  50. package/dist/cli/{index-tecp3a77.js → index-kd1n3ne2.js} +9 -9
  51. package/dist/cli/{index-ss8nfrbb.js → index-ke881z7m.js} +15 -15
  52. package/dist/cli/{index-9ws7m02r.js → index-krjamprc.js} +2 -2
  53. package/dist/cli/{index-f8nb470m.js → index-kzr3nby8.js} +4 -4
  54. package/dist/cli/{index-02vgzrpg.js → index-mq4eyhtf.js} +7 -7
  55. package/dist/cli/{index-4tpzdegx.js → index-njg8zvqe.js} +7 -7
  56. package/dist/cli/{index-hh87yny7.js → index-nnc23ddw.js} +6 -6
  57. package/dist/cli/{index-7c4gckzq.js → index-nzhfhpng.js} +5 -5
  58. package/dist/cli/{index-q8vfw61p.js → index-pjrx4jkq.js} +1 -1
  59. package/dist/cli/{index-xhxbv7mz.js → index-qdz6zysj.js} +11 -11
  60. package/dist/cli/{index-mhd6kdzr.js → index-qyj4383m.js} +1 -1
  61. package/dist/cli/index-r097ettz.js +1330 -0
  62. package/dist/cli/{index-tvdn9gr0.js → index-ra3erqpk.js} +15 -15
  63. package/dist/cli/{index-2x015vjy.js → index-rck7v4r4.js} +1 -1
  64. package/dist/cli/{index-vtpt8yns.js → index-rjsqf4hv.js} +2 -2
  65. package/dist/cli/{index-bk8r4m9j.js → index-rpvp88js.js} +2 -2
  66. package/dist/cli/{index-2k5348b6.js → index-ssp4t8g6.js} +58 -57
  67. package/dist/cli/{index-v839c9mv.js → index-tggyracy.js} +1 -1
  68. package/dist/cli/{index-hzy6n59p.js → index-ve74c3a8.js} +6 -6
  69. package/dist/cli/{index-4ph7ad0b.js → index-vx1j2t5p.js} +2 -2
  70. package/dist/cli/{index-7h22y3ew.js → index-w0afnznk.js} +2 -2
  71. package/dist/cli/{index-xh50xsgf.js → index-x8sh8v4a.js} +8 -8
  72. package/dist/cli/{index-6901y99d.js → index-xht6gprr.js} +35 -22
  73. package/dist/cli/{index-qw2wfz92.js → index-yn6jrxen.js} +18 -20
  74. package/dist/cli/{index-94s844qn.js → index-yq73sd3w.js} +4 -4
  75. package/dist/cli/index.js +57 -56
  76. package/dist/cli/{knowledge-escalator-m4b4q218.js → knowledge-escalator-2e92rdsx.js} +18 -18
  77. package/dist/cli/{knowledge-events-wwg0cc7m.js → knowledge-events-gzqwr94e.js} +15 -15
  78. package/dist/cli/{knowledge-link-13t3nfrz.js → knowledge-link-r7e2t5c1.js} +5 -5
  79. package/dist/cli/{knowledge-store-07fwtdzy.js → knowledge-store-6j8d1gm4.js} +7 -7
  80. package/dist/cli/{knowledge-validator-8492vmn3.js → knowledge-validator-wt2tcfg7.js} +9 -9
  81. package/dist/cli/{mcp-b1wyrebx.js → mcp-ky6xn6ys.js} +1 -1
  82. package/dist/cli/{model-preflight-315wr8nt.js → model-preflight-ajt55s59.js} +56 -55
  83. package/dist/cli/{pending-delegations-tpa7wpny.js → pending-delegations-wry31649.js} +14 -14
  84. package/dist/cli/{pr-subscriptions-ev2bkbrz.js → pr-subscriptions-dsdjbfr4.js} +13 -13
  85. package/dist/cli/{pr-workflow-gate-3cg64r61.js → pr-workflow-gate-0vcq1m95.js} +53 -52
  86. package/dist/cli/{runner-q1g9atrv.js → runner-s4422dq4.js} +6 -6
  87. package/dist/cli/{scan-cursor-3pfx6mbh.js → scan-cursor-1zgrg7kp.js} +8 -8
  88. package/dist/cli/{schema-km0fywpx.js → schema-q9xbwkec.js} +2 -2
  89. package/dist/cli/{scope-persistence-xctbs0aj.js → scope-persistence-4wwmytwh.js} +18 -18
  90. package/dist/cli/{server-d1mcxa8s.js → server-q8ydxk7z.js} +79 -69
  91. package/dist/cli/{skill-generator-tce30v8g.js → skill-generator-b1eqcxej.js} +20 -20
  92. package/dist/cli/{snapshot-coordination-init-t7vfaqhw.js → snapshot-coordination-init-0yva5015.js} +53 -52
  93. package/dist/cli/{speckit-checkoff-tcn1dqt0.js → speckit-checkoff-sh9w7j5b.js} +5 -5
  94. package/dist/cli/{telemetry-cr8q16wk.js → telemetry-j7zr1dht.js} +1 -1
  95. package/dist/cli/workflow-wal-file-a2c8e920.js +32 -0
  96. package/dist/cli/{workspace-snapshot-7hws89e9.js → workspace-snapshot-ksdspd74.js} +3 -3
  97. package/dist/cli/{worktree-collision-ownership-5jb0p5aa.js → worktree-collision-ownership-xr6crt8c.js} +15 -15
  98. package/dist/cli/{worktree-isolation-cxg8fgba.js → worktree-isolation-0126b5e7.js} +53 -52
  99. package/dist/hooks/delegation-gate/worktree-isolation.d.ts +3 -0
  100. package/dist/hooks/delegation-gate.d.ts +6 -0
  101. package/dist/hooks/guardrails/audit-log.d.ts +2 -0
  102. package/dist/hooks/guardrails/cmd-delete-grammar.d.ts +47 -0
  103. package/dist/hooks/guardrails/destructive-command.d.ts +11 -3
  104. package/dist/hooks/guardrails/shell-audit-store.d.ts +2 -0
  105. package/dist/hooks/guardrails/tool-before.d.ts +16 -0
  106. package/dist/hooks/shell-write-detect.d.ts +10 -0
  107. package/dist/index.js +689 -687
  108. package/dist/memory/redaction.d.ts +13 -3
  109. package/dist/pr-review/legacy-transcript-adapter.d.ts +15 -4
  110. package/dist/sandbox/macos/sandbox-exec-executor.d.ts +24 -0
  111. package/dist/workflow/coder-settlement.d.ts +5 -0
  112. package/dist/worktree/core.d.ts +3 -0
  113. package/dist/worktree/merge.d.ts +15 -1
  114. package/dist/worktree/ownership.d.ts +3 -0
  115. package/dist/worktree/settlement-artifact-lifecycle.d.ts +32 -0
  116. package/dist/worktree/settlement-source-recovery.d.ts +12 -0
  117. package/package.json +1 -1
  118. package/dist/cli/curator-llm-factory-kja1c81k.js +0 -82
  119. package/dist/cli/guardrail-explain-agaet7r5.js +0 -83
@@ -1,35 +1,22 @@
1
1
  // @bun
2
2
  import {
3
+ assertSettlementArtifactsRemovable,
3
4
  autoCommitDirty,
4
- cleanUntrackedFiles
5
- } from "./index-rdyfrdcp.js";
5
+ cleanUntrackedFiles,
6
+ withSettlementArtifactLifecycle
7
+ } from "./index-2n7a184b.js";
6
8
  import {
7
9
  isSpawnCwdMissing,
8
10
  isSpawnCwdUnreadable
9
11
  } from "./index-spggmr30.js";
10
- import {
11
- validateSwarmPath
12
- } from "./index-4krkevgc.js";
13
- import {
14
- derivePlanId,
15
- derivePlanIdentityHash
16
- } from "./index-7pmbnjvj.js";
17
12
  import {
18
13
  init_path_identity,
19
14
  isPathWithinDeclaredScope,
20
15
  unsafePathTextReason
21
16
  } from "./index-9rwhas09.js";
22
17
  import {
23
- atomicWriteFile,
24
- taskEvidencePath,
25
- withTaskEvidenceLock
26
- } from "./index-yyrnkc3a.js";
27
- import {
28
- assertProjectRoot
29
- } from "./index-t7hmqgjy.js";
30
- import {
31
- telemetry
32
- } from "./index-c2k7q723.js";
18
+ atomicWriteFile
19
+ } from "./index-6m551cng.js";
33
20
  import {
34
21
  advisoryWarn,
35
22
  init_git_executable,
@@ -43,368 +30,9 @@ import {
43
30
  import {
44
31
  log
45
32
  } from "./index-zgwm4ryv.js";
46
- import {
47
- exports_external,
48
- init_zod
49
- } from "./index-gknz3bv1.js";
50
-
51
- // src/gate-evidence.ts
52
- init_zod();
53
- import { createHash as createHash2 } from "crypto";
54
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
55
- import * as path4 from "path";
56
-
57
- // src/evidence/task-gate-requirements.ts
58
- init_zod();
59
- import { createHash } from "crypto";
60
- import * as fs from "fs";
61
- import * as path from "path";
62
- var MAX_TASK_GATE_REQUIREMENTS_BYTES = 256 * 1024;
63
- var TaskGateRequirementsReceiptSchema = exports_external.object({
64
- schemaVersion: exports_external.literal(1),
65
- taskId: exports_external.string().min(1).max(120),
66
- generation: exports_external.number().int().min(0),
67
- normalizedRole: exports_external.string().min(1).max(120),
68
- testEngineerExempt: exports_external.boolean().nullable(),
69
- requiredGates: exports_external.array(exports_external.string()).min(1).max(16),
70
- sourceEvent: exports_external.string().min(1).max(120),
71
- sourceTransitionId: exports_external.string().min(1).max(200).nullable(),
72
- recordedAt: exports_external.string().min(1).max(128),
73
- routeBinding: exports_external.object({
74
- role: exports_external.enum(["reviewer", "test_engineer"]),
75
- identity: exports_external.string().trim().min(1).max(256),
76
- sessionId: exports_external.string().trim().min(1).max(256),
77
- taskId: exports_external.string().trim().min(1).max(120),
78
- slotId: exports_external.string().trim().min(1).max(256),
79
- callId: exports_external.string().trim().min(1).max(256),
80
- childSessionId: exports_external.string().trim().min(1).max(256),
81
- generation: exports_external.number().int().nonnegative()
82
- }).strict().optional(),
83
- previousChainHash: exports_external.string().regex(/^[a-f0-9]{64}$/).nullable(),
84
- chainHash: exports_external.string().regex(/^[a-f0-9]{64}$/)
85
- }).strict();
86
- function samePath(left, right) {
87
- const normalize = (value) => process.platform === "win32" ? path.resolve(value).toLowerCase() : path.resolve(value);
88
- return normalize(left) === normalize(right);
89
- }
90
- function assertSafeRequirementsParent(directory, create) {
91
- assertProjectRoot(directory, undefined, "task gate requirements");
92
- const rootStat = fs.lstatSync(directory);
93
- if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
94
- throw new Error("TASK_GATE_REQUIREMENTS_UNREADABLE: project root is not a regular directory");
95
- }
96
- const canonicalRoot = fs.realpathSync(directory);
97
- const segments = [".swarm", "evidence", "task-gate-requirements"];
98
- let current = canonicalRoot;
99
- for (const segment of segments) {
100
- current = path.join(current, segment);
101
- let info;
102
- try {
103
- info = fs.lstatSync(current);
104
- } catch (error) {
105
- if (error.code === "ENOENT") {
106
- if (!create)
107
- return current;
108
- try {
109
- fs.mkdirSync(current);
110
- } catch (mkdirError) {
111
- if (mkdirError.code !== "EEXIST") {
112
- throw mkdirError;
113
- }
114
- }
115
- info = fs.lstatSync(current);
116
- } else {
117
- throw error;
118
- }
119
- }
120
- if (info.isSymbolicLink() || !info.isDirectory()) {
121
- throw new Error("TASK_GATE_REQUIREMENTS_UNREADABLE: receipt parent is redirected or not a directory");
122
- }
123
- const canonicalCurrent = fs.realpathSync(current);
124
- if (!samePath(canonicalCurrent, current)) {
125
- throw new Error("TASK_GATE_REQUIREMENTS_UNREADABLE: receipt parent escaped the project root");
126
- }
127
- }
128
- return current;
129
- }
130
- function safeTaskGateRequirementsReceiptPath(directory, taskId, createParent) {
131
- const parent = assertSafeRequirementsParent(directory, createParent);
132
- return path.join(parent, `${taskId}.jsonl`);
133
- }
134
- function sha256(value) {
135
- return createHash("sha256").update(value).digest("hex");
136
- }
137
- function canonicalReceiptPayload(receipt) {
138
- const routeBinding = receipt.routeBinding ? {
139
- role: receipt.routeBinding.role,
140
- identity: receipt.routeBinding.identity,
141
- sessionId: receipt.routeBinding.sessionId,
142
- taskId: receipt.routeBinding.taskId,
143
- slotId: receipt.routeBinding.slotId,
144
- callId: receipt.routeBinding.callId,
145
- childSessionId: receipt.routeBinding.childSessionId,
146
- generation: receipt.routeBinding.generation
147
- } : undefined;
148
- return JSON.stringify({
149
- schemaVersion: receipt.schemaVersion,
150
- taskId: receipt.taskId,
151
- generation: receipt.generation,
152
- normalizedRole: receipt.normalizedRole,
153
- testEngineerExempt: receipt.testEngineerExempt,
154
- requiredGates: [...receipt.requiredGates],
155
- sourceEvent: receipt.sourceEvent,
156
- sourceTransitionId: receipt.sourceTransitionId,
157
- recordedAt: receipt.recordedAt,
158
- ...routeBinding ? { routeBinding } : {},
159
- previousChainHash: receipt.previousChainHash
160
- });
161
- }
162
- function computeChainHash(receipt) {
163
- return sha256(canonicalReceiptPayload(receipt));
164
- }
165
- function routeBindingFromEvent(event) {
166
- if (event.type !== "stage_b_completed" || !event.routeBinding)
167
- return;
168
- const binding = event.routeBinding;
169
- if (binding.role !== event.gate || !binding.sessionId || !binding.taskId || !binding.slotId || !binding.callId || !binding.childSessionId || typeof binding.generation !== "number") {
170
- return;
171
- }
172
- return binding;
173
- }
174
- function readBoundedTextFile(filePath) {
175
- let pathStat;
176
- try {
177
- pathStat = fs.lstatSync(filePath);
178
- } catch (error) {
179
- if (error.code === "ENOENT")
180
- return null;
181
- throw error;
182
- }
183
- if (pathStat.isSymbolicLink() || !pathStat.isFile()) {
184
- throw new Error("TASK_GATE_REQUIREMENTS_UNREADABLE: receipt path is not a regular file");
185
- }
186
- if (pathStat.size > MAX_TASK_GATE_REQUIREMENTS_BYTES) {
187
- throw new Error(`TASK_GATE_REQUIREMENTS_OVERSIZED: ${pathStat.size} bytes exceeds ${MAX_TASK_GATE_REQUIREMENTS_BYTES}`);
188
- }
189
- const descriptor = fs.openSync(filePath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
190
- try {
191
- const openedStat = fs.fstatSync(descriptor);
192
- if (!openedStat.isFile() || openedStat.dev !== pathStat.dev || openedStat.ino !== pathStat.ino) {
193
- throw new Error("TASK_GATE_REQUIREMENTS_UNREADABLE: receipt changed while being opened");
194
- }
195
- if (openedStat.size > MAX_TASK_GATE_REQUIREMENTS_BYTES) {
196
- throw new Error(`TASK_GATE_REQUIREMENTS_OVERSIZED: ${openedStat.size} bytes exceeds ${MAX_TASK_GATE_REQUIREMENTS_BYTES}`);
197
- }
198
- return fs.readFileSync(descriptor, "utf-8");
199
- } finally {
200
- fs.closeSync(descriptor);
201
- }
202
- }
203
- async function readTaskGateRequirementsReceipts(directory, taskId) {
204
- const filePath = safeTaskGateRequirementsReceiptPath(directory, taskId, false);
205
- const text = readBoundedTextFile(filePath);
206
- if (text === null)
207
- return [];
208
- const receipts = [];
209
- for (const line of text.split(`
210
- `)) {
211
- if (!line.trim())
212
- continue;
213
- const parsed = TaskGateRequirementsReceiptSchema.parse(JSON.parse(line));
214
- if (parsed.taskId !== taskId || parsed.routeBinding !== undefined && parsed.routeBinding.taskId !== taskId) {
215
- throw new Error(`TASK_GATE_REQUIREMENTS_IDENTITY_MISMATCH: expected ${taskId}, found ${parsed.taskId}`);
216
- }
217
- const { chainHash, ...withoutChainHash } = parsed;
218
- const expectedHash = computeChainHash(withoutChainHash);
219
- if (expectedHash !== chainHash) {
220
- throw new Error(`TASK_GATE_REQUIREMENTS_CHAIN_MISMATCH: receipt for ${taskId} failed hash validation`);
221
- }
222
- const previousChainHash = receipts.at(-1)?.chainHash ?? null;
223
- if (parsed.previousChainHash !== previousChainHash) {
224
- throw new Error(`TASK_GATE_REQUIREMENTS_CHAIN_MISMATCH: receipt for ${taskId} failed linkage validation`);
225
- }
226
- receipts.push(parsed);
227
- }
228
- return receipts;
229
- }
230
- function readTaskGateRequirementsReceiptsSync(directory, taskId) {
231
- const filePath = safeTaskGateRequirementsReceiptPath(directory, taskId, false);
232
- const text = readBoundedTextFile(filePath);
233
- if (text === null)
234
- return [];
235
- const receipts = [];
236
- for (const line of text.split(`
237
- `)) {
238
- if (!line.trim())
239
- continue;
240
- const parsed = TaskGateRequirementsReceiptSchema.parse(JSON.parse(line));
241
- if (parsed.taskId !== taskId || parsed.routeBinding !== undefined && parsed.routeBinding.taskId !== taskId) {
242
- throw new Error(`TASK_GATE_REQUIREMENTS_IDENTITY_MISMATCH: expected ${taskId}, found ${parsed.taskId}`);
243
- }
244
- const { chainHash, ...withoutChainHash } = parsed;
245
- if (computeChainHash(withoutChainHash) !== chainHash) {
246
- throw new Error(`TASK_GATE_REQUIREMENTS_CHAIN_MISMATCH: receipt for ${taskId} failed hash validation`);
247
- }
248
- const previousChainHash = receipts.at(-1)?.chainHash ?? null;
249
- if (parsed.previousChainHash !== previousChainHash) {
250
- throw new Error(`TASK_GATE_REQUIREMENTS_CHAIN_MISMATCH: receipt for ${taskId} failed linkage validation`);
251
- }
252
- receipts.push(parsed);
253
- }
254
- return receipts;
255
- }
256
- function routeEvidenceFromTaskGateRequirements(receipts) {
257
- const latestByDispatch = new Map;
258
- for (const receipt of receipts) {
259
- const binding = receipt.routeBinding;
260
- if (!binding)
261
- continue;
262
- const dispatchKey = [
263
- binding.role,
264
- binding.sessionId,
265
- binding.taskId,
266
- binding.callId,
267
- binding.childSessionId,
268
- String(binding.generation)
269
- ].join("\x00");
270
- latestByDispatch.set(dispatchKey, binding);
271
- }
272
- return [...latestByDispatch.values()];
273
- }
274
- function isLegacyTaskGateRequirementsChain(receipts) {
275
- return receipts.length > 0 && receipts.every((receipt) => !receipt.routeBinding);
276
- }
277
- function deriveReceiptRole(event) {
278
- switch (event.type) {
279
- case "accepted_mutation":
280
- case "dispatch_attempted":
281
- case "dispatch_no_mutation":
282
- if (typeof event.agentType === "string" && event.agentType.trim().length > 0) {
283
- return {
284
- normalizedRole: event.agentType.trim(),
285
- testEngineerExempt: event.agentType === "coder" ? event.context?.testEngineerExempt === true : null
286
- };
287
- }
288
- return null;
289
- case "stage_b_completed":
290
- case "gate_recorded":
291
- return {
292
- normalizedRole: event.gate,
293
- testEngineerExempt: null
294
- };
295
- default:
296
- return null;
297
- }
298
- }
299
- function shouldAppendReceipt(current, next, role) {
300
- if (next.required_gates.length === 0)
301
- return false;
302
- const currentGeneration = current?.workflow?.generation ?? -1;
303
- const nextGeneration = next.workflow?.generation ?? -1;
304
- if (current === null)
305
- return true;
306
- if (JSON.stringify(current.required_gates) !== JSON.stringify(next.required_gates)) {
307
- return true;
308
- }
309
- if ((current.test_engineer_exempt ?? null) !== role.testEngineerExempt) {
310
- return true;
311
- }
312
- return currentGeneration !== nextGeneration;
313
- }
314
- async function appendTaskGateRequirementsReceiptIfNeeded(directory, taskId, current, next, event) {
315
- const role = deriveReceiptRole(event);
316
- const routeBinding = routeBindingFromEvent(event);
317
- if (routeBinding && routeBinding.taskId !== taskId) {
318
- throw new Error(`TASK_GATE_REQUIREMENTS_ROUTE_IDENTITY_MISMATCH: expected ${taskId}, found ${routeBinding.taskId}`);
319
- }
320
- if (!role || !shouldAppendReceipt(current, next, role) && !routeBinding) {
321
- return;
322
- }
323
- const filePath = safeTaskGateRequirementsReceiptPath(directory, taskId, true);
324
- const receipts = await readTaskGateRequirementsReceipts(directory, taskId);
325
- const latest = receipts.at(-1);
326
- const baseReceipt = {
327
- schemaVersion: 1,
328
- taskId,
329
- generation: next.workflow?.generation ?? 0,
330
- normalizedRole: role.normalizedRole,
331
- testEngineerExempt: role.testEngineerExempt,
332
- requiredGates: [...next.required_gates],
333
- sourceEvent: event.type,
334
- sourceTransitionId: event.transitionId ?? null,
335
- recordedAt: new Date().toISOString(),
336
- previousChainHash: latest?.chainHash ?? null,
337
- ...routeBinding ? { routeBinding } : {}
338
- };
339
- const receipt = {
340
- ...baseReceipt,
341
- chainHash: computeChainHash(baseReceipt)
342
- };
343
- if (latest && latest.generation === receipt.generation && latest.normalizedRole === receipt.normalizedRole && latest.testEngineerExempt === receipt.testEngineerExempt && JSON.stringify(latest.requiredGates) === JSON.stringify(receipt.requiredGates) && latest.sourceTransitionId === receipt.sourceTransitionId && JSON.stringify(latest.routeBinding ?? null) === JSON.stringify(receipt.routeBinding ?? null)) {
344
- return;
345
- }
346
- const lines = [...receipts, receipt].map((entry) => JSON.stringify(entry));
347
- assertSafeRequirementsParent(directory, false);
348
- await atomicWriteFile(filePath, `${lines.join(`
349
- `)}
350
- `);
351
- assertSafeRequirementsParent(directory, false);
352
- }
353
-
354
- // src/validation/task-id.ts
355
- var STRICT_TASK_ID_PATTERN = /^\d+\.\d+(\.\d+)*$/;
356
- var RETRO_TASK_ID_REGEX = /^retro-\d+$/;
357
- var INTERNAL_TOOL_ID_REGEX = /^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build|secretscan)$/;
358
- var GENERAL_TASK_ID_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
359
- function checkUnsafeChars(taskId) {
360
- if (!taskId || taskId.length === 0) {
361
- return "Invalid task ID: empty string";
362
- }
363
- if (/\0/.test(taskId)) {
364
- return "Invalid task ID: contains null bytes";
365
- }
366
- for (let i = 0;i < taskId.length; i++) {
367
- if (taskId.charCodeAt(i) < 32) {
368
- return "Invalid task ID: contains control characters";
369
- }
370
- }
371
- if (taskId.includes("..") || taskId.includes("/") || taskId.includes("\\")) {
372
- return "Invalid task ID: path traversal detected";
373
- }
374
- return;
375
- }
376
- function isStrictTaskId(taskId) {
377
- if (!taskId)
378
- return false;
379
- const unsafeMsg = checkUnsafeChars(taskId);
380
- if (unsafeMsg)
381
- return false;
382
- return STRICT_TASK_ID_PATTERN.test(taskId);
383
- }
384
- function assertStrictTaskId(taskId) {
385
- if (!isStrictTaskId(taskId)) {
386
- throw new Error(`Invalid taskId: "${taskId}". Must match N.M or N.M.P (e.g. "1.1", "1.2.3").`);
387
- }
388
- }
389
- function sanitizeTaskId(taskId) {
390
- const unsafeMsg = checkUnsafeChars(taskId);
391
- if (unsafeMsg) {
392
- throw new Error(unsafeMsg);
393
- }
394
- if (STRICT_TASK_ID_PATTERN.test(taskId) || RETRO_TASK_ID_REGEX.test(taskId) || INTERNAL_TOOL_ID_REGEX.test(taskId) || GENERAL_TASK_ID_REGEX.test(taskId)) {
395
- return taskId;
396
- }
397
- throw new Error(`Invalid task ID: must be alphanumeric (ASCII) with optional hyphens, underscores, or dots, got "${taskId}"`);
398
- }
399
- function validateTaskIdFormat(taskId) {
400
- if (!STRICT_TASK_ID_PATTERN.test(taskId)) {
401
- return `Invalid taskId "${taskId}". Must match pattern N.M or N.M.P (e.g., "1.1", "1.2.3")`;
402
- }
403
- return;
404
- }
405
33
 
406
34
  // src/workflow/workflow-wal-file.ts
407
- import * as fs4 from "fs";
35
+ import * as fs3 from "fs";
408
36
  import { mkdir, open } from "fs/promises";
409
37
  import { dirname } from "path";
410
38
 
@@ -413,15 +41,15 @@ init_path_identity();
413
41
 
414
42
  // src/worktree/merge.ts
415
43
  init_warning_buffer();
416
- import * as fs3 from "fs";
44
+ import * as fs2 from "fs";
417
45
  import * as path3 from "path";
418
46
 
419
47
  // src/turbo/lean/recovery.ts
420
- import * as fs2 from "fs";
421
- import * as path2 from "path";
48
+ import * as fs from "fs";
49
+ import * as path from "path";
422
50
  var RECOVERY_DIR_NAME = "recovery";
423
51
  function recoveryDir(directory) {
424
- return path2.join(directory, ".swarm", RECOVERY_DIR_NAME);
52
+ return path.join(directory, ".swarm", RECOVERY_DIR_NAME);
425
53
  }
426
54
  function isRecoveryRecord(value) {
427
55
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
@@ -435,11 +63,11 @@ function readRecoveryRecords(directory) {
435
63
  const dir = recoveryDir(directory);
436
64
  let entries;
437
65
  try {
438
- entries = fs2.readdirSync(dir, { withFileTypes: true });
66
+ entries = fs.readdirSync(dir, { withFileTypes: true });
439
67
  } catch {
440
68
  return {
441
69
  records: [],
442
- errored: fs2.existsSync(dir)
70
+ errored: fs.existsSync(dir)
443
71
  };
444
72
  }
445
73
  const records = [];
@@ -447,9 +75,9 @@ function readRecoveryRecords(directory) {
447
75
  for (const entry of entries) {
448
76
  if (!entry.isFile() || !entry.name.endsWith(".json"))
449
77
  continue;
450
- const full = path2.join(dir, entry.name);
78
+ const full = path.join(dir, entry.name);
451
79
  try {
452
- const parsed = JSON.parse(fs2.readFileSync(full, "utf-8"));
80
+ const parsed = JSON.parse(fs.readFileSync(full, "utf-8"));
453
81
  if (isRecoveryRecord(parsed)) {
454
82
  records.push(parsed);
455
83
  } else {
@@ -475,7 +103,169 @@ function recoveryReadErrored(directory) {
475
103
  // src/worktree/merge.ts
476
104
  init_bun_compat();
477
105
  init_git_executable();
478
- var _internals = {
106
+
107
+ // src/worktree/settlement-source-recovery.ts
108
+ init_bun_compat();
109
+ init_git_executable();
110
+ import { stat } from "fs/promises";
111
+ import * as path2 from "path";
112
+ var _internals = { bunSpawn, resolveGitExecutable };
113
+ var OID = /^[0-9a-f]{40}$|^[0-9a-f]{64}$/;
114
+ var REPO_REDIRECT_ENV = new Set([
115
+ "GIT_DIR",
116
+ "GIT_WORK_TREE",
117
+ "GIT_INDEX_FILE",
118
+ "GIT_COMMON_DIR",
119
+ "GIT_OBJECT_DIRECTORY",
120
+ "GIT_ALTERNATE_OBJECT_DIRECTORIES",
121
+ "GIT_NAMESPACE"
122
+ ]);
123
+ function gitEnvWithoutRepoRedirectors() {
124
+ const env = {};
125
+ for (const [key, value] of Object.entries(process.env)) {
126
+ if (!REPO_REDIRECT_ENV.has(key.toUpperCase()))
127
+ env[key] = value;
128
+ }
129
+ env.LC_ALL = "C";
130
+ return env;
131
+ }
132
+ async function git(directory, args) {
133
+ let proc;
134
+ try {
135
+ proc = _internals.bunSpawn([_internals.resolveGitExecutable(), ...args], {
136
+ cwd: directory,
137
+ stdin: "ignore",
138
+ stdout: "pipe",
139
+ stderr: "pipe",
140
+ timeout: 1e4,
141
+ maxBuffer: 65536,
142
+ env: gitEnvWithoutRepoRedirectors()
143
+ });
144
+ if (proc.spawnError)
145
+ throw proc.spawnError;
146
+ const [exitCode, stdout, stderr] = await Promise.all([
147
+ proc.exited,
148
+ proc.stdout.text(),
149
+ proc.stderr.text()
150
+ ]);
151
+ if (proc.spawnError)
152
+ throw proc.spawnError;
153
+ return { exitCode, stdout, stderr };
154
+ } finally {
155
+ try {
156
+ proc?.kill();
157
+ } catch {}
158
+ }
159
+ }
160
+ function requireOid(oid) {
161
+ if (!OID.test(oid))
162
+ throw new Error("CODER_SETTLEMENT_SOURCE_UNCERTAIN: malformed source OID");
163
+ }
164
+ async function probeSettlementSource(directory, oid) {
165
+ requireOid(oid);
166
+ const result = await git(directory, [
167
+ "rev-parse",
168
+ "--verify",
169
+ "--quiet",
170
+ `${oid}^{commit}`
171
+ ]);
172
+ if (result.exitCode === 0 && result.stdout.trim() === oid)
173
+ return "present";
174
+ if (result.exitCode === 1 && !result.stderr.trim() && !result.stdout.trim()) {
175
+ const objects = await git(directory, [
176
+ "rev-parse",
177
+ "--git-path",
178
+ "objects"
179
+ ]);
180
+ const objectsPath = objects.exitCode === 0 ? objects.stdout.trim() : "";
181
+ const objectsUsable = objectsPath !== "" && await stat(path2.resolve(directory, objectsPath)).then((entry) => entry.isDirectory(), () => false);
182
+ if (!objectsUsable) {
183
+ throw new Error(`CODER_SETTLEMENT_SOURCE_UNCERTAIN: object database unavailable for ${oid}`);
184
+ }
185
+ const health = await git(directory, ["count-objects", "-v"]);
186
+ if (health.exitCode !== 0 || health.stderr.trim())
187
+ throw new Error(`CODER_SETTLEMENT_SOURCE_UNCERTAIN: object database unreadable for ${oid}`);
188
+ return "absent";
189
+ }
190
+ throw new Error(`CODER_SETTLEMENT_SOURCE_UNCERTAIN: ${oid}: ${result.stderr.trim() || "Git object probe failed"}`);
191
+ }
192
+ function settlementBackupRef(oid) {
193
+ requireOid(oid);
194
+ return `refs/swarm/coder-settlements/${oid}`;
195
+ }
196
+ async function readDirectRef(directory, ref) {
197
+ const symbolic = await git(directory, ["symbolic-ref", "-q", ref]);
198
+ if (symbolic.exitCode !== 1)
199
+ throw new Error(`CODER_SETTLEMENT_REF_UNCERTAIN: symbolic or unreadable ref ${ref}`);
200
+ const result = await git(directory, [
201
+ "rev-parse",
202
+ "--verify",
203
+ "--quiet",
204
+ ref
205
+ ]);
206
+ if (result.exitCode === 0 && OID.test(result.stdout.trim()))
207
+ return result.stdout.trim();
208
+ if (result.exitCode === 1 && !result.stderr.trim() && !result.stdout.trim())
209
+ return null;
210
+ throw new Error(`CODER_SETTLEMENT_REF_UNCERTAIN: ${ref}`);
211
+ }
212
+ async function createExactRef(directory, ref, oid) {
213
+ requireOid(oid);
214
+ const current = await readDirectRef(directory, ref);
215
+ if (current === oid)
216
+ return false;
217
+ if (current !== null)
218
+ throw new Error(`RECOVERABLE_ORPHAN_COMMIT: ${oid}; occupied ref ${ref}`);
219
+ const result = await git(directory, [
220
+ "update-ref",
221
+ "--no-deref",
222
+ ref,
223
+ oid,
224
+ "0".repeat(oid.length)
225
+ ]);
226
+ if (await readDirectRef(directory, ref) !== oid)
227
+ throw new Error(`RECOVERABLE_ORPHAN_COMMIT: ${oid}; cannot preserve ${ref}: ${result.stderr.trim()}`);
228
+ return true;
229
+ }
230
+ async function preserveSettlementSource(directory, oid) {
231
+ const ref = settlementBackupRef(oid);
232
+ await createExactRef(directory, ref, oid);
233
+ return ref;
234
+ }
235
+ async function restoreSettlementBranch(directory, branch, oid) {
236
+ const ref = `refs/heads/${branch}`;
237
+ const valid = await git(directory, ["check-ref-format", ref]);
238
+ if (valid.exitCode !== 0)
239
+ throw new Error("CODER_SETTLEMENT_REF_UNCERTAIN: malformed lane branch");
240
+ return createExactRef(directory, ref, oid);
241
+ }
242
+ async function releaseSettlementSource(directory, oid) {
243
+ const ref = settlementBackupRef(oid);
244
+ const current = await readDirectRef(directory, ref);
245
+ if (current === null)
246
+ return;
247
+ if (current !== oid)
248
+ throw new Error(`CODER_SETTLEMENT_REF_UNCERTAIN: occupied backup ${ref}`);
249
+ await git(directory, ["update-ref", "--no-deref", "-d", ref, oid]);
250
+ if (await readDirectRef(directory, ref) !== null)
251
+ throw new Error(`CODER_SETTLEMENT_REF_UNCERTAIN: cannot release ${ref}`);
252
+ }
253
+ async function validateSettlementLane(directory, branchName, expectedHead) {
254
+ requireOid(expectedHead);
255
+ if ((await git(directory, ["check-ref-format", `refs/heads/${branchName}`])).exitCode !== 0)
256
+ throw new Error("CODER_SETTLEMENT_DISPATCH_ARTIFACT_CHANGED: invalid branch");
257
+ const [branch, head] = await Promise.all([
258
+ git(directory, ["symbolic-ref", "--short", "HEAD"]),
259
+ git(directory, ["rev-parse", "--verify", "HEAD"])
260
+ ]);
261
+ if (branch.exitCode !== 0 || branch.stdout.trim() !== branchName || head.exitCode !== 0 || head.stdout.trim() !== expectedHead)
262
+ throw new Error("CODER_SETTLEMENT_DISPATCH_ARTIFACT_CHANGED: lane branch or HEAD changed");
263
+ }
264
+
265
+ // src/worktree/merge.ts
266
+ var _internals2 = {
267
+ withSettlementArtifactLifecycle,
268
+ assertSettlementArtifactsRemovable,
479
269
  bunSpawn,
480
270
  platform: process.platform,
481
271
  sleep: (ms) => new Promise((resolve3) => setTimeout(resolve3, ms)),
@@ -513,7 +303,7 @@ function gitSpawnFailureResult(error, cwd, args) {
513
303
  async function runGit(args, cwd, timeoutMs = MERGE_TIMEOUT_MS) {
514
304
  let proc;
515
305
  try {
516
- proc = _internals.bunSpawn([_internals.resolveGitExecutable(), ...args], {
306
+ proc = _internals2.bunSpawn([_internals2.resolveGitExecutable(), ...args], {
517
307
  cwd,
518
308
  timeout: timeoutMs,
519
309
  stdin: "ignore",
@@ -587,7 +377,7 @@ async function matchesSourceHeadWorkingTree(primaryDir, sourceHead) {
587
377
  return { landed: false };
588
378
  if (status === "A") {
589
379
  const worktreePath = path3.join(primaryDir, filePath);
590
- if (!fs3.existsSync(worktreePath))
380
+ if (!fs2.existsSync(worktreePath))
591
381
  return { landed: false };
592
382
  const expected = await runGit(["rev-parse", `${sourceHead}:${filePath}`], primaryDir);
593
383
  const actual = await runGit(["hash-object", "--", filePath], primaryDir);
@@ -654,13 +444,13 @@ async function detectInProgressOperation(primaryDir) {
654
444
  if (!rawPath)
655
445
  continue;
656
446
  const markerPath = path3.isAbsolute(rawPath) ? rawPath : path3.resolve(primaryDir, rawPath);
657
- if (fs3.existsSync(markerPath))
447
+ if (fs2.existsSync(markerPath))
658
448
  return { inProgress: true };
659
449
  }
660
450
  return { inProgress: false };
661
451
  }
662
452
  function currentPathCasePolicy() {
663
- return _internals.platform === "win32" ? "insensitive" : "sensitive";
453
+ return _internals2.platform === "win32" ? "insensitive" : "sensitive";
664
454
  }
665
455
  function normalizeGitPath(rawPath, casePolicy) {
666
456
  if (rawPath.includes("\x00")) {
@@ -890,6 +680,258 @@ function sameOverlapSnapshot(left, right) {
890
680
  function getMergeStrategy(config) {
891
681
  return config.mergeStrategy ?? config.merge_strategy ?? "merge";
892
682
  }
683
+ var FINGERPRINT_BATCH = 200;
684
+ var FINGERPRINT_ARG_BUDGET = 24000;
685
+ async function hashWorktreeFiles(primaryDir, files) {
686
+ const hashed = await runGit(["hash-object", "--", ...files], primaryDir);
687
+ if (hashed.exitCode !== 0)
688
+ return `hash-object: ${hashed.stderr.trim() || hashed.stdout.trim() || `git exited ${hashed.exitCode}`}`;
689
+ const oids = hashed.stdout.split(/\r?\n/).filter(Boolean);
690
+ return oids.length === files.length ? oids : "hash-object: unexpected output length";
691
+ }
692
+ async function fingerprintWorktreePaths(primaryDir, paths, tolerant = false) {
693
+ const fingerprints = new Map;
694
+ const regular = [];
695
+ for (const p of paths) {
696
+ let stat2;
697
+ try {
698
+ stat2 = fs2.lstatSync(path3.join(primaryDir, p));
699
+ } catch (error) {
700
+ const code = error.code;
701
+ if (code === "ENOENT" || code === "ENOTDIR") {
702
+ fingerprints.set(p, "absent");
703
+ continue;
704
+ }
705
+ if (!tolerant)
706
+ return `worktree stat for ${p}: ${error.message}`;
707
+ fingerprints.set(p, "unreadable");
708
+ continue;
709
+ }
710
+ if (stat2.isFile())
711
+ regular.push(p);
712
+ else
713
+ fingerprints.set(p, "other");
714
+ }
715
+ const batches = [];
716
+ let batch = [];
717
+ let length = 0;
718
+ for (const p of regular) {
719
+ if (batch.length > 0 && (batch.length >= FINGERPRINT_BATCH || length + p.length + 1 > FINGERPRINT_ARG_BUDGET)) {
720
+ batches.push(batch);
721
+ batch = [];
722
+ length = 0;
723
+ }
724
+ batch.push(p);
725
+ length += p.length + 1;
726
+ }
727
+ if (batch.length > 0)
728
+ batches.push(batch);
729
+ for (const current of batches) {
730
+ const oids = await hashWorktreeFiles(primaryDir, current);
731
+ if (typeof oids !== "string") {
732
+ for (const [index, p] of current.entries())
733
+ fingerprints.set(p, oids[index]);
734
+ continue;
735
+ }
736
+ if (!tolerant)
737
+ return oids;
738
+ for (const p of current) {
739
+ const single = await hashWorktreeFiles(primaryDir, [p]);
740
+ fingerprints.set(p, typeof single === "string" ? "unreadable" : single[0]);
741
+ }
742
+ }
743
+ return fingerprints;
744
+ }
745
+ function unmergedIndexPaths(index) {
746
+ const unmerged = new Set;
747
+ for (const [name, records] of index) {
748
+ if (records.split(`
749
+ `).some((record) => !record.endsWith(" 0")))
750
+ unmerged.add(name);
751
+ }
752
+ return unmerged;
753
+ }
754
+ async function takeSquashStateSnapshot(primaryDir, incomingPaths) {
755
+ const describe = (result, operation) => `${operation}: ${result.stderr.trim() || result.stdout.trim() || `git exited ${result.exitCode}`}`;
756
+ const listing = await runGit(["ls-files", "-s", "-z"], primaryDir);
757
+ if (listing.exitCode !== 0)
758
+ return describe(listing, "index listing");
759
+ const index = new Map;
760
+ for (const record of listing.stdout.split("\x00")) {
761
+ const tab = record.indexOf("\t");
762
+ if (tab < 0)
763
+ continue;
764
+ const name = record.slice(tab + 1);
765
+ const entry = record.slice(0, tab);
766
+ index.set(name, index.has(name) ? `${index.get(name)}
767
+ ${entry}` : entry);
768
+ }
769
+ const worktree = await fingerprintWorktreePaths(primaryDir, incomingPaths);
770
+ if (typeof worktree === "string")
771
+ return worktree;
772
+ const differing = await runGit(["diff", "--name-only", "--no-renames", "-z", "HEAD"], primaryDir);
773
+ if (differing.exitCode !== 0)
774
+ return describe(differing, "HEAD diff listing");
775
+ const flagged = await runGit(["ls-files", "-v", "-z"], primaryDir);
776
+ if (flagged.exitCode !== 0)
777
+ return describe(flagged, "index tag listing");
778
+ const incoming = new Set(incomingPaths);
779
+ const outside = new Set;
780
+ for (const name of differing.stdout.split("\x00")) {
781
+ if (name !== "" && !incoming.has(name))
782
+ outside.add(name);
783
+ }
784
+ for (const record of flagged.stdout.split("\x00")) {
785
+ if (!/^[a-z] /.test(record))
786
+ continue;
787
+ const name = record.slice(2);
788
+ if (!incoming.has(name))
789
+ outside.add(name);
790
+ }
791
+ const dirty = await fingerprintWorktreePaths(primaryDir, [...outside], true);
792
+ if (typeof dirty === "string")
793
+ return dirty;
794
+ return { index, worktree, dirty };
795
+ }
796
+ async function restoreFailedSquashPaths(primaryDir, branchName, incomingPaths, before) {
797
+ const describe = (result, operation) => `${operation}: ${result.stderr.trim() || result.stdout.trim() || `git exited ${result.exitCode}`}`;
798
+ const after = await takeSquashStateSnapshot(primaryDir, incomingPaths);
799
+ if (typeof after === "string")
800
+ return after;
801
+ const incoming = new Set(incomingPaths);
802
+ const reported = [];
803
+ const indexChanged = new Set;
804
+ const indexNames = new Set([...before.index.keys(), ...after.index.keys()]);
805
+ for (const name of indexNames) {
806
+ if (incoming.has(name))
807
+ continue;
808
+ if (before.index.get(name) !== after.index.get(name)) {
809
+ reported.push(`changed outside the incoming paths: ${name}`);
810
+ indexChanged.add(name);
811
+ }
812
+ }
813
+ const headListing = await runGit(["--literal-pathspecs", "ls-tree", "-z", "HEAD", "--", ...incomingPaths], primaryDir);
814
+ if (headListing.exitCode !== 0)
815
+ return describe(headListing, "HEAD listing");
816
+ const headTypes = new Map;
817
+ for (const record of headListing.stdout.split("\x00")) {
818
+ const tab = record.indexOf("\t");
819
+ if (tab < 0)
820
+ continue;
821
+ const [, type] = record.slice(0, tab).split(" ");
822
+ headTypes.set(record.slice(tab + 1), type);
823
+ }
824
+ const laneListing = await runGit([
825
+ "--literal-pathspecs",
826
+ "ls-tree",
827
+ "-z",
828
+ branchName,
829
+ "--",
830
+ ...incomingPaths
831
+ ], primaryDir);
832
+ const laneBlobs = new Map;
833
+ if (laneListing.exitCode !== 0)
834
+ reported.push(describe(laneListing, "lane listing"));
835
+ const laneRecords = laneListing.exitCode === 0 ? laneListing.stdout.split("\x00") : [];
836
+ for (const record of laneRecords) {
837
+ const tab = record.indexOf("\t");
838
+ if (tab < 0)
839
+ continue;
840
+ const [mode, type, oid] = record.slice(0, tab).split(" ");
841
+ if (type === "blob" && mode !== "120000" && oid)
842
+ laneBlobs.set(record.slice(tab + 1), oid);
843
+ }
844
+ const changed = [];
845
+ for (const p of incomingPaths) {
846
+ if (before.index.get(p) !== after.index.get(p)) {
847
+ changed.push(p);
848
+ continue;
849
+ }
850
+ if (before.worktree.get(p) === after.worktree.get(p))
851
+ continue;
852
+ if (headTypes.get(p) !== "blob") {
853
+ changed.push(p);
854
+ continue;
855
+ }
856
+ const state = after.worktree.get(p);
857
+ if (state === "absent" || state !== "other" && state === laneBlobs.get(p)) {
858
+ changed.push(p);
859
+ } else {
860
+ reported.push(`left in place (working tree changed without an index change): ${p}`);
861
+ }
862
+ }
863
+ if (changed.length > 0) {
864
+ const trackedBlobs = changed.filter((p) => headTypes.get(p) === "blob");
865
+ const absentFromHead = changed.filter((p) => !headTypes.has(p));
866
+ for (const p of changed) {
867
+ const type = headTypes.get(p);
868
+ if (type !== undefined && type !== "blob")
869
+ reported.push(`not restored (directory or submodule in HEAD): ${p}`);
870
+ }
871
+ const restorable = [...trackedBlobs, ...absentFromHead];
872
+ if (restorable.length > 0) {
873
+ const reset = await runGit(["--literal-pathspecs", "reset", "-q", "HEAD", "--", ...restorable], primaryDir);
874
+ if (reset.exitCode !== 0)
875
+ return describe(reset, "index reset");
876
+ }
877
+ if (trackedBlobs.length > 0) {
878
+ const checkout = await runGit([
879
+ "--literal-pathspecs",
880
+ "checkout",
881
+ "-q",
882
+ "HEAD",
883
+ "--",
884
+ ...trackedBlobs
885
+ ], primaryDir);
886
+ if (checkout.exitCode !== 0)
887
+ return describe(checkout, "checkout");
888
+ }
889
+ const candidates = [];
890
+ for (const p of absentFromHead) {
891
+ const state = after.worktree.get(p);
892
+ if (state === "other")
893
+ reported.push(`left in place (not a regular file): ${p}`);
894
+ else if (state !== "absent")
895
+ candidates.push(p);
896
+ }
897
+ for (const p of candidates) {
898
+ if (laneBlobs.get(p) !== after.worktree.get(p)) {
899
+ reported.push(`left in place (not the exact lane bytes): ${p}`);
900
+ continue;
901
+ }
902
+ const current = await runGit(["hash-object", "--", p], primaryDir);
903
+ if (current.exitCode !== 0 || current.stdout.trim() !== laneBlobs.get(p)) {
904
+ reported.push(`left in place (changed since it was checked): ${p}`);
905
+ continue;
906
+ }
907
+ try {
908
+ fs2.unlinkSync(path3.join(primaryDir, p));
909
+ } catch (error) {
910
+ if (error.code !== "ENOENT")
911
+ reported.push(`could not remove ${p}: ${error.message}`);
912
+ }
913
+ }
914
+ }
915
+ const dirtyNames = new Set([...before.dirty.keys(), ...after.dirty.keys()]);
916
+ for (const name of dirtyNames) {
917
+ if (!indexChanged.has(name) && before.dirty.get(name) !== after.dirty.get(name))
918
+ reported.push(`working tree outside the incoming paths changed during the failed squash: ${name}`);
919
+ }
920
+ const remaining = await runGit(["ls-files", "-u", "-z"], primaryDir);
921
+ if (remaining.exitCode !== 0)
922
+ return describe(remaining, "unmerged listing after restore");
923
+ const unmergedBefore = unmergedIndexPaths(before.index);
924
+ for (const record of remaining.stdout.split("\x00")) {
925
+ const tab = record.indexOf("\t");
926
+ if (tab < 0)
927
+ continue;
928
+ const name = record.slice(tab + 1);
929
+ if (!unmergedBefore.has(name))
930
+ reported.push(`unmerged: ${name}`);
931
+ }
932
+ const unique = [...new Set(reported)];
933
+ return unique.length === 0 ? null : `not restored: ${unique.join("; ")}`;
934
+ }
893
935
  async function mergeLaneBranch(primaryDir, branchName, strategy, commitMessage) {
894
936
  let result;
895
937
  switch (strategy) {
@@ -933,26 +975,33 @@ async function mergeLaneBranch(primaryDir, branchName, strategy, commitMessage)
933
975
  };
934
976
  }
935
977
  const incomingPaths = [...parsedIncoming.paths.values()];
978
+ const squashSnapshot = await takeSquashStateSnapshot(primaryDir, incomingPaths);
979
+ if (typeof squashSnapshot === "string") {
980
+ return {
981
+ error: `could not record pre-merge state before squash of ${branchName}: ${squashSnapshot}`
982
+ };
983
+ }
936
984
  const squashResult = await runGit(["merge", "--squash", "--no-commit", branchName], primaryDir);
937
985
  if (squashResult.exitCode !== 0) {
938
986
  const combined = `${squashResult.stderr}
939
987
  ${squashResult.stdout}`;
940
- const restore = await runGit(["checkout", "-q", "HEAD", "--", ...incomingPaths], primaryDir);
988
+ const restoreFailure = await restoreFailedSquashPaths(primaryDir, branchName, incomingPaths, squashSnapshot);
989
+ if (restoreFailure !== null) {
990
+ advisoryWarn(`[worktree] mergeLaneBranch: squash merge failed and targeted restore also failed for ${branchName}: ${restoreFailure}`);
991
+ }
992
+ const restoreSuffix = restoreFailure === null ? "" : `; restore of pre-merge state incomplete, partial merge state may remain: ${restoreFailure}`;
941
993
  if (/CONFLICT/i.test(combined)) {
942
994
  return {
943
995
  conflict: true,
944
996
  files: parseConflictFiles(combined),
945
- message: squashResult.stderr.trim() || squashResult.stdout.trim() || "squash merge reported a conflict"
997
+ message: `${squashResult.stderr.trim() || squashResult.stdout.trim() || "squash merge reported a conflict"}${restoreSuffix}`
946
998
  };
947
999
  }
948
- if (restore.exitCode !== 0) {
949
- advisoryWarn(`[worktree] mergeLaneBranch: squash merge failed and targeted restore also failed for ${branchName}: ${restore.stderr.trim() || restore.stdout.trim()}`);
950
- }
951
1000
  return {
952
- error: squashResult.stderr.trim() || squashResult.stdout.trim() || "squash merge failed"
1001
+ error: `${squashResult.stderr.trim() || squashResult.stdout.trim() || "squash merge failed"}${restoreSuffix}`
953
1002
  };
954
1003
  }
955
- const resetResult = await runGit(["reset", "-q", "HEAD", "--", ...incomingPaths], primaryDir);
1004
+ const resetResult = await runGit(["--literal-pathspecs", "reset", "-q", "HEAD", "--", ...incomingPaths], primaryDir);
956
1005
  if (resetResult.exitCode !== 0) {
957
1006
  advisoryWarn(`[worktree] mergeLaneBranch: targeted unstage failed for ${branchName} (${resetResult.stderr.trim() || resetResult.stdout.trim()}); lane changes remain staged`);
958
1007
  }
@@ -1008,7 +1057,7 @@ async function readOrderedCommitRange(primaryDir, fromExclusive, toInclusive, de
1008
1057
  }
1009
1058
  return { commits };
1010
1059
  }
1011
- async function recoverMergeBackFromImmutableCoordinates(primaryDir, coordinates) {
1060
+ async function recoverMergeBackFromImmutableCoordinates(primaryDir, coordinates, options) {
1012
1061
  if (!GIT_OBJECT_ID_PATTERN.test(coordinates.sourceBaseOid) || !GIT_OBJECT_ID_PATTERN.test(coordinates.sourceHeadOid) || !GIT_OBJECT_ID_PATTERN.test(coordinates.targetHeadOid)) {
1013
1062
  return {
1014
1063
  error: "Malformed preserved lane recovery coordinates"
@@ -1045,7 +1094,10 @@ async function recoverMergeBackFromImmutableCoordinates(primaryDir, coordinates)
1045
1094
  };
1046
1095
  }
1047
1096
  if (coordinates.strategy === "merge") {
1048
- return finalizeMergeStrategyResult(primaryDir, "merge", await runGit(["merge", "--no-edit", coordinates.sourceHeadOid], primaryDir), {});
1097
+ if (options?.landUnstaged) {
1098
+ return mergeLaneBranch(primaryDir, coordinates.sourceHeadOid, "squash-unstaged");
1099
+ }
1100
+ return mergeLaneBranch(primaryDir, coordinates.sourceHeadOid, "merge", options?.landingCommitMessage);
1049
1101
  }
1050
1102
  if (coordinates.strategy === "rebase") {
1051
1103
  return finalizeMergeStrategyResult(primaryDir, "rebase", await runGit([
@@ -1135,22 +1187,31 @@ async function reconcileLandedMerge(primaryDir, provenance) {
1135
1187
  return trailerSearch.stdout.trim() ? { landed: true, method: "cherry-pick-trailer" } : { landed: false };
1136
1188
  }
1137
1189
  async function postMergeCleanup(directory, branchName) {
1138
- const pruneResult = await runGit(["worktree", "prune"], directory);
1139
- const pruneOk = pruneResult.exitCode === 0;
1140
- const deleteResult = await runGit(["branch", "-D", branchName], directory);
1141
- const deleteOk = deleteResult.exitCode === 0;
1142
- if (deleteOk && pruneOk) {
1143
- return { cleaned: true };
1144
- }
1145
- if (!deleteOk && pruneOk) {
1146
- return {
1147
- error: `Branch delete failed: ${deleteResult.stderr.trim() || deleteResult.stdout.trim()}`,
1148
- partial: true
1149
- };
1190
+ try {
1191
+ return await _internals2.withSettlementArtifactLifecycle(directory, async () => {
1192
+ await _internals2.assertSettlementArtifactsRemovable(directory, {
1193
+ branch: branchName
1194
+ });
1195
+ const pruneResult = await runGit(["worktree", "prune"], directory);
1196
+ const pruneOk = pruneResult.exitCode === 0;
1197
+ const deleteResult = await runGit(["branch", "-D", branchName], directory);
1198
+ const deleteOk = deleteResult.exitCode === 0;
1199
+ if (deleteOk && pruneOk) {
1200
+ return { cleaned: true };
1201
+ }
1202
+ if (!deleteOk && pruneOk) {
1203
+ return {
1204
+ error: `Branch delete failed: ${deleteResult.stderr.trim() || deleteResult.stdout.trim()}`,
1205
+ partial: true
1206
+ };
1207
+ }
1208
+ return {
1209
+ error: deleteOk ? `Worktree prune failed: ${pruneResult.stderr.trim() || pruneResult.stdout.trim()}` : `Branch delete failed: ${deleteResult.stderr.trim() || deleteResult.stdout.trim()}; worktree prune failed: ${pruneResult.stderr.trim() || pruneResult.stdout.trim()}`
1210
+ };
1211
+ });
1212
+ } catch (error) {
1213
+ return { error: String(error) };
1150
1214
  }
1151
- return {
1152
- error: deleteOk ? `Worktree prune failed: ${pruneResult.stderr.trim() || pruneResult.stdout.trim()}` : `Branch delete failed: ${deleteResult.stderr.trim() || deleteResult.stdout.trim()}; worktree prune failed: ${pruneResult.stderr.trim() || pruneResult.stdout.trim()}`
1153
- };
1154
1215
  }
1155
1216
  async function pruneStaleWorktreeMetadata(directory) {
1156
1217
  const result = await runGit(["worktree", "prune"], directory);
@@ -1193,6 +1254,13 @@ async function handleSourceWorktreeGone(branchHead, worktreePath, branchName, pr
1193
1254
  advisoryWarn(`STALE_LANE_WORKTREE_DETECTED: lane worktree "${worktreePath}" no longer exists. ` + `Its stale git registration was pruned, and the merge-back for branch "${branchName}" ` + `is being taken from "${primaryDir}" instead. Any uncommitted work in that worktree is ` + "unrecoverable; every commit on the branch is preserved.");
1194
1255
  return null;
1195
1256
  }
1257
+ async function releaseVerifiedSettlementSource(primaryDir, sourceHead, context) {
1258
+ try {
1259
+ await releaseSettlementSource(primaryDir, sourceHead);
1260
+ } catch (error) {
1261
+ advisoryWarn(`[worktree] attemptMergeBackFromDirty: landing verified (${context}) but releasing preserved settlement source ${sourceHead} failed; outcome unchanged, backup ref left in place:`, error);
1262
+ }
1263
+ }
1196
1264
  async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, strategy, options = {}) {
1197
1265
  let autoCommitted = false;
1198
1266
  let cleaned = false;
@@ -1209,6 +1277,34 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
1209
1277
  provenance
1210
1278
  };
1211
1279
  }
1280
+ let orphanRestored = false;
1281
+ try {
1282
+ if (await probeSettlementSource(primaryDir, provenance.sourceHead) === "absent") {
1283
+ return {
1284
+ failed: true,
1285
+ stage: SOURCE_WORKTREE_GONE_STAGE,
1286
+ message: "Recorded source commit is absent",
1287
+ provenance
1288
+ };
1289
+ }
1290
+ } catch (error) {
1291
+ return {
1292
+ failed: true,
1293
+ stage: "reconciliation",
1294
+ message: String(error),
1295
+ provenance
1296
+ };
1297
+ }
1298
+ try {
1299
+ await preserveSettlementSource(primaryDir, provenance.sourceHead);
1300
+ } catch (error) {
1301
+ return {
1302
+ failed: true,
1303
+ stage: "reconciliation",
1304
+ message: String(error),
1305
+ provenance
1306
+ };
1307
+ }
1212
1308
  const reconciliation = await reconcileLandedMerge(primaryDir, provenance);
1213
1309
  if ("error" in reconciliation && reconciliation.error) {
1214
1310
  return {
@@ -1219,6 +1315,9 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
1219
1315
  };
1220
1316
  }
1221
1317
  if (reconciliation.landed) {
1318
+ if (reconciliation.method !== "worktree-match") {
1319
+ await releaseVerifiedSettlementSource(primaryDir, provenance.sourceHead, "resume reconciliation");
1320
+ }
1222
1321
  return {
1223
1322
  merged: true,
1224
1323
  strategy: reconciliation.method === "worktree-match" ? "squash-unstaged" : strategy,
@@ -1228,6 +1327,16 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
1228
1327
  provenance
1229
1328
  };
1230
1329
  }
1330
+ try {
1331
+ orphanRestored = await restoreSettlementBranch(primaryDir, branchName, provenance.sourceHead);
1332
+ } catch (error) {
1333
+ return {
1334
+ failed: true,
1335
+ stage: "reconciliation",
1336
+ message: String(error),
1337
+ provenance
1338
+ };
1339
+ }
1231
1340
  const source = await captureLaneSourceHead(worktreePath, branchName, primaryDir, false);
1232
1341
  if (source.sourceWorktreeMissing) {
1233
1342
  const unrecoverable = await handleSourceWorktreeGone(source.result, worktreePath, branchName, primaryDir, provenance);
@@ -1237,7 +1346,7 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
1237
1346
  }
1238
1347
  const sourceHead = source.result;
1239
1348
  const targetHead = await runGit(["rev-parse", "HEAD"], primaryDir);
1240
- if (sourceHead.exitCode !== 0 || targetHead.exitCode !== 0 || sourceHead.stdout.trim() !== provenance.sourceHead || targetHead.stdout.trim() !== provenance.targetHeadBefore) {
1349
+ if (sourceHead.exitCode !== 0 || targetHead.exitCode !== 0 || sourceHead.stdout.trim() !== provenance.sourceHead) {
1241
1350
  return {
1242
1351
  failed: true,
1243
1352
  stage: "reconciliation",
@@ -1245,6 +1354,61 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
1245
1354
  provenance
1246
1355
  };
1247
1356
  }
1357
+ if (strategy === "merge" && (orphanRestored || targetHead.stdout.trim() !== provenance.targetHeadBefore)) {
1358
+ const relation = await runGit([
1359
+ "merge-base",
1360
+ "--is-ancestor",
1361
+ provenance.targetHeadBefore,
1362
+ targetHead.stdout.trim()
1363
+ ], primaryDir);
1364
+ if (relation.exitCode !== 0)
1365
+ return {
1366
+ failed: true,
1367
+ stage: "reconciliation",
1368
+ message: "Current primary HEAD no longer descends from recorded target",
1369
+ provenance
1370
+ };
1371
+ const base = await runGit(["merge-base", targetHead.stdout.trim(), provenance.sourceHead], primaryDir);
1372
+ if (base.exitCode !== 0)
1373
+ return {
1374
+ failed: true,
1375
+ stage: "reconciliation",
1376
+ message: "Unable to derive current immutable merge base",
1377
+ provenance
1378
+ };
1379
+ const result = await recoverMergeBackFromImmutableCoordinates(primaryDir, {
1380
+ sourceBaseOid: base.stdout.trim(),
1381
+ sourceHeadOid: provenance.sourceHead,
1382
+ targetHeadOid: targetHead.stdout.trim(),
1383
+ strategy
1384
+ }, options.commitLanding ? { landingCommitMessage: options.landingCommitMessage } : { landUnstaged: true });
1385
+ if ("merged" in result) {
1386
+ if (result.strategy !== "squash-unstaged") {
1387
+ await releaseVerifiedSettlementSource(primaryDir, provenance.sourceHead, "retarget recovery");
1388
+ }
1389
+ return {
1390
+ merged: true,
1391
+ strategy: result.strategy === "squash-unstaged" ? "squash-unstaged" : strategy,
1392
+ autoCommitted: false,
1393
+ cleaned: false,
1394
+ reconciled: false,
1395
+ provenance
1396
+ };
1397
+ }
1398
+ return {
1399
+ failed: true,
1400
+ stage: "merge",
1401
+ message: "error" in result ? result.error : result.message,
1402
+ provenance
1403
+ };
1404
+ }
1405
+ if (targetHead.stdout.trim() !== provenance.targetHeadBefore)
1406
+ return {
1407
+ failed: true,
1408
+ stage: "reconciliation",
1409
+ message: "Stored merge operation target HEAD has changed",
1410
+ provenance
1411
+ };
1248
1412
  }
1249
1413
  if (!provenance && !sourceWorktreeMissing) {
1250
1414
  const commitResult = await autoCommitDirty(worktreePath);
@@ -1283,7 +1447,7 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
1283
1447
  };
1284
1448
  }
1285
1449
  }
1286
- const initialOverlapSnapshot = await _internals.captureMergeOverlapSnapshot(primaryDir, branchName);
1450
+ const initialOverlapSnapshot = await _internals2.captureMergeOverlapSnapshot(primaryDir, branchName);
1287
1451
  if ("error" in initialOverlapSnapshot) {
1288
1452
  return {
1289
1453
  failed: true,
@@ -1320,7 +1484,7 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
1320
1484
  }
1321
1485
  }
1322
1486
  }
1323
- const finalOverlapSnapshot = await _internals.captureMergeOverlapSnapshot(primaryDir, branchName);
1487
+ const finalOverlapSnapshot = await _internals2.captureMergeOverlapSnapshot(primaryDir, branchName);
1324
1488
  if ("error" in finalOverlapSnapshot) {
1325
1489
  return {
1326
1490
  failed: true,
@@ -1353,6 +1517,12 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
1353
1517
  const landingStrategy = strategy === "merge" && !options.commitLanding ? "squash-unstaged" : strategy;
1354
1518
  const mergeResult = await mergeLaneBranch(primaryDir, branchName, landingStrategy, landingStrategy === "merge" && options.commitLanding ? options.landingCommitMessage : undefined);
1355
1519
  if ("merged" in mergeResult && mergeResult.merged) {
1520
+ if (provenance && landingStrategy !== "squash-unstaged") {
1521
+ const landed = await reconcileLandedMerge(primaryDir, provenance);
1522
+ if (landed.landed && landed.method !== "worktree-match") {
1523
+ await releaseVerifiedSettlementSource(primaryDir, provenance.sourceHead, "fresh landing");
1524
+ }
1525
+ }
1356
1526
  return {
1357
1527
  merged: true,
1358
1528
  strategy: landingStrategy,
@@ -1440,7 +1610,19 @@ async function cleanupOrphanedBranches(directory, activeSessionIds = [], options
1440
1610
  skippedRecoveryBranches.push(branch);
1441
1611
  continue;
1442
1612
  }
1443
- const deleteResult = await runGit(["branch", options.preserveUnmerged ? "-d" : "-D", branch], directory);
1613
+ let deleteResult;
1614
+ try {
1615
+ deleteResult = await _internals2.withSettlementArtifactLifecycle(directory, async () => {
1616
+ await _internals2.assertSettlementArtifactsRemovable(directory, {
1617
+ branch
1618
+ });
1619
+ return runGit(["branch", options.preserveUnmerged ? "-d" : "-D", branch], directory);
1620
+ });
1621
+ } catch (error) {
1622
+ skipped.push(branch);
1623
+ errors.push({ branch, error: String(error) });
1624
+ continue;
1625
+ }
1444
1626
  if (deleteResult.exitCode === 0) {
1445
1627
  removed.push(branch);
1446
1628
  } else {
@@ -1577,11 +1759,11 @@ var UTF8_FATAL_DECODER = new TextDecoder("utf-8", { fatal: true });
1577
1759
  var CODER_SETTLEMENT_MAX_BYTES = 64 * 1024 * 1024;
1578
1760
  var SMALL_WORKFLOW_WAL_MAX_BYTES = 1024 * 1024;
1579
1761
  var CHUNK_BYTES = 64 * 1024;
1580
- var _internals2 = {
1762
+ var _internals3 = {
1581
1763
  openFile: open,
1582
- openFileSync: fs4.openSync,
1583
- readFileSync: fs4.readSync,
1584
- closeFileSync: fs4.closeSync
1764
+ openFileSync: fs3.openSync,
1765
+ readFileSync: fs3.readSync,
1766
+ closeFileSync: fs3.closeSync
1585
1767
  };
1586
1768
  function maxBytesFor(kind) {
1587
1769
  return kind === "coder-settlement" ? CODER_SETTLEMENT_MAX_BYTES : SMALL_WORKFLOW_WAL_MAX_BYTES;
@@ -1646,7 +1828,7 @@ function validateWal(kind, raw, filePath, expectedTaskId) {
1646
1828
  async function readBoundedBytes(kind, filePath, maxBytes) {
1647
1829
  let handle;
1648
1830
  try {
1649
- handle = await _internals2.openFile(filePath, "r");
1831
+ handle = await _internals3.openFile(filePath, "r");
1650
1832
  } catch (error) {
1651
1833
  if (error.code === "ENOENT")
1652
1834
  return null;
@@ -1687,7 +1869,7 @@ async function readBoundedBytes(kind, filePath, maxBytes) {
1687
1869
  function readBoundedBytesSync(kind, filePath, maxBytes) {
1688
1870
  let fd;
1689
1871
  try {
1690
- fd = _internals2.openFileSync(filePath, "r");
1872
+ fd = _internals3.openFileSync(filePath, "r");
1691
1873
  } catch (error) {
1692
1874
  if (error.code === "ENOENT")
1693
1875
  return null;
@@ -1704,7 +1886,7 @@ function readBoundedBytesSync(kind, filePath, maxBytes) {
1704
1886
  if (remaining <= 0)
1705
1887
  break;
1706
1888
  const buffer = Buffer.alloc(Math.min(CHUNK_BYTES, remaining));
1707
- const bytesRead = _internals2.readFileSync(fd, buffer, 0, buffer.length, null);
1889
+ const bytesRead = _internals3.readFileSync(fd, buffer, 0, buffer.length, null);
1708
1890
  if (bytesRead === 0)
1709
1891
  break;
1710
1892
  total += bytesRead;
@@ -1717,7 +1899,7 @@ function readBoundedBytesSync(kind, filePath, maxBytes) {
1717
1899
  failure = walIoError(kind, filePath, "read", error);
1718
1900
  }
1719
1901
  try {
1720
- _internals2.closeFileSync(fd);
1902
+ _internals3.closeFileSync(fd);
1721
1903
  } catch (error) {
1722
1904
  failure ??= walIoError(kind, filePath, "close", error);
1723
1905
  }
@@ -1761,951 +1943,4 @@ async function writeWorkflowWalFile(kind, filePath, wal) {
1761
1943
  await atomicWriteFile(filePath, serialized);
1762
1944
  }
1763
1945
 
1764
- // src/gate-evidence.ts
1765
- var _internals3 = {
1766
- appendTaskGateRequirementsReceiptIfNeeded
1767
- };
1768
- var TASK_WORKFLOW_SCHEMA_MARKER = "exact-task-v1";
1769
- var TASK_WORKFLOW_STATES = [
1770
- "idle",
1771
- "coder_delegated",
1772
- "pre_check_passed",
1773
- "reviewer_run",
1774
- "tests_run",
1775
- "rework_required",
1776
- "complete",
1777
- "blocked",
1778
- "closed"
1779
- ];
1780
- var TASK_WORKFLOW_OUTCOMES = [
1781
- "none",
1782
- "dispatch_attempted",
1783
- "dispatch_no_mutation",
1784
- "accepted_mutation",
1785
- "accepted_mutation_failed",
1786
- "stage_a_passed",
1787
- "stage_a_failed",
1788
- "stage_b_completed",
1789
- "stage_b_failed",
1790
- "gate_recorded",
1791
- "task_completed",
1792
- "task_blocked",
1793
- "task_closed",
1794
- "repair_idle",
1795
- "external_evidence_attested",
1796
- "external_evidence_revoked"
1797
- ];
1798
- var MAX_PLAN_SCOPE_INSPECTION_BYTES = 4 * 1024 * 1024;
1799
- function readCurrentTaskDeclaredFiles(directory, taskId) {
1800
- try {
1801
- const planPath = validateSwarmPath(directory, "plan.json");
1802
- const stat = statSync2(planPath);
1803
- if (!stat.isFile() || stat.size > MAX_PLAN_SCOPE_INSPECTION_BYTES) {
1804
- return null;
1805
- }
1806
- const parsed = JSON.parse(readFileSync3(planPath, "utf8"));
1807
- if (!Array.isArray(parsed.phases))
1808
- return null;
1809
- let declaredFiles = null;
1810
- for (const phase of parsed.phases) {
1811
- if (!phase || typeof phase !== "object")
1812
- return null;
1813
- const tasks = phase.tasks;
1814
- if (!Array.isArray(tasks))
1815
- return null;
1816
- for (const task of tasks) {
1817
- if (!task || typeof task !== "object")
1818
- return null;
1819
- const record = task;
1820
- if (record.id !== taskId)
1821
- continue;
1822
- if (!Array.isArray(record.files_touched) || !record.files_touched.every((file) => typeof file === "string")) {
1823
- return null;
1824
- }
1825
- if (declaredFiles !== null)
1826
- return null;
1827
- declaredFiles = [...record.files_touched];
1828
- }
1829
- }
1830
- return declaredFiles;
1831
- } catch {
1832
- return null;
1833
- }
1834
- }
1835
- var TASK_GATE_REQUIREMENTS_RECONSTRUCTION_SENTINEL = "requirements_reconstruction";
1836
- function assertTaskEvidenceWriteAllowed(directory, taskId, event) {
1837
- assertValidTaskId(taskId);
1838
- const coderWalPath = validateSwarmPath(directory, `coder-settlements/${taskId}.json`);
1839
- const coderWal = readWorkflowWalFileSync("coder-settlement", coderWalPath, taskId);
1840
- if ((coderWal?.state === "DISPATCHED" || coderWal?.state === "PREPARED") && !(event != null && event.transitionId === coderWal.transitionId && (event.type === "dispatch_attempted" || event.type === "dispatch_no_mutation" || event.type === "accepted_mutation"))) {
1841
- throw new Error(`CODER_SETTLEMENT_IN_PROGRESS: transition ${String(coderWal.transitionId)} owns evidence for task ${taskId}. Wait for the owning transition to settle or run /swarm recover ${taskId} (or /swarm reset-session), then retry; do not remove the WAL by hand.`);
1842
- }
1843
- const terminalWalPath = validateSwarmPath(directory, `task-terminals/${taskId}.json`);
1844
- const terminalWal = readWorkflowWalFileSync("task-terminal", terminalWalPath, taskId);
1845
- if (terminalWal?.state === "PREPARED") {
1846
- const matchingTerminalEvent = event != null && event.transitionId === terminalWal.transitionId && (event.type === "task_completed" && terminalWal.newPlanStatus === "completed" || event.type === "task_blocked" && terminalWal.newPlanStatus === "blocked" || event.type === "task_closed" && terminalWal.newPlanStatus === "closed");
1847
- if (!matchingTerminalEvent) {
1848
- throw new Error(`TASK_TERMINAL_PREPARED: transition ${String(terminalWal.transitionId)} owns evidence for task ${taskId}`);
1849
- }
1850
- }
1851
- const repairWalPath = validateSwarmPath(directory, `task-repairs/${taskId}.json`);
1852
- const repairWal = readWorkflowWalFileSync("task-repair", repairWalPath, taskId);
1853
- if (repairWal?.state === "PREPARED" && !(event?.type === "repair_idle" && event.transitionId === repairWal.transitionId)) {
1854
- throw new Error(`TASK_REPAIR_PREPARED: transition ${String(repairWal.transitionId)} owns evidence for task ${taskId}`);
1855
- }
1856
- }
1857
- var GateEvidenceSchema = exports_external.object({
1858
- sessionId: exports_external.string(),
1859
- timestamp: exports_external.string(),
1860
- agent: exports_external.string()
1861
- }).passthrough();
1862
- var ExternalEvidenceBundleSchema = exports_external.object({
1863
- class: exports_external.literal("external_git"),
1864
- transitionId: exports_external.string().min(1).max(512),
1865
- declarationDigest: exports_external.string().regex(/^[a-f0-9]{64}$/),
1866
- anchors: exports_external.array(exports_external.object({
1867
- command: exports_external.string().min(1).max(400),
1868
- expect: exports_external.string().max(4096).optional(),
1869
- expect_prefix: exports_external.string().min(1).max(4096).optional(),
1870
- matched: exports_external.boolean(),
1871
- exit_code: exports_external.number().int(),
1872
- stdout: exports_external.string().max(4096)
1873
- })).min(1).max(16).superRefine((anchors, ctx) => {
1874
- anchors.forEach((anchor, index) => {
1875
- if (anchor.expect === undefined && anchor.expect_prefix === undefined) {
1876
- ctx.addIssue({
1877
- code: exports_external.ZodIssueCode.custom,
1878
- message: `anchor ${index} must carry expect and/or a non-empty expect_prefix`,
1879
- path: [index]
1880
- });
1881
- }
1882
- });
1883
- }),
1884
- attestedAt: exports_external.string().min(1)
1885
- });
1886
- var TaskWorkflowMetadataSchema = exports_external.object({
1887
- schema: exports_external.literal(TASK_WORKFLOW_SCHEMA_MARKER),
1888
- generation: exports_external.number().int().min(0),
1889
- state: exports_external.enum(TASK_WORKFLOW_STATES),
1890
- retryCount: exports_external.number().int().min(0).default(0),
1891
- retryHistory: exports_external.array(exports_external.enum(TASK_WORKFLOW_OUTCOMES)).max(3).default([]),
1892
- retryEpoch: exports_external.number().int().min(0).default(0),
1893
- lastOutcome: exports_external.enum(TASK_WORKFLOW_OUTCOMES).default("none"),
1894
- lastTransitionId: exports_external.string().min(1).nullable().optional().default(null),
1895
- updatedAt: exports_external.string(),
1896
- forcedCompletion: exports_external.boolean().optional(),
1897
- supervisedRecovery: exports_external.boolean().optional(),
1898
- settlementRecovery: exports_external.boolean().optional(),
1899
- noMutationSettlement: exports_external.object({
1900
- generation: exports_external.literal(0),
1901
- transitionId: exports_external.string().min(1).max(512),
1902
- declaredFiles: exports_external.array(exports_external.string()).length(0)
1903
- }).optional(),
1904
- externalEvidence: ExternalEvidenceBundleSchema.optional()
1905
- });
1906
- var TaskEvidenceSchema = exports_external.object({
1907
- taskId: exports_external.string(),
1908
- required_gates: exports_external.array(exports_external.string()).default([]),
1909
- gates: exports_external.record(exports_external.string(), GateEvidenceSchema),
1910
- turbo: exports_external.boolean().optional(),
1911
- requirements_state: exports_external.enum(["known", "unknown"]).optional(),
1912
- test_engineer_exempt: exports_external.boolean().optional(),
1913
- planId: exports_external.string().optional(),
1914
- planIdentityHash: exports_external.string().regex(/^[a-f0-9]{64}$/).optional(),
1915
- workflow: TaskWorkflowMetadataSchema.optional(),
1916
- repair_provenance: exports_external.object({
1917
- source_sha256: exports_external.string().regex(/^[a-f0-9]{64}$/).nullable(),
1918
- source_generation: exports_external.number().int().min(0).nullable(),
1919
- requirements_receipt_hash: exports_external.string().regex(/^[a-f0-9]{64}$/).nullable()
1920
- }).optional(),
1921
- todo_scan: exports_external.object({
1922
- priority: exports_external.string(),
1923
- count: exports_external.number().int().min(0),
1924
- details: exports_external.array(exports_external.string()).max(200).optional(),
1925
- recorded_at: exports_external.string().optional()
1926
- }).optional()
1927
- });
1928
- function parseTaskEvidence(raw, expectedTaskId) {
1929
- const parsed = TaskEvidenceSchema.parse(JSON.parse(raw));
1930
- if (parsed.taskId !== expectedTaskId) {
1931
- throw new Error(`TASK_EVIDENCE_IDENTITY_MISMATCH: expected ${expectedTaskId}, found ${parsed.taskId}`);
1932
- }
1933
- return parsed;
1934
- }
1935
- function resolveCurrentPlanIdentitySync(directory) {
1936
- if (!directory)
1937
- return null;
1938
- try {
1939
- const planPath = path4.join(directory, ".swarm", "plan.json");
1940
- const raw = readFileSync3(planPath, "utf8");
1941
- const plan = JSON.parse(raw);
1942
- if (typeof plan.swarm !== "string" || typeof plan.title !== "string")
1943
- return null;
1944
- return {
1945
- planId: derivePlanId(plan),
1946
- planIdentityHash: derivePlanIdentityHash(plan)
1947
- };
1948
- } catch {
1949
- return null;
1950
- }
1951
- }
1952
- function evidenceStampedForDifferentPlan(evidence, currentPlanIdentityHash) {
1953
- if (evidence == null || currentPlanIdentityHash == null)
1954
- return false;
1955
- return typeof evidence.planIdentityHash === "string" && evidence.planIdentityHash !== currentPlanIdentityHash;
1956
- }
1957
- function planStampForPersist(nextEvidence, previous, planIdentity, campaignRestart) {
1958
- if (nextEvidence.planIdentityHash !== undefined)
1959
- return {};
1960
- const carriesGates = Object.keys(nextEvidence.gates ?? {}).length > 0;
1961
- if (carriesGates && previous != null && !campaignRestart) {
1962
- return previous.planIdentityHash !== undefined ? {
1963
- ...previous.planId !== undefined ? { planId: previous.planId } : {},
1964
- planIdentityHash: previous.planIdentityHash
1965
- } : {};
1966
- }
1967
- return planIdentity ? {
1968
- planId: planIdentity.planId,
1969
- planIdentityHash: planIdentity.planIdentityHash
1970
- } : {};
1971
- }
1972
- var DEFAULT_REQUIRED_GATES = ["reviewer", "test_engineer"];
1973
- var DEFAULT_WORKFLOW_STATE = "idle";
1974
- var WORKFLOW_STATE_RANK = {
1975
- idle: 0,
1976
- coder_delegated: 1,
1977
- pre_check_passed: 2,
1978
- reviewer_run: 3,
1979
- tests_run: 4,
1980
- rework_required: 5,
1981
- blocked: 6,
1982
- closed: 7,
1983
- complete: 8
1984
- };
1985
- function isValidTaskId(taskId) {
1986
- return isStrictTaskId(taskId);
1987
- }
1988
- function assertValidTaskId(taskId) {
1989
- assertStrictTaskId(taskId);
1990
- }
1991
- function createDefaultWorkflowMetadata(nowIso) {
1992
- return {
1993
- schema: TASK_WORKFLOW_SCHEMA_MARKER,
1994
- generation: 0,
1995
- state: DEFAULT_WORKFLOW_STATE,
1996
- retryCount: 0,
1997
- retryHistory: [],
1998
- retryEpoch: 0,
1999
- lastOutcome: "none",
2000
- lastTransitionId: null,
2001
- updatedAt: nowIso
2002
- };
2003
- }
2004
- function getEventOutcome(event) {
2005
- switch (event.type) {
2006
- case "dispatch_attempted":
2007
- return "dispatch_attempted";
2008
- case "dispatch_no_mutation":
2009
- return "dispatch_no_mutation";
2010
- case "accepted_mutation":
2011
- return event.context?.settlementFailed === true ? "accepted_mutation_failed" : "accepted_mutation";
2012
- case "stage_a_passed":
2013
- return "stage_a_passed";
2014
- case "stage_a_failed":
2015
- return "stage_a_failed";
2016
- case "stage_b_completed":
2017
- return "stage_b_completed";
2018
- case "stage_b_failed":
2019
- return "stage_b_failed";
2020
- case "gate_recorded":
2021
- return "gate_recorded";
2022
- case "task_completed":
2023
- return "task_completed";
2024
- case "task_blocked":
2025
- return "task_blocked";
2026
- case "task_closed":
2027
- return "task_closed";
2028
- case "repair_idle":
2029
- return "repair_idle";
2030
- case "external_evidence_attested":
2031
- return "external_evidence_attested";
2032
- case "external_evidence_revoked":
2033
- return "external_evidence_revoked";
2034
- }
2035
- }
2036
- function isAuthoritativeWorkflowMetadata(workflow) {
2037
- return workflow?.schema === TASK_WORKFLOW_SCHEMA_MARKER;
2038
- }
2039
- function getTaskWorkflowSnapshot(evidence) {
2040
- if (isAuthoritativeWorkflowMetadata(evidence?.workflow)) {
2041
- return { ...evidence.workflow, authoritative: true };
2042
- }
2043
- return {
2044
- ...createDefaultWorkflowMetadata(""),
2045
- authoritative: false
2046
- };
2047
- }
2048
- function maybeExpandRequiredGates(existing, event) {
2049
- if (event.type === "accepted_mutation") {
2050
- const agentType = event.agentType;
2051
- if (typeof agentType === "string" && agentType.trim() !== "") {
2052
- return existing ? expandRequiredGates(existing.required_gates.filter((gate) => gate !== TASK_GATE_REQUIREMENTS_RECONSTRUCTION_SENTINEL), agentType, event.context ?? {}) : deriveRequiredGates(agentType, event.context ?? {});
2053
- }
2054
- }
2055
- if (event.type === "stage_b_completed" && event.ensureDefaultStageB === true) {
2056
- return expandRequiredGates(existing?.required_gates ?? [], "coder", {
2057
- testEngineerExempt: false
2058
- });
2059
- }
2060
- if (event.type === "stage_b_completed" || event.type === "gate_recorded") {
2061
- return existing ? expandRequiredGates(existing.required_gates, event.gate) : deriveRequiredGates(event.gate);
2062
- }
2063
- return existing?.required_gates ?? [];
2064
- }
2065
- function hasAllRequiredGatesPassed(requiredGates, gates) {
2066
- return requiredGates.length > 0 && requiredGates.every((gate) => gates[gate] != null);
2067
- }
2068
- function shouldTreatGateAsStageB(gate) {
2069
- return gate === "reviewer" || gate === "test_engineer";
2070
- }
2071
- function clearWorkflowGateProof(gates) {
2072
- const retained = { ...gates };
2073
- delete retained.pre_check;
2074
- delete retained.reviewer;
2075
- delete retained.test_engineer;
2076
- delete retained.council;
2077
- delete retained.critic;
2078
- delete retained.critic_sounding_board;
2079
- return retained;
2080
- }
2081
- function assertExpectedGeneration(snapshot, event) {
2082
- if (typeof event.expectedGeneration === "number" && event.expectedGeneration !== snapshot.generation) {
2083
- throw new Error(`TASK_WORKFLOW_GENERATION_MISMATCH: expected ${event.expectedGeneration}, current ${snapshot.generation}`);
2084
- }
2085
- }
2086
- function isDuplicateTransition(snapshot, event) {
2087
- if (event.type === "dispatch_no_mutation" && event.context?.declaredFiles?.length === 0 && event.context.settlementTransitionId === event.transitionId && !snapshot.noMutationSettlement) {
2088
- return false;
2089
- }
2090
- return snapshot.authoritative && typeof event.transitionId === "string" && event.transitionId.length > 0 && snapshot.lastTransitionId === event.transitionId && snapshot.lastOutcome === getEventOutcome(event);
2091
- }
2092
- function isNoMutationSettlementMetadata(workflow) {
2093
- const settlement = workflow.noMutationSettlement;
2094
- if (!workflow.authoritative || workflow.generation !== 0 || settlement?.generation !== 0 || typeof settlement.transitionId !== "string" || settlement.transitionId.length === 0 || !Array.isArray(settlement.declaredFiles) || settlement.declaredFiles.length !== 0)
2095
- return false;
2096
- return workflow.state === "idle" || workflow.state === "complete";
2097
- }
2098
- function deriveApplicableGateSet(evidence, options) {
2099
- if (!evidence) {
2100
- return {
2101
- requiredGates: ["pre_check"],
2102
- satisfiedGates: [],
2103
- missingGates: ["pre_check"],
2104
- readOnlyNoMutation: false
2105
- };
2106
- }
2107
- const workflow = getTaskWorkflowSnapshot(evidence);
2108
- const readOnlyNoMutation = isNoMutationSettlementMetadata(workflow) && (options?.currentDeclaredFiles === undefined ? true : options.currentDeclaredFiles !== null && options.currentDeclaredFiles.length === 0);
2109
- const externalEvidenceMatched = workflow.lastOutcome === "external_evidence_attested" && (workflow.externalEvidence?.anchors.length ?? 0) > 0 && workflow.externalEvidence.anchors.every((anchor) => anchor.matched);
2110
- const requiredGates = [...new Set(evidence.required_gates ?? [])];
2111
- if (!readOnlyNoMutation && !externalEvidenceMatched && !requiredGates.includes("pre_check")) {
2112
- requiredGates.unshift("pre_check");
2113
- }
2114
- const satisfiedGates = requiredGates.filter((gate) => evidence.gates?.[gate] != null);
2115
- return {
2116
- requiredGates,
2117
- satisfiedGates,
2118
- missingGates: requiredGates.filter((gate) => evidence.gates?.[gate] == null),
2119
- readOnlyNoMutation
2120
- };
2121
- }
2122
- function isReadOnlyNoMutationEligible(evidence, options) {
2123
- return deriveApplicableGateSet(evidence, options).readOnlyNoMutation;
2124
- }
2125
- function computeExternalDeclarationDigest(input) {
2126
- const canonical = {
2127
- taskId: input.taskId,
2128
- evidence_class: input.evidence_class,
2129
- evidence_anchors: input.evidence_anchors.map((anchor) => ({
2130
- command: anchor.command,
2131
- expect: anchor.expect,
2132
- expect_prefix: anchor.expect_prefix
2133
- })),
2134
- plan_title: input.plan_title,
2135
- plan_swarm: input.plan_swarm,
2136
- generation: input.generation
2137
- };
2138
- return createHash2("sha256").update(JSON.stringify(canonical)).digest("hex");
2139
- }
2140
- function externalProofCurrent(plan, planTask, evidence) {
2141
- if (planTask.evidence_class !== "external_git")
2142
- return false;
2143
- const workflow = evidence?.workflow;
2144
- if (!workflow)
2145
- return false;
2146
- const bundle = workflow.externalEvidence;
2147
- if (!bundle || bundle.anchors.length === 0)
2148
- return false;
2149
- if (!bundle.anchors.every((anchor) => anchor.matched))
2150
- return false;
2151
- return bundle.declarationDigest === computeExternalDeclarationDigest({
2152
- taskId: planTask.id,
2153
- evidence_class: "external_git",
2154
- evidence_anchors: planTask.evidence_anchors ?? [],
2155
- plan_title: plan.title,
2156
- plan_swarm: plan.swarm,
2157
- generation: workflow.generation
2158
- });
2159
- }
2160
- function isExternalEvidenceInitialCompletionEligible(plan, planTask, evidence) {
2161
- if (!externalProofCurrent(plan, planTask, evidence))
2162
- return false;
2163
- const snapshot = getTaskWorkflowSnapshot(evidence);
2164
- return snapshot.authoritative && snapshot.state === "idle";
2165
- }
2166
- function reduceTaskWorkflowSnapshot(current, event, context) {
2167
- if ((current.state === "complete" || current.state === "blocked" || current.state === "closed") && event.type !== "repair_idle" && !(current.state === "complete" && event.type === "task_completed" || current.state === "blocked" && event.type === "task_blocked" || current.state === "blocked" && event.type === "task_closed" || current.state === "blocked" && event.type === "stage_a_passed" && event.settlementRecovery === true)) {
2168
- throw new Error(`TASK_WORKFLOW_TERMINAL: cannot apply ${event.type} from ${current.state}`);
2169
- }
2170
- const outcome = getEventOutcome(event);
2171
- const base = {
2172
- schema: TASK_WORKFLOW_SCHEMA_MARKER,
2173
- generation: current.generation,
2174
- state: current.state,
2175
- retryCount: current.retryCount,
2176
- retryHistory: current.retryHistory,
2177
- retryEpoch: current.retryEpoch,
2178
- lastOutcome: outcome,
2179
- lastTransitionId: event.transitionId ?? current.lastTransitionId,
2180
- updatedAt: context.nowIso,
2181
- ...current.forcedCompletion === true ? { forcedCompletion: true } : {},
2182
- ...current.supervisedRecovery === true ? { supervisedRecovery: true } : {},
2183
- ...current.settlementRecovery === true ? { settlementRecovery: true } : {},
2184
- ...current.noMutationSettlement ? { noMutationSettlement: current.noMutationSettlement } : {},
2185
- ...current.externalEvidence ? { externalEvidence: current.externalEvidence } : {}
2186
- };
2187
- switch (event.type) {
2188
- case "dispatch_attempted": {
2189
- const {
2190
- noMutationSettlement: _clearedSettlement,
2191
- externalEvidence: _clearedExternalEvidence,
2192
- ...withoutSettlement
2193
- } = base;
2194
- return withoutSettlement;
2195
- }
2196
- case "dispatch_no_mutation": {
2197
- const {
2198
- noMutationSettlement: _clearedSettlement,
2199
- externalEvidence: _clearedExternalEvidence,
2200
- ...withoutSettlement
2201
- } = base;
2202
- return {
2203
- ...withoutSettlement,
2204
- retryCount: Math.min(current.retryCount + 1, 3),
2205
- retryHistory: [...current.retryHistory, outcome].slice(-3),
2206
- retryEpoch: current.retryEpoch || current.generation + 1,
2207
- ...current.generation === 0 && event.transitionId && Array.isArray(event.context?.declaredFiles) && event.context.declaredFiles.length === 0 && event.context.settlementTransitionId === event.transitionId ? {
2208
- noMutationSettlement: {
2209
- generation: 0,
2210
- transitionId: event.transitionId,
2211
- declaredFiles: []
2212
- }
2213
- } : {}
2214
- };
2215
- }
2216
- case "stage_b_failed":
2217
- if (current.state !== "pre_check_passed" && current.state !== "reviewer_run" && current.state !== "tests_run" && current.state !== "rework_required") {
2218
- throw new Error(`TASK_WORKFLOW_STAGE_A_REQUIRED: cannot reject ${event.gate} from ${current.state}`);
2219
- }
2220
- return {
2221
- ...base,
2222
- state: "rework_required",
2223
- retryCount: Math.min(current.retryCount + 1, 3),
2224
- retryHistory: [...current.retryHistory, outcome].slice(-3),
2225
- retryEpoch: current.retryEpoch || current.generation + 1
2226
- };
2227
- case "accepted_mutation": {
2228
- const {
2229
- noMutationSettlement: _clearedSettlement,
2230
- externalEvidence: _clearedExternalEvidence,
2231
- ...withoutSettlement
2232
- } = base;
2233
- if (event.context?.settlementFailed === true) {
2234
- return {
2235
- ...withoutSettlement,
2236
- generation: current.generation + 1,
2237
- state: "rework_required",
2238
- retryCount: Math.min(current.retryCount + 1, 3),
2239
- retryHistory: [...current.retryHistory, outcome].slice(-3),
2240
- retryEpoch: current.retryEpoch || current.generation + 1,
2241
- supervisedRecovery: undefined,
2242
- settlementRecovery: undefined
2243
- };
2244
- }
2245
- return {
2246
- ...withoutSettlement,
2247
- generation: current.generation + 1,
2248
- state: "coder_delegated",
2249
- supervisedRecovery: undefined,
2250
- settlementRecovery: undefined
2251
- };
2252
- }
2253
- case "stage_a_passed":
2254
- if (current.state !== "coder_delegated" && current.state !== "pre_check_passed" && !(current.state === "rework_required" && event.supervisedRecovery === true) && !(event.settlementRecovery === true && (current.state === "idle" || current.state === "blocked"))) {
2255
- throw new Error(`TASK_WORKFLOW_CODER_MUTATION_REQUIRED: cannot pass Stage A from ${current.state}`);
2256
- }
2257
- return {
2258
- ...base,
2259
- ...event.supervisedRecovery === true ? { supervisedRecovery: true } : {},
2260
- ...event.settlementRecovery === true ? { settlementRecovery: true } : {},
2261
- state: "pre_check_passed"
2262
- };
2263
- case "stage_a_failed":
2264
- if (current.state !== "coder_delegated" && current.state !== "pre_check_passed" && current.state !== "rework_required") {
2265
- throw new Error(`TASK_WORKFLOW_CODER_MUTATION_REQUIRED: cannot fail Stage A from ${current.state}`);
2266
- }
2267
- return {
2268
- ...base,
2269
- state: "rework_required",
2270
- retryCount: Math.min(current.retryCount + 1, 3),
2271
- retryHistory: [...current.retryHistory, outcome].slice(-3),
2272
- retryEpoch: current.retryEpoch || current.generation + 1
2273
- };
2274
- case "stage_b_completed":
2275
- if (current.state !== "pre_check_passed" && current.state !== "reviewer_run" && current.state !== "tests_run") {
2276
- throw new Error(`TASK_WORKFLOW_STAGE_A_REQUIRED: cannot record ${event.gate} from ${current.state}`);
2277
- }
2278
- if (event.routeComplete === false) {
2279
- return {
2280
- ...base,
2281
- state: event.gate === "reviewer" || current.state === "reviewer_run" ? "reviewer_run" : current.state
2282
- };
2283
- }
2284
- if (event.routeComplete === true) {
2285
- return { ...base, state: "tests_run" };
2286
- }
2287
- return {
2288
- ...base,
2289
- state: hasAllRequiredGatesPassed(context.requiredGates, context.gates) ? "tests_run" : "reviewer_run"
2290
- };
2291
- case "gate_recorded":
2292
- return {
2293
- ...base,
2294
- state: current.state
2295
- };
2296
- case "external_evidence_attested": {
2297
- if (current.state !== "idle") {
2298
- throw new Error(`TASK_WORKFLOW_EXTERNAL_ATTEST_STATE: external evidence can only be attested from idle (task never entered the coder QA lifecycle), not ${current.state}`);
2299
- }
2300
- if (current.externalEvidence?.transitionId === event.bundle.transitionId) {
2301
- return { ...base };
2302
- }
2303
- return { ...base, externalEvidence: event.bundle };
2304
- }
2305
- case "external_evidence_revoked": {
2306
- const {
2307
- externalEvidence: _revokedExternalEvidence,
2308
- ...withoutExternalEvidence
2309
- } = base;
2310
- return withoutExternalEvidence;
2311
- }
2312
- case "task_completed": {
2313
- const readOnlyNoMutation = event.readOnlyNoMutation === true && current.state === "idle" && current.generation === 0 && isNoMutationSettlementMetadata(current) && context.requiredGates.every((gate) => context.gates[gate] != null);
2314
- const externalAdmitted = event.externalEvidence === true && current.externalEvidence !== undefined && current.externalEvidence.anchors.length > 0 && current.externalEvidence.anchors.every((anchor) => anchor.matched) && (current.state === "idle" || current.state === "complete");
2315
- if (event.qaExempt !== true && current.state !== "tests_run" && current.state !== "complete" && !(current.state === "pre_check_passed" && context.gates.council != null) && !readOnlyNoMutation && !externalAdmitted) {
2316
- throw new Error(`TASK_WORKFLOW_QA_REQUIRED: cannot complete from ${current.state}`);
2317
- }
2318
- return {
2319
- ...base,
2320
- state: "complete",
2321
- ...event.qaExempt === true ? { forcedCompletion: true } : {}
2322
- };
2323
- }
2324
- case "task_blocked":
2325
- return {
2326
- ...base,
2327
- state: "blocked"
2328
- };
2329
- case "task_closed":
2330
- return {
2331
- ...base,
2332
- state: "closed"
2333
- };
2334
- case "repair_idle": {
2335
- const {
2336
- forcedCompletion: _cleared,
2337
- supervisedRecovery: _clearedMarker,
2338
- settlementRecovery: _clearedSettlementMarker,
2339
- noMutationSettlement: _clearedSettlement,
2340
- externalEvidence: _clearedExternalEvidence,
2341
- ...withoutForced
2342
- } = base;
2343
- return {
2344
- ...withoutForced,
2345
- generation: current.generation + 1,
2346
- state: "idle",
2347
- retryCount: 0,
2348
- retryHistory: [],
2349
- retryEpoch: 0
2350
- };
2351
- }
2352
- }
2353
- }
2354
- function getEvidenceDir(directory) {
2355
- const swarmDir = path4.resolve(directory, ".swarm");
2356
- const evidenceDir = path4.join(swarmDir, "evidence");
2357
- mkdirSync3(evidenceDir, { recursive: true });
2358
- let resolvedSwarmDir;
2359
- let resolvedEvidenceDir;
2360
- try {
2361
- resolvedSwarmDir = path4.normalize(realpathSync2(swarmDir));
2362
- resolvedEvidenceDir = path4.normalize(realpathSync2(evidenceDir));
2363
- } catch (error) {
2364
- throw new Error(`Unable to resolve evidence directory: ${error.message}`);
2365
- }
2366
- const swarmPrefix = `${resolvedSwarmDir}${path4.sep}`;
2367
- const withinSwarmBoundary = process.platform === "win32" ? resolvedEvidenceDir.toLowerCase().startsWith(swarmPrefix.toLowerCase()) : resolvedEvidenceDir.startsWith(swarmPrefix);
2368
- if (!withinSwarmBoundary) {
2369
- throw new Error(`Evidence path escapes .swarm boundary: ${resolvedEvidenceDir}`);
2370
- }
2371
- return resolvedEvidenceDir;
2372
- }
2373
- function getEvidencePath(directory, taskId) {
2374
- assertValidTaskId(taskId);
2375
- return taskEvidencePath(directory, taskId);
2376
- }
2377
- function bindTrustedNoMutationSettlement(directory, taskId, event) {
2378
- if (event.type !== "dispatch_no_mutation")
2379
- return event;
2380
- const context = event.context;
2381
- if (!context || event.transitionId === undefined) {
2382
- return { ...event, context: undefined };
2383
- }
2384
- try {
2385
- const wal = readWorkflowWalFileSync("coder-settlement", validateSwarmPath(directory, `coder-settlements/${taskId}.json`), taskId);
2386
- const declaredFiles = wal?.context?.declaredFiles;
2387
- const trusted = wal !== null && (wal.state === "PREPARED" || wal.state === "COMMITTED") && wal.accepted === false && wal.transitionId === event.transitionId && Array.isArray(declaredFiles) && declaredFiles.length === 0 && Array.isArray(context.declaredFiles) && context.declaredFiles.length === 0;
2388
- return {
2389
- ...event,
2390
- context: trusted ? {
2391
- ...context,
2392
- declaredFiles,
2393
- settlementTransitionId: wal.transitionId
2394
- } : { ...context, settlementTransitionId: undefined }
2395
- };
2396
- } catch {
2397
- return {
2398
- ...event,
2399
- context: { ...context, settlementTransitionId: undefined }
2400
- };
2401
- }
2402
- }
2403
- function readExisting(evidencePath, taskId) {
2404
- try {
2405
- const raw = readFileSync3(evidencePath, "utf-8");
2406
- return parseTaskEvidence(raw, taskId);
2407
- } catch (error) {
2408
- if (error.code === "ENOENT")
2409
- return null;
2410
- telemetry.gateParseError(taskId, error);
2411
- throw error;
2412
- }
2413
- }
2414
- function deriveRequiredGates(agentType, context = {}) {
2415
- switch (agentType) {
2416
- case "coder":
2417
- return context.testEngineerExempt === true ? ["reviewer"] : ["reviewer", "test_engineer"];
2418
- case "docs":
2419
- return ["docs"];
2420
- case "designer":
2421
- return ["designer", "reviewer", "test_engineer"];
2422
- case "explorer":
2423
- return ["explorer"];
2424
- case "sme":
2425
- return ["sme"];
2426
- case "reviewer":
2427
- return ["reviewer"];
2428
- case "test_engineer":
2429
- return ["test_engineer"];
2430
- case "critic":
2431
- return ["critic"];
2432
- case "critic_sounding_board":
2433
- return ["critic_sounding_board"];
2434
- case "critic_drift_verifier":
2435
- return ["critic_drift_verifier"];
2436
- case "critic_hallucination_verifier":
2437
- return ["critic_hallucination_verifier"];
2438
- case "critic_architecture_supervisor":
2439
- return ["critic_architecture_supervisor"];
2440
- default:
2441
- return ["reviewer", "test_engineer"];
2442
- }
2443
- }
2444
- function expandRequiredGates(existingGates, newAgentType, context = {}) {
2445
- const newGates = deriveRequiredGates(newAgentType, context);
2446
- const combined = [...new Set([...existingGates ?? [], ...newGates])];
2447
- return combined.sort();
2448
- }
2449
- function updateEvidenceForTransition(existing, event) {
2450
- const nowIso = new Date().toISOString();
2451
- const requiredGates = maybeExpandRequiredGates(existing, event);
2452
- let gates = {
2453
- ...existing?.gates ?? {}
2454
- };
2455
- if (event.type === "accepted_mutation" || event.type === "repair_idle") {
2456
- gates = clearWorkflowGateProof(gates);
2457
- }
2458
- if (event.type === "stage_a_passed") {
2459
- gates = {
2460
- ...gates,
2461
- pre_check: {
2462
- sessionId: "system",
2463
- timestamp: nowIso,
2464
- agent: "pre_check"
2465
- }
2466
- };
2467
- }
2468
- if (event.type === "stage_a_failed") {
2469
- delete gates.pre_check;
2470
- }
2471
- if (event.type === "stage_b_failed") {
2472
- delete gates.reviewer;
2473
- delete gates.test_engineer;
2474
- }
2475
- if (event.type === "stage_b_completed" || event.type === "gate_recorded") {
2476
- gates = {
2477
- ...gates,
2478
- [event.gate]: {
2479
- sessionId: event.sessionId,
2480
- timestamp: nowIso,
2481
- agent: event.gate
2482
- }
2483
- };
2484
- }
2485
- const snapshot = getTaskWorkflowSnapshot(existing);
2486
- assertExpectedGeneration(snapshot, event);
2487
- if (isDuplicateTransition(snapshot, event) && existing) {
2488
- return existing;
2489
- }
2490
- const workflow = reduceTaskWorkflowSnapshot(snapshot, event, {
2491
- requiredGates,
2492
- gates,
2493
- nowIso
2494
- });
2495
- return {
2496
- taskId: existing?.taskId ?? "",
2497
- required_gates: requiredGates,
2498
- gates,
2499
- turbo: "turbo" in event && event.turbo === true ? true : ("turbo" in event) && event.turbo === false ? existing?.turbo : existing?.turbo,
2500
- test_engineer_exempt: (event.type === "dispatch_attempted" || event.type === "dispatch_no_mutation" || event.type === "accepted_mutation") && event.agentType === "coder" ? event.context?.testEngineerExempt === true && !requiredGates.includes("test_engineer") : existing?.test_engineer_exempt,
2501
- workflow,
2502
- requirements_state: existing?.requirements_state,
2503
- ...existing?.repair_provenance ? { repair_provenance: existing.repair_provenance } : {},
2504
- ...existing?.todo_scan ? { todo_scan: existing.todo_scan } : {}
2505
- };
2506
- }
2507
- async function transitionTaskWorkflowEvidence(directory, taskId, event) {
2508
- const { evidence } = await transitionTaskWorkflowEvidenceWithStatus(directory, taskId, event);
2509
- return evidence;
2510
- }
2511
- async function transitionTaskWorkflowEvidenceWithStatus(directory, taskId, event) {
2512
- assertValidTaskId(taskId);
2513
- let updatedEvidence = null;
2514
- let duplicated = false;
2515
- await withTaskEvidenceTransaction(directory, taskId, event.type, async (transaction) => {
2516
- if (transaction.transitionWithStatus) {
2517
- const result = await transaction.transitionWithStatus(event);
2518
- updatedEvidence = result.evidence;
2519
- duplicated = result.duplicated;
2520
- return;
2521
- }
2522
- updatedEvidence = await transaction.transition(event);
2523
- });
2524
- return {
2525
- evidence: updatedEvidence ?? {
2526
- taskId,
2527
- required_gates: [],
2528
- gates: {},
2529
- workflow: createDefaultWorkflowMetadata(new Date().toISOString())
2530
- },
2531
- duplicated
2532
- };
2533
- }
2534
- async function withTaskEvidenceTransaction(directory, taskId, agent, callback) {
2535
- assertValidTaskId(taskId);
2536
- return withTaskEvidenceLock(directory, taskId, agent, async () => {
2537
- const resolvedEvidenceDir = getEvidenceDir(directory);
2538
- const evidencePath = path4.join(resolvedEvidenceDir, `${taskId}.json`);
2539
- let current = null;
2540
- try {
2541
- current = readExisting(evidencePath, taskId);
2542
- } catch (error) {
2543
- telemetry.gateParseError(taskId, error);
2544
- throw error;
2545
- }
2546
- const persist = async (nextEvidence, event) => {
2547
- const planIdentity = resolveCurrentPlanIdentitySync(directory);
2548
- const validated = TaskEvidenceSchema.parse({
2549
- ...nextEvidence,
2550
- taskId,
2551
- ...planStampForPersist(nextEvidence, current, planIdentity, event?.type === "accepted_mutation" && event.agentType === "coder" && nextEvidence !== current)
2552
- });
2553
- await atomicWriteFile(evidencePath, JSON.stringify(validated, null, 2));
2554
- if (event) {
2555
- await _internals3.appendTaskGateRequirementsReceiptIfNeeded(directory, taskId, current, validated, event);
2556
- }
2557
- current = validated;
2558
- return validated;
2559
- };
2560
- const transitionWithStatusImpl = async (event) => {
2561
- const boundEvent = bindTrustedNoMutationSettlement(directory, taskId, event);
2562
- assertTaskEvidenceWriteAllowed(directory, taskId, boundEvent);
2563
- const nextEvidence = updateEvidenceForTransition(current, boundEvent);
2564
- const duplicated = nextEvidence === current;
2565
- nextEvidence.taskId = taskId;
2566
- const evidence = await persist(nextEvidence, boundEvent);
2567
- return { evidence, duplicated };
2568
- };
2569
- const saveImpl = async (nextEvidence) => {
2570
- assertTaskEvidenceWriteAllowed(directory, taskId, undefined);
2571
- nextEvidence.taskId = taskId;
2572
- return persist(nextEvidence);
2573
- };
2574
- return callback({
2575
- taskId,
2576
- read: () => current,
2577
- transition: async (event) => {
2578
- const { evidence } = await transitionWithStatusImpl(event);
2579
- return evidence;
2580
- },
2581
- transitionWithStatus: transitionWithStatusImpl,
2582
- save: saveImpl
2583
- });
2584
- });
2585
- }
2586
- async function ensureTaskGateRequirementsReceiptForSettledTransition(directory, taskId, evidence, event) {
2587
- assertValidTaskId(taskId);
2588
- const validated = TaskEvidenceSchema.parse({ ...evidence, taskId });
2589
- await _internals3.appendTaskGateRequirementsReceiptIfNeeded(directory, taskId, null, validated, event);
2590
- }
2591
- async function recordGateEvidence(directory, taskId, gate, sessionId, turbo, options = {}) {
2592
- assertValidTaskId(taskId);
2593
- if (shouldTreatGateAsStageB(gate) && typeof options.expectedGeneration !== "number") {
2594
- throw new Error(`TASK_WORKFLOW_GENERATION_REQUIRED: ${gate} for task ${taskId} must be bound at dispatch`);
2595
- }
2596
- await transitionTaskWorkflowEvidence(directory, taskId, shouldTreatGateAsStageB(gate) ? {
2597
- type: "stage_b_completed",
2598
- gate,
2599
- sessionId,
2600
- routeBinding: options.routeBinding,
2601
- routeComplete: options.routeComplete,
2602
- turbo,
2603
- ensureDefaultStageB: options.ensureDefaultStageB,
2604
- expectedGeneration: options.expectedGeneration,
2605
- transitionId: options.transitionId
2606
- } : {
2607
- type: "gate_recorded",
2608
- gate,
2609
- sessionId,
2610
- turbo,
2611
- expectedGeneration: options.expectedGeneration,
2612
- transitionId: options.transitionId
2613
- });
2614
- telemetry.gatePassed(sessionId, gate, taskId);
2615
- }
2616
- async function recordTodoScanEvidence(directory, taskId, scan) {
2617
- assertValidTaskId(taskId);
2618
- await withTaskEvidenceTransaction(directory, taskId, "todo_scan_recorded", async (transaction) => {
2619
- const existing = transaction.read();
2620
- const base = existing ?? {
2621
- taskId,
2622
- required_gates: [],
2623
- gates: {},
2624
- workflow: createDefaultWorkflowMetadata(new Date().toISOString())
2625
- };
2626
- if (!transaction.save) {
2627
- throw new Error(`TASK_EVIDENCE_SAVE_UNAVAILABLE: transaction for task ${taskId} does not support supplementary writes`);
2628
- }
2629
- await transaction.save({ ...base, todo_scan: scan });
2630
- });
2631
- }
2632
- async function recordAgentDispatch(directory, taskId, agentType, turbo, context = {}) {
2633
- assertValidTaskId(taskId);
2634
- const expectedGeneration = getTaskWorkflowSnapshot(await readTaskEvidence(directory, taskId)).generation;
2635
- await transitionTaskWorkflowEvidence(directory, taskId, agentType === "coder" ? {
2636
- type: "accepted_mutation",
2637
- agentType,
2638
- turbo,
2639
- context,
2640
- expectedGeneration
2641
- } : {
2642
- type: "dispatch_attempted",
2643
- agentType,
2644
- turbo,
2645
- context,
2646
- expectedGeneration
2647
- });
2648
- }
2649
- async function readTaskEvidence(directory, taskId) {
2650
- const state = await readTaskEvidenceState(directory, taskId);
2651
- return state.kind === "ok" ? state.evidence : null;
2652
- }
2653
- async function readTaskEvidenceState(directory, taskId) {
2654
- try {
2655
- assertValidTaskId(taskId);
2656
- } catch {
2657
- return { kind: "missing" };
2658
- }
2659
- try {
2660
- const evidencePath = getEvidencePath(directory, taskId);
2661
- const raw = readFileSync3(evidencePath, "utf-8");
2662
- const evidence = parseTaskEvidence(raw, taskId);
2663
- return { kind: "ok", evidence };
2664
- } catch (error) {
2665
- const evidencePath = getEvidencePathSafe(directory, taskId);
2666
- const code = error.code;
2667
- if (code === "ENOENT" || code === "ENAMETOOLONG") {
2668
- return { kind: "missing" };
2669
- }
2670
- telemetry.gateParseError(taskId, error);
2671
- return { kind: "unparseable", evidencePath, error };
2672
- }
2673
- }
2674
- function getEvidencePathSafe(directory, taskId) {
2675
- try {
2676
- return getEvidencePath(directory, taskId);
2677
- } catch {
2678
- return `${directory}/.swarm/evidence/${taskId}.json`;
2679
- }
2680
- }
2681
- function readTaskEvidenceRaw(directory, taskId) {
2682
- assertValidTaskId(taskId);
2683
- const evidencePath = getEvidencePath(directory, taskId);
2684
- try {
2685
- const raw = readFileSync3(evidencePath, "utf-8");
2686
- return parseTaskEvidence(raw, taskId);
2687
- } catch (error) {
2688
- const code = error.code;
2689
- if (code === "ENOENT" || code === "ENAMETOOLONG")
2690
- return null;
2691
- throw error;
2692
- }
2693
- }
2694
- async function hasPassedAllGates(directory, taskId, currentDeclaredFiles) {
2695
- const evidence = await readTaskEvidence(directory, taskId);
2696
- if (!evidence)
2697
- return false;
2698
- if (!Array.isArray(evidence.required_gates))
2699
- return false;
2700
- if (currentDeclaredFiles === undefined) {
2701
- if (deriveApplicableGateSet(evidence).readOnlyNoMutation)
2702
- return false;
2703
- return hasAllRequiredGatesPassed(evidence.required_gates, evidence.gates);
2704
- }
2705
- return deriveApplicableGateSet(evidence, { currentDeclaredFiles }).missingGates.length === 0;
2706
- }
2707
- function compareTaskWorkflowStateRank(left, right) {
2708
- return WORKFLOW_STATE_RANK[left] - WORKFLOW_STATE_RANK[right];
2709
- }
2710
-
2711
- export { readTaskGateRequirementsReceiptsSync, routeEvidenceFromTaskGateRequirements, isLegacyTaskGateRequirementsChain, isStrictTaskId, sanitizeTaskId, validateTaskIdFormat, listRecoveryRecords, recoveryReadErrored, _internals, SOURCE_WORKTREE_GONE_STAGE, SOURCE_WORKTREE_UNCERTAIN_STAGE, getMergeStrategy, recoverMergeBackFromImmutableCoordinates, reconcileLandedMerge, postMergeCleanup, pruneStaleWorktreeMetadata, attemptMergeBackFromDirty, cleanupOrphanedBranches, startupOrphanRecovery, readWorkflowWalFile, writeWorkflowWalFile, _internals3 as _internals1, TASK_WORKFLOW_SCHEMA_MARKER, readCurrentTaskDeclaredFiles, TASK_GATE_REQUIREMENTS_RECONSTRUCTION_SENTINEL, assertTaskEvidenceWriteAllowed, ExternalEvidenceBundleSchema, parseTaskEvidence, resolveCurrentPlanIdentitySync, evidenceStampedForDifferentPlan, DEFAULT_REQUIRED_GATES, isValidTaskId, getTaskWorkflowSnapshot, deriveApplicableGateSet, isReadOnlyNoMutationEligible, computeExternalDeclarationDigest, externalProofCurrent, isExternalEvidenceInitialCompletionEligible, reduceTaskWorkflowSnapshot, deriveRequiredGates, expandRequiredGates, transitionTaskWorkflowEvidence, transitionTaskWorkflowEvidenceWithStatus, withTaskEvidenceTransaction, ensureTaskGateRequirementsReceiptForSettledTransition, recordGateEvidence, recordTodoScanEvidence, recordAgentDispatch, readTaskEvidence, readTaskEvidenceState, readTaskEvidenceRaw, hasPassedAllGates, compareTaskWorkflowStateRank };
1946
+ export { listRecoveryRecords, recoveryReadErrored, probeSettlementSource, preserveSettlementSource, releaseSettlementSource, validateSettlementLane, _internals2 as _internals, SOURCE_WORKTREE_GONE_STAGE, SOURCE_WORKTREE_UNCERTAIN_STAGE, getMergeStrategy, recoverMergeBackFromImmutableCoordinates, reconcileLandedMerge, postMergeCleanup, pruneStaleWorktreeMetadata, attemptMergeBackFromDirty, cleanupOrphanedBranches, startupOrphanRecovery, _internals3 as _internals1, readWorkflowWalFile, readWorkflowWalFileSync, writeWorkflowWalFile };