opencode-swarm 7.199.3 → 7.199.5

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 (120) hide show
  1. package/.opencode/skills/swarm-pr-feedback/references/followup-dispositions.md +1 -0
  2. package/.opencode/skills/swarm-pr-review/SKILL.md +3 -3
  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/agents/architect.d.ts +1 -1
  6. package/dist/background/pending-delegations.d.ts +46 -0
  7. package/dist/cli/{auto-checkpoint-8sxq4fam.js → auto-checkpoint-tje4xvtw.js} +12 -11
  8. package/dist/cli/{checkpoint-septjh9j.js → checkpoint-wyh8nkhb.js} +21 -21
  9. package/dist/cli/{coder-settlement-5e51gv83.js → coder-settlement-d0ca5fb3.js} +18 -18
  10. package/dist/cli/{config-doctor-szqpesb3.js → config-doctor-swg02esj.js} +19 -19
  11. package/dist/cli/{core-wawy5vxa.js → core-yh8ae69m.js} +7 -7
  12. package/dist/cli/{curation-policy-0smbd33w.js → curation-policy-w9y0db1n.js} +8 -8
  13. package/dist/cli/{curator-s699p3wr.js → curator-9vzqhesg.js} +51 -51
  14. package/dist/cli/{curator-drift-p4xkfxm3.js → curator-drift-85qect05.js} +12 -12
  15. package/dist/cli/curator-llm-factory-dwvftpvm.js +82 -0
  16. package/dist/cli/{dispatch-1pbmmj8z.js → dispatch-sftetpzv.js} +4 -4
  17. package/dist/cli/{doctor-knowledge-receipt-phase-id-xcczpaad.js → doctor-knowledge-receipt-phase-id-eqzsh3b7.js} +12 -12
  18. package/dist/cli/{evidence-summary-service-smwfa1sk.js → evidence-summary-service-hc513kyq.js} +27 -27
  19. package/dist/cli/{gate-evidence-y1591qqg.js → gate-evidence-a10epye0.js} +13 -13
  20. package/dist/cli/guardrail-explain-rqqhmb44.js +83 -0
  21. package/dist/cli/guardrail-log-caspzygc.js +23 -0
  22. package/dist/cli/{guardrail-reset-fq7tby85.js → guardrail-reset-48r2n8mz.js} +51 -51
  23. package/dist/cli/hive-promoter-sd3a61mq.js +97 -0
  24. package/dist/cli/{index-zh3fxcnn.js → index-0aj9tvms.js} +51 -51
  25. package/dist/cli/{index-dyp5807d.js → index-0je0mees.js} +10 -8
  26. package/dist/cli/{index-2a8xvtba.js → index-0ra0vs2p.js} +13 -11
  27. package/dist/cli/{index-2mx2gn97.js → index-0veqvgny.js} +1 -1
  28. package/dist/cli/{index-j1kcy808.js → index-10wwrgj2.js} +6 -6
  29. package/dist/cli/{index-c36fnjz3.js → index-26dmsdx3.js} +4884 -5746
  30. package/dist/cli/{index-ywb5er8g.js → index-270zfq1f.js} +2 -2
  31. package/dist/cli/{index-krz83azd.js → index-34jat4f2.js} +2 -2
  32. package/dist/cli/{index-dgtvf04w.js → index-3ckvw3j2.js} +2 -2
  33. package/dist/cli/{index-wamvtpcn.js → index-3fz5w2wb.js} +15 -6
  34. package/dist/cli/{index-h349p91m.js → index-3mzc5rqc.js} +2 -2
  35. package/dist/cli/{index-bkscmz4z.js → index-4cyc18bc.js} +11 -11
  36. package/dist/cli/{index-wer76f2n.js → index-4pbzepgw.js} +1645 -124
  37. package/dist/cli/{index-7vzvj8ry.js → index-6ssraqaa.js} +15 -11
  38. package/dist/cli/{index-s7ftr7ka.js → index-6xv2hz0e.js} +5 -5
  39. package/dist/cli/{index-qy55ytz4.js → index-6xyt6d5m.js} +13 -13
  40. package/dist/cli/{index-ddq1vt2f.js → index-76skvj8z.js} +7 -7
  41. package/dist/cli/{index-2zwk30cc.js → index-85vd6sxy.js} +10 -10
  42. package/dist/cli/{index-68k5agm2.js → index-9c0vp5yj.js} +2 -2
  43. package/dist/cli/{index-36anctab.js → index-9n40q82y.js} +4 -4
  44. package/dist/cli/{index-nr1pj3hy.js → index-9y6yk1n0.js} +1 -1
  45. package/dist/cli/{index-j2vv0h13.js → index-axqyjreb.js} +6 -4
  46. package/dist/cli/{index-eh27whw4.js → index-b0kr8720.js} +53 -53
  47. package/dist/cli/{index-820pzqd6.js → index-b3ws03kp.js} +7 -5
  48. package/dist/cli/{index-dp7362hg.js → index-bgydmx8k.js} +11 -11
  49. package/dist/cli/{index-r0mapyst.js → index-d7y3cafq.js} +5 -5
  50. package/dist/cli/{index-5p1md309.js → index-dengtwpp.js} +5 -4
  51. package/dist/cli/{index-6dtt0brw.js → index-dtwj4hsk.js} +4 -4
  52. package/dist/cli/{index-4s6kdsfr.js → index-dz15f98h.js} +1 -1
  53. package/dist/cli/{index-fnqk017s.js → index-esakwcr3.js} +1 -1
  54. package/dist/cli/{index-hz2609qt.js → index-eyq1q1xn.js} +9 -7
  55. package/dist/cli/{index-5jp79fag.js → index-gyz59cbh.js} +25 -21
  56. package/dist/cli/{index-7c432abn.js → index-hx2f3j9w.js} +2 -2
  57. package/dist/cli/{index-p5pgjp7n.js → index-j3rfbs45.js} +1 -1
  58. package/dist/cli/{index-w7d8gcj0.js → index-jmhn6ab5.js} +2 -2
  59. package/dist/cli/{index-sn3z9bq2.js → index-my753e0g.js} +21 -17
  60. package/dist/cli/{index-2bc7zfw3.js → index-n1ddn12j.js} +2 -2
  61. package/dist/cli/{index-w4dbmngb.js → index-p5d32v0x.js} +11 -11
  62. package/dist/cli/{index-2s7dvzff.js → index-qbxk2rn6.js} +42 -41
  63. package/dist/cli/{index-w00dj8p5.js → index-snx2vb1x.js} +2 -2
  64. package/dist/cli/{index-zxdawwc7.js → index-sp2cxpaq.js} +131 -8
  65. package/dist/cli/{index-g4fs6z4e.js → index-spggmr30.js} +6 -2
  66. package/dist/cli/{index-pxdc0qn1.js → index-tsg61z0r.js} +2 -2
  67. package/dist/cli/{index-5c6h1d0s.js → index-v4mremxw.js} +6 -5
  68. package/dist/cli/{index-cjapb4hy.js → index-x5jwegqw.js} +7 -5
  69. package/dist/cli/{index-4925h28w.js → index-xtda4xsn.js} +403 -170
  70. package/dist/cli/{index-2acc95ec.js → index-xyg7des8.js} +4 -4
  71. package/dist/cli/{index-ccpxq4yh.js → index-ybvnf7rt.js} +8 -8
  72. package/dist/cli/{index-r7swzftd.js → index-yg5xd4am.js} +18 -16
  73. package/dist/cli/{index-hc6wa3yg.js → index-zbygz217.js} +3 -3
  74. package/dist/cli/{index-yvjpwsrd.js → index-zdfzrwbk.js} +7 -7
  75. package/dist/cli/{index-vdhr11qv.js → index-zte3djpf.js} +2 -2
  76. package/dist/cli/index.js +52 -52
  77. package/dist/cli/{knowledge-escalator-ebvnynz8.js → knowledge-escalator-9wqe0m8j.js} +18 -18
  78. package/dist/cli/{knowledge-events-crh7ax0w.js → knowledge-events-m5vdchaa.js} +16 -16
  79. package/dist/cli/{knowledge-link-1f91bzcc.js → knowledge-link-t0ce3mw7.js} +7 -7
  80. package/dist/cli/{knowledge-store-58rh7jbp.js → knowledge-store-ff4hy057.js} +8 -8
  81. package/dist/cli/{knowledge-validator-0vmhxf5s.js → knowledge-validator-erj5thtq.js} +10 -10
  82. package/dist/cli/{mcp-kjatmx4e.js → mcp-d0hz5gfp.js} +1 -1
  83. package/dist/cli/{model-preflight-0c7xkq6x.js → model-preflight-p34x0k25.js} +51 -51
  84. package/dist/cli/{pending-delegations-j8g6zmnx.js → pending-delegations-1j6dx1mf.js} +18 -15
  85. package/dist/cli/{pr-subscriptions-5zfjmma9.js → pr-subscriptions-b1g41jce.js} +15 -15
  86. package/dist/cli/{pr-workflow-gate-y0yfj38r.js → pr-workflow-gate-zjwt050h.js} +59 -59
  87. package/dist/cli/{runner-7sd43gan.js → runner-wq954cda.js} +9 -9
  88. package/dist/cli/{scan-cursor-gegs7kjt.js → scan-cursor-enz1rp21.js} +11 -10
  89. package/dist/cli/{schema-znqyq1kp.js → schema-9r8sggpb.js} +1 -1
  90. package/dist/cli/{scope-persistence-sx4qgy4b.js → scope-persistence-c5n4g9f0.js} +20 -19
  91. package/dist/cli/{server-rbknas06.js → server-8z7pd66d.js} +56 -56
  92. package/dist/cli/{skill-generator-gtg3yenw.js → skill-generator-nezzfa0t.js} +20 -20
  93. package/dist/cli/{snapshot-coordination-init-a0tt6s4t.js → snapshot-coordination-init-2j06c7ck.js} +51 -51
  94. package/dist/cli/{speckit-checkoff-gqcw669v.js → speckit-checkoff-805cqmrf.js} +7 -6
  95. package/dist/cli/{telemetry-6yv06xyz.js → telemetry-gena5typ.js} +3 -3
  96. package/dist/cli/{workspace-snapshot-4zfj5wnd.js → workspace-snapshot-hzhz0rxw.js} +7 -7
  97. package/dist/cli/{worktree-collision-ownership-6qwxygnn.js → worktree-collision-ownership-xpr0yv7h.js} +22 -21
  98. package/dist/cli/{worktree-isolation-6sc66ka0.js → worktree-isolation-z6ytes0j.js} +51 -51
  99. package/dist/commands/close/dry-run.d.ts +2 -1
  100. package/dist/commands/close/orchestrator.d.ts +16 -5
  101. package/dist/commands/destructive-purge.d.ts +53 -12
  102. package/dist/commands/git-status-read.d.ts +76 -0
  103. package/dist/commands/rollback-gate.d.ts +24 -5
  104. package/dist/config/schema.d.ts +5 -3
  105. package/dist/evaluation/contracts.d.ts +5 -5
  106. package/dist/hooks/lane-liveness-watchdog.d.ts +6 -1
  107. package/dist/hooks/pr-workflow-gate.d.ts +61 -1
  108. package/dist/index.js +254 -252
  109. package/dist/memory/schema.d.ts +3 -3
  110. package/dist/pr-review/completion.d.ts +63 -2
  111. package/dist/services/diagnose-service.d.ts +7 -8
  112. package/dist/tools/dispatch-lanes.d.ts +2 -1
  113. package/dist/utils/git-executable.d.ts +4 -0
  114. package/opencode-swarm.schema.json +3 -2
  115. package/package.json +1 -1
  116. package/dist/cli/curator-llm-factory-m6w5axpg.js +0 -82
  117. package/dist/cli/guardrail-explain-1fvbaenr.js +0 -83
  118. package/dist/cli/guardrail-log-nd644x5c.js +0 -23
  119. package/dist/cli/hive-promoter-bhnm4sf7.js +0 -97
  120. package/dist/cli/{index-fzpt2djt.js → index-te9hq2f4.js} +3 -3
@@ -4,7 +4,7 @@ import {
4
4
  ensureTaskCheckpointReceipt,
5
5
  loadPlan,
6
6
  updateTaskCheckpointReceipt
7
- } from "./index-5jp79fag.js";
7
+ } from "./index-gyz59cbh.js";
8
8
  import {
9
9
  tool
10
10
  } from "./index-9nyqt3kb.js";
@@ -14,16 +14,16 @@ import {
14
14
  isGitBinaryMissing,
15
15
  isSpawnCwdMissing,
16
16
  isSpawnCwdUnreadable
17
- } from "./index-g4fs6z4e.js";
17
+ } from "./index-spggmr30.js";
18
18
  import {
19
19
  validateSwarmPath
20
- } from "./index-820pzqd6.js";
20
+ } from "./index-b3ws03kp.js";
21
21
  import {
22
22
  readLedgerEvents
23
- } from "./index-ccpxq4yh.js";
23
+ } from "./index-ybvnf7rt.js";
24
24
  import {
25
25
  appendCoreEventSync
26
- } from "./index-h349p91m.js";
26
+ } from "./index-3mzc5rqc.js";
27
27
  import {
28
28
  derivePlanId,
29
29
  derivePlanIdentityHash
@@ -38,22 +38,27 @@ import {
38
38
  } from "./index-ejhxgyvm.js";
39
39
  import {
40
40
  atomicWriteSwarmFileSync
41
- } from "./index-ywb5er8g.js";
41
+ } from "./index-270zfq1f.js";
42
42
  import {
43
43
  loadPluginConfigWithMeta
44
- } from "./index-dgtvf04w.js";
44
+ } from "./index-3ckvw3j2.js";
45
45
  import {
46
46
  init_git_executable,
47
- resolveGitExecutable
48
- } from "./index-zxdawwc7.js";
47
+ resolveGitExecutable,
48
+ resolveGitExecutableAsync
49
+ } from "./index-sp2cxpaq.js";
49
50
  import {
50
- exports_external,
51
- init_zod
52
- } from "./index-gknz3bv1.js";
51
+ bunSpawn,
52
+ init_bun_compat
53
+ } from "./index-qbxk2rn6.js";
53
54
  import {
54
55
  init_logger,
55
56
  log
56
57
  } from "./index-zgwm4ryv.js";
58
+ import {
59
+ exports_external,
60
+ init_zod
61
+ } from "./index-gknz3bv1.js";
57
62
 
58
63
  // src/tools/checkpoint.ts
59
64
  init_zod();
@@ -62,12 +67,347 @@ import * as fs4 from "fs";
62
67
  import * as path5 from "path";
63
68
 
64
69
  // src/commands/destructive-purge.ts
65
- import { spawnSync } from "child_process";
66
70
  import { createHash, randomBytes } from "crypto";
67
71
  import * as fs from "fs";
68
- import * as path from "path";
69
- init_git_executable();
72
+ import * as path2 from "path";
70
73
  init_logger();
74
+
75
+ // src/commands/git-status-read.ts
76
+ init_bun_compat();
77
+ init_git_executable();
78
+ var GIT_READ_DEFAULT_TIMEOUT_MS = 1e4;
79
+ var GIT_READ_DEFAULT_MAX_BUFFER_BYTES = 1024 * 1024;
80
+ var GIT_READ_STDERR_TAIL_MAX_CHARS = 200;
81
+ var TRANSIENT_RETRY_CODES = new Set(["ETIMEDOUT", "EBUSY", "EPERM"]);
82
+ function stderrTail(text) {
83
+ const tail = text.slice(-GIT_READ_STDERR_TAIL_MAX_CHARS);
84
+ return tail.replace(/[\x00-\x1f\x7f]+/g, " ").trim();
85
+ }
86
+ async function readBoundedOutput(stream, maxBytes) {
87
+ const reader = stream.getReader();
88
+ const chunks = [];
89
+ let totalBytes = 0;
90
+ let truncated = false;
91
+ try {
92
+ for (;; ) {
93
+ const { done, value } = await reader.read();
94
+ if (done)
95
+ break;
96
+ if (!value)
97
+ continue;
98
+ const remaining = maxBytes - totalBytes;
99
+ if (value.byteLength > remaining) {
100
+ if (remaining > 0)
101
+ chunks.push(value.slice(0, remaining));
102
+ truncated = true;
103
+ totalBytes += remaining;
104
+ continue;
105
+ }
106
+ chunks.push(value);
107
+ totalBytes += value.byteLength;
108
+ }
109
+ const joined = new Uint8Array(totalBytes);
110
+ let offset = 0;
111
+ for (const chunk of chunks) {
112
+ joined.set(chunk, offset);
113
+ offset += chunk.byteLength;
114
+ }
115
+ return { text: new TextDecoder().decode(joined), truncated };
116
+ } finally {
117
+ try {
118
+ reader.releaseLock();
119
+ } catch {}
120
+ }
121
+ }
122
+ async function readOnceDefault(args, cwd, timeoutMs, maxBufferBytes = GIT_READ_DEFAULT_MAX_BUFFER_BYTES, ignoreOutput = false) {
123
+ let proc;
124
+ let timer;
125
+ let resolutionTimer;
126
+ let childCompleted = false;
127
+ try {
128
+ const startedAt = Date.now();
129
+ const resolution = gitStatusReadInternals.resolveExecutable().then((executable2) => ({ kind: "resolved", executable: executable2 }));
130
+ resolution.catch(() => {});
131
+ const resolutionOutcome = await Promise.race([
132
+ resolution,
133
+ new Promise((resolve) => {
134
+ resolutionTimer = setTimeout(() => resolve({ kind: "timeout" }), timeoutMs);
135
+ })
136
+ ]);
137
+ if (resolutionTimer !== undefined) {
138
+ clearTimeout(resolutionTimer);
139
+ resolutionTimer = undefined;
140
+ }
141
+ if (resolutionOutcome.kind === "timeout") {
142
+ return { ok: false, code: "ETIMEDOUT", status: null, stderrTail: "" };
143
+ }
144
+ const executable = resolutionOutcome.executable;
145
+ const remainingMs = timeoutMs - (Date.now() - startedAt);
146
+ if (remainingMs <= 0) {
147
+ return { ok: false, code: "ETIMEDOUT", status: null, stderrTail: "" };
148
+ }
149
+ const options = {
150
+ cwd,
151
+ stdin: "ignore",
152
+ stdout: ignoreOutput ? "ignore" : "pipe",
153
+ stderr: ignoreOutput ? "ignore" : "pipe",
154
+ killProcessTree: true,
155
+ maxBuffer: ignoreOutput ? undefined : maxBufferBytes,
156
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
157
+ };
158
+ proc = gitStatusReadInternals.spawn([executable, ...args], options);
159
+ if (proc.spawnError) {
160
+ return {
161
+ ok: false,
162
+ code: proc.spawnError.code ?? null,
163
+ status: null,
164
+ stderrTail: ""
165
+ };
166
+ }
167
+ const completed = Promise.all([
168
+ proc.exited,
169
+ ignoreOutput ? Promise.resolve({ text: "", truncated: false }) : readBoundedOutput(proc.stdout, maxBufferBytes),
170
+ ignoreOutput ? Promise.resolve({ text: "", truncated: false }) : readBoundedOutput(proc.stderr, maxBufferBytes)
171
+ ]).then(([exitCode, stdout, stderr]) => ({
172
+ kind: "completed",
173
+ exitCode,
174
+ stdout,
175
+ stderr
176
+ }));
177
+ completed.catch(() => {});
178
+ const result = await Promise.race([
179
+ completed,
180
+ new Promise((resolve) => {
181
+ timer = setTimeout(() => resolve({ kind: "timeout" }), remainingMs);
182
+ })
183
+ ]);
184
+ if (result.kind === "timeout") {
185
+ return { ok: false, code: "ETIMEDOUT", status: null, stderrTail: "" };
186
+ }
187
+ childCompleted = true;
188
+ if (proc.spawnError) {
189
+ return {
190
+ ok: false,
191
+ code: proc.spawnError.code ?? null,
192
+ status: null,
193
+ stderrTail: stderrTail(result.stderr.text)
194
+ };
195
+ }
196
+ if (result.stdout.truncated || result.stderr.truncated) {
197
+ const partialStderr = stderrTail(result.stderr.text);
198
+ return {
199
+ ok: false,
200
+ code: "EOUTPUT",
201
+ status: null,
202
+ stderrTail: `output exceeded the ${maxBufferBytes}-byte bound${partialStderr ? `: ${partialStderr}` : ""}`
203
+ };
204
+ }
205
+ if (result.exitCode === null || result.exitCode === -1 || proc.signalCode != null) {
206
+ return {
207
+ ok: false,
208
+ code: "ESIGNAL",
209
+ status: null,
210
+ stderrTail: stderrTail(result.stderr.text)
211
+ };
212
+ }
213
+ if (result.exitCode !== 0) {
214
+ return {
215
+ ok: false,
216
+ code: null,
217
+ status: result.exitCode,
218
+ stderrTail: stderrTail(result.stderr.text)
219
+ };
220
+ }
221
+ return { ok: true, stdout: result.stdout.text };
222
+ } catch (err) {
223
+ return {
224
+ ok: false,
225
+ code: err?.code ?? null,
226
+ status: null,
227
+ stderrTail: ""
228
+ };
229
+ } finally {
230
+ if (timer)
231
+ clearTimeout(timer);
232
+ if (resolutionTimer)
233
+ clearTimeout(resolutionTimer);
234
+ if (!childCompleted && proc && !proc.spawnError) {
235
+ try {
236
+ proc.kill("SIGKILL");
237
+ } catch {}
238
+ let reapTimer;
239
+ try {
240
+ await Promise.race([
241
+ proc.exited,
242
+ new Promise((resolve) => {
243
+ reapTimer = setTimeout(resolve, 2000);
244
+ })
245
+ ]);
246
+ } catch {} finally {
247
+ if (reapTimer)
248
+ clearTimeout(reapTimer);
249
+ }
250
+ }
251
+ }
252
+ }
253
+ var gitStatusReadInternals = {
254
+ readOnce: readOnceDefault,
255
+ resolveExecutable: () => resolveGitExecutableAsync(),
256
+ spawn: bunSpawn
257
+ };
258
+ async function readGitStatusAsync(args, cwd, opts) {
259
+ const timeoutMs = opts?.timeoutMs ?? GIT_READ_DEFAULT_TIMEOUT_MS;
260
+ const maxBufferBytes = opts?.maxBufferBytes ?? GIT_READ_DEFAULT_MAX_BUFFER_BYTES;
261
+ const first = await gitStatusReadInternals.readOnce(args, cwd, timeoutMs, maxBufferBytes);
262
+ if (first.ok || first.code === null)
263
+ return first;
264
+ if (!TRANSIENT_RETRY_CODES.has(first.code))
265
+ return first;
266
+ return gitStatusReadInternals.readOnce(args, cwd, timeoutMs, maxBufferBytes);
267
+ }
268
+ async function readGitRepositoryStatusAsync(cwd) {
269
+ const result = await gitStatusReadInternals.readOnce(["rev-parse", "--git-dir"], cwd, GIT_READ_DEFAULT_TIMEOUT_MS);
270
+ return result.ok;
271
+ }
272
+
273
+ // src/commands/rollback-gate.ts
274
+ import * as fsSync from "fs";
275
+ import * as path from "path";
276
+ var ROLLBACK_GIT_KIND = "swarm-rollback-git";
277
+ var ROLLBACK_PHASE_KIND = "swarm-rollback-phase";
278
+ var GIT_LIST_MAX_BUFFER_BYTES = 32 * 1024 * 1024;
279
+ var _rollbackGateInternals = {
280
+ runGit: (args, cwd) => readGitStatusAsync(args, cwd),
281
+ runGitBuffered: (args, cwd) => readGitStatusAsync(args, cwd, {
282
+ maxBufferBytes: GIT_LIST_MAX_BUFFER_BYTES
283
+ })
284
+ };
285
+ async function readToString(raw) {
286
+ const value = await raw;
287
+ if (typeof value === "string")
288
+ return value;
289
+ if (value === null)
290
+ return null;
291
+ return value.ok ? value.stdout : null;
292
+ }
293
+ async function readFailureDetail(raw) {
294
+ const value = await raw;
295
+ if (value === null || typeof value === "string")
296
+ return null;
297
+ if (value.ok)
298
+ return null;
299
+ return {
300
+ code: value.code,
301
+ status: value.status,
302
+ stderrTail: value.stderrTail
303
+ };
304
+ }
305
+ function isRealGitRepository(directory) {
306
+ try {
307
+ if (fsSync.statSync(path.join(directory, ".git")).isFile())
308
+ return true;
309
+ } catch {
310
+ return false;
311
+ }
312
+ return fsSync.existsSync(path.join(directory, ".git", "HEAD"));
313
+ }
314
+ function parseTrackedDirtyPaths(statusOutput) {
315
+ const dirtyPaths = [];
316
+ const tokens = statusOutput.split("\x00");
317
+ for (let i = 0;i < tokens.length; i += 1) {
318
+ const token = tokens[i];
319
+ if (token === "" || token.length < 4)
320
+ continue;
321
+ const xy = token.slice(0, 2);
322
+ if (xy === "??")
323
+ continue;
324
+ const filePath = token.slice(3);
325
+ if (!filePath)
326
+ continue;
327
+ dirtyPaths.push(filePath);
328
+ if (/[RC]/.test(xy) && i + 1 < tokens.length && tokens[i + 1] !== "") {
329
+ dirtyPaths.push(tokens[i + 1]);
330
+ i += 1;
331
+ }
332
+ }
333
+ return dirtyPaths;
334
+ }
335
+ async function untrackedPathsInTargetTree(directory, targetSha) {
336
+ if (!isRealGitRepository(directory))
337
+ return [];
338
+ const targetTree = await readToString(await _rollbackGateInternals.runGitBuffered(["ls-tree", "-r", "-z", "--name-only", targetSha], directory));
339
+ const index = await readToString(await _rollbackGateInternals.runGitBuffered(["ls-files", "-z"], directory));
340
+ if (targetTree === null || index === null)
341
+ return [];
342
+ const indexed = new Set(index.split("\x00").filter((p) => p !== ""));
343
+ const inWay = [];
344
+ for (const rel of targetTree.split("\x00")) {
345
+ if (rel === "" || indexed.has(rel))
346
+ continue;
347
+ if (fsSync.existsSync(path.join(directory, rel)))
348
+ inWay.push(rel);
349
+ }
350
+ return inWay;
351
+ }
352
+ function trackedDirtyCandidates(directory, dirtyRelPaths) {
353
+ return dirtyRelPaths.map((rel) => ({
354
+ path: path.join(directory, rel),
355
+ reason: "uncommitted tracked change \u2014 destroyed by git reset --hard"
356
+ }));
357
+ }
358
+ function swarmOverwriteCandidates(directory, overwriteRelPaths) {
359
+ return overwriteRelPaths.map((rel) => ({
360
+ path: path.join(directory, ".swarm", rel),
361
+ reason: "live .swarm state replaced by the checkpoint copy"
362
+ }));
363
+ }
364
+ function describeUnreadableCause(measurement) {
365
+ if (measurement.code === "ETIMEDOUT") {
366
+ return "the read timed out (ETIMEDOUT) \u2014 the host may be unable to complete child spawns while loaded; restart the host and retry";
367
+ }
368
+ if (measurement.code === "EOUTPUT") {
369
+ return `the status output exceeded the read safety bound (${measurement.stderrTail ?? "output too large"}) \u2014 reduce the change footprint (commit or stash some work, or remove untracked bulk) and retry`;
370
+ }
371
+ if (measurement.code === "ESIGNAL") {
372
+ return "the git process was terminated before it answered (signal) \u2014 something external stopped it; retry, and inspect what terminates child processes if it recurs";
373
+ }
374
+ if (measurement.code === "ENOENT") {
375
+ return "the git executable was not found (ENOENT) \u2014 install git on PATH, or set git.binary in your USER-level config, and retry";
376
+ }
377
+ if (measurement.status !== null && measurement.status !== undefined) {
378
+ return `git status exited with status ${measurement.status}${measurement.stderrTail ? `: ${measurement.stderrTail}` : ""} \u2014 repair the repository state and retry`;
379
+ }
380
+ if (measurement.code) {
381
+ return `the read failed with code ${measurement.code} \u2014 retry, or inspect git status manually`;
382
+ }
383
+ return "retry, or inspect git status manually";
384
+ }
385
+ async function measureGitDestruction(directory, targetSha) {
386
+ if (!isRealGitRepository(directory)) {
387
+ return { kind: "ok", dirtyRelPaths: [] };
388
+ }
389
+ const raw = _rollbackGateInternals.runGit(["--no-optional-locks", "status", "--porcelain", "-z"], directory);
390
+ const status = await readToString(raw);
391
+ if (status === null) {
392
+ const failure = await readFailureDetail(raw);
393
+ return failure ? {
394
+ kind: "unreadable",
395
+ code: failure.code,
396
+ status: failure.status,
397
+ stderrTail: failure.stderrTail
398
+ } : { kind: "unreadable" };
399
+ }
400
+ const dirtyRelPaths = parseTrackedDirtyPaths(status);
401
+ if (targetSha) {
402
+ for (const rel of await untrackedPathsInTargetTree(directory, targetSha)) {
403
+ if (!dirtyRelPaths.includes(rel))
404
+ dirtyRelPaths.push(rel);
405
+ }
406
+ }
407
+ return { kind: "ok", dirtyRelPaths };
408
+ }
409
+
410
+ // src/commands/destructive-purge.ts
71
411
  var PENDING_PURGE_PATH = "pending-purge.json";
72
412
  var PENDING_PURGE_TTL_MS = 15 * 60 * 1000;
73
413
  var _internals = {
@@ -78,23 +418,26 @@ var _internals = {
78
418
  now: () => Date.now(),
79
419
  randomBytes,
80
420
  scopeDigest,
81
- runGitStatus: runGitStatusSync
421
+ runGitStatus: (args, cwd) => readGitStatusAsync(args, cwd)
82
422
  };
83
- var GIT_STATUS_ARGS = ["status", "--porcelain"];
84
- function runGitStatusSync(args, cwd) {
85
- const result = spawnSync(resolveGitExecutable(), args, {
86
- cwd,
87
- encoding: "utf8",
88
- timeout: 1e4,
89
- maxBuffer: 1024 * 1024,
90
- windowsHide: true,
91
- stdio: ["ignore", "pipe", "pipe"]
92
- });
93
- if (result.error || result.status !== 0)
423
+ var GIT_STATUS_ARGS = [
424
+ "--no-optional-locks",
425
+ "status",
426
+ "--porcelain"
427
+ ];
428
+ async function runGitStatusRead(args, cwd) {
429
+ const raw = await _internals.runGitStatus(args, cwd);
430
+ if (typeof raw === "string")
431
+ return { stdout: raw };
432
+ if (raw === null)
94
433
  return null;
95
- return result.stdout ?? "";
434
+ if (raw.ok)
435
+ return { stdout: raw.stdout };
436
+ return {
437
+ cause: { code: raw.code, status: raw.status, stderrTail: raw.stderrTail }
438
+ };
96
439
  }
97
- function parseTrackedDirtyPaths(statusOutput) {
440
+ function parseTrackedDirtyPaths2(statusOutput) {
98
441
  const dirtyPaths = [];
99
442
  for (const line of statusOutput.split(`
100
443
  `)) {
@@ -117,18 +460,20 @@ function parseTrackedDirtyPaths(statusOutput) {
117
460
  }
118
461
  return dirtyPaths;
119
462
  }
120
- function readTrackedDirtyPaths(directory) {
121
- const statusOutput = _internals.runGitStatus(GIT_STATUS_ARGS, directory);
122
- if (statusOutput === null)
463
+ async function readTrackedDirtyPaths(directory) {
464
+ const read = await runGitStatusRead(GIT_STATUS_ARGS, directory);
465
+ if (read === null)
123
466
  return { ok: false };
124
- return { ok: true, dirtyPaths: parseTrackedDirtyPaths(statusOutput) };
467
+ if ("cause" in read)
468
+ return { ok: false, failure: read.cause };
469
+ return { ok: true, dirtyPaths: parseTrackedDirtyPaths2(read.stdout) };
125
470
  }
126
- function recheckBeforeDestructive(directory, expectedDirtyPaths) {
127
- const read = readTrackedDirtyPaths(directory);
471
+ async function recheckBeforeDestructive(directory, expectedDirtyPaths) {
472
+ const read = await readTrackedDirtyPaths(directory);
128
473
  if (!read.ok) {
129
474
  return {
130
475
  ok: false,
131
- reason: "git status could not be re-read before the destructive reset \u2014 the confirmed scope cannot be re-verified",
476
+ reason: `git status could not be re-read before the destructive reset \u2014 the confirmed scope cannot be re-verified${read.failure ? `. Cause: ${describeUnreadableCause(read.failure)}` : ""}`,
132
477
  newDirtyPaths: []
133
478
  };
134
479
  }
@@ -157,7 +502,7 @@ function resolveCandidates(scopeTarget, extra) {
157
502
  }
158
503
  function scopeDigest(kind, candidates) {
159
504
  const paths = candidates.map((c) => {
160
- const resolved = path.resolve(c.path);
505
+ const resolved = path2.resolve(c.path);
161
506
  if (resolved.includes("\x00") || resolved.includes(`
162
507
  `)) {
163
508
  throw new Error(`Purge candidate path contains a NUL or newline separator character and cannot be scope-bound: ${JSON.stringify(resolved)}`);
@@ -289,12 +634,12 @@ function executeDestructivePurge(scopeTarget, projectRoot, token, extra) {
289
634
 
290
635
  // src/commands/reset-backup.ts
291
636
  import * as fs2 from "fs";
292
- import * as path2 from "path";
637
+ import * as path3 from "path";
293
638
  var RESET_BACKUP_RETENTION = 5;
294
639
  function backupSwarmStateBeforeReset(directory, kind, relEntries, opts) {
295
640
  const warnings = [];
296
641
  const copied = [];
297
- const swarmDir = path2.join(directory, ".swarm");
642
+ const swarmDir = path3.join(directory, ".swarm");
298
643
  try {
299
644
  const stat = fs2.lstatSync(swarmDir);
300
645
  if (stat.isSymbolicLink() || !stat.isDirectory()) {
@@ -306,8 +651,8 @@ function backupSwarmStateBeforeReset(directory, kind, relEntries, opts) {
306
651
  return { backupDir: null, copied, warnings };
307
652
  }
308
653
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
309
- const backupsRoot = path2.join(swarmDir, opts?.backupsRoot ?? "reset-backups");
310
- const backupDir = path2.join(backupsRoot, `${kind}-${timestamp}`);
654
+ const backupsRoot = path3.join(swarmDir, opts?.backupsRoot ?? "reset-backups");
655
+ const backupDir = path3.join(backupsRoot, `${kind}-${timestamp}`);
311
656
  let backupDirCreated = false;
312
657
  const ensureBackupDir = () => {
313
658
  if (!backupDirCreated) {
@@ -327,8 +672,8 @@ function backupSwarmStateBeforeReset(directory, kind, relEntries, opts) {
327
672
  continue;
328
673
  try {
329
674
  ensureBackupDir();
330
- const dest = path2.join(backupDir, rel);
331
- fs2.mkdirSync(path2.dirname(dest), { recursive: true });
675
+ const dest = path3.join(backupDir, rel);
676
+ fs2.mkdirSync(path3.dirname(dest), { recursive: true });
332
677
  fs2.cpSync(src, dest, { recursive: true });
333
678
  copied.push(rel);
334
679
  } catch (err) {
@@ -343,7 +688,7 @@ function backupSwarmStateBeforeReset(directory, kind, relEntries, opts) {
343
688
  }
344
689
  return { backupDir: null, copied, warnings };
345
690
  }
346
- pruneOldResetBackups(backupsRoot, warnings, path2.basename(backupDir));
691
+ pruneOldResetBackups(backupsRoot, warnings, path3.basename(backupDir));
347
692
  return { backupDir, copied, warnings };
348
693
  }
349
694
  var BACKUP_KIND_PREFIXES = [
@@ -367,7 +712,7 @@ function pruneOldResetBackups(backupsRoot, warnings, keepDirName) {
367
712
  if (stale.name === keepDirName)
368
713
  continue;
369
714
  try {
370
- fs2.rmSync(path2.join(backupsRoot, stale.name), {
715
+ fs2.rmSync(path3.join(backupsRoot, stale.name), {
371
716
  recursive: true,
372
717
  force: true
373
718
  });
@@ -382,7 +727,7 @@ function pruneOldResetBackups(backupsRoot, warnings, keepDirName) {
382
727
  function backupTrackedChangesBeforeRollback(directory, repoRelPaths) {
383
728
  const warnings = [];
384
729
  const copied = [];
385
- const swarmDir = path2.join(directory, ".swarm");
730
+ const swarmDir = path3.join(directory, ".swarm");
386
731
  try {
387
732
  const stat = fs2.lstatSync(swarmDir);
388
733
  if (stat.isSymbolicLink() || !stat.isDirectory()) {
@@ -394,8 +739,8 @@ function backupTrackedChangesBeforeRollback(directory, repoRelPaths) {
394
739
  return { backupDir: null, copied, warnings };
395
740
  }
396
741
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
397
- const backupsRoot = path2.join(swarmDir, "rollback-backups");
398
- const backupDir = path2.join(backupsRoot, `rollback-git-${timestamp}`);
742
+ const backupsRoot = path3.join(swarmDir, "rollback-backups");
743
+ const backupDir = path3.join(backupsRoot, `rollback-git-${timestamp}`);
399
744
  let backupDirCreated = false;
400
745
  const ensureBackupDir = () => {
401
746
  if (!backupDirCreated) {
@@ -406,13 +751,13 @@ function backupTrackedChangesBeforeRollback(directory, repoRelPaths) {
406
751
  for (const rel of repoRelPaths) {
407
752
  if (!rel)
408
753
  continue;
409
- const src = path2.join(directory, rel);
754
+ const src = path3.join(directory, rel);
410
755
  if (!fs2.existsSync(src))
411
756
  continue;
412
757
  try {
413
758
  ensureBackupDir();
414
- const dest = path2.join(backupDir, "tracked", rel);
415
- fs2.mkdirSync(path2.dirname(dest), { recursive: true });
759
+ const dest = path3.join(backupDir, "tracked", rel);
760
+ fs2.mkdirSync(path3.dirname(dest), { recursive: true });
416
761
  fs2.cpSync(src, dest, { recursive: true });
417
762
  copied.push(rel);
418
763
  } catch (err) {
@@ -427,123 +772,10 @@ function backupTrackedChangesBeforeRollback(directory, repoRelPaths) {
427
772
  }
428
773
  return { backupDir: null, copied, warnings };
429
774
  }
430
- pruneOldResetBackups(backupsRoot, warnings, path2.basename(backupDir));
775
+ pruneOldResetBackups(backupsRoot, warnings, path3.basename(backupDir));
431
776
  return { backupDir, copied, warnings };
432
777
  }
433
778
 
434
- // src/commands/rollback-gate.ts
435
- init_git_executable();
436
- import { spawnSync as spawnSync2 } from "child_process";
437
- import * as fsSync from "fs";
438
- import * as path3 from "path";
439
- var ROLLBACK_GIT_KIND = "swarm-rollback-git";
440
- var ROLLBACK_PHASE_KIND = "swarm-rollback-phase";
441
- var GIT_STATUS_TIMEOUT_MS = 1e4;
442
- var GIT_LIST_MAX_BUFFER_BYTES = 32 * 1024 * 1024;
443
- var _rollbackGateInternals = {
444
- runGit: (args, cwd) => {
445
- const result = spawnSync2(resolveGitExecutable(), args, {
446
- cwd,
447
- encoding: "utf-8",
448
- timeout: GIT_STATUS_TIMEOUT_MS,
449
- windowsHide: true,
450
- stdio: ["ignore", "pipe", "pipe"]
451
- });
452
- if (result.error || result.status !== 0)
453
- return null;
454
- return result.stdout ?? "";
455
- },
456
- runGitBuffered: (args, cwd) => {
457
- const result = spawnSync2(resolveGitExecutable(), args, {
458
- cwd,
459
- encoding: "utf-8",
460
- timeout: GIT_STATUS_TIMEOUT_MS,
461
- windowsHide: true,
462
- maxBuffer: GIT_LIST_MAX_BUFFER_BYTES,
463
- stdio: ["ignore", "pipe", "pipe"]
464
- });
465
- if (result.error || result.status !== 0)
466
- return null;
467
- return result.stdout ?? "";
468
- }
469
- };
470
- function isRealGitRepository(directory) {
471
- try {
472
- if (fsSync.statSync(path3.join(directory, ".git")).isFile())
473
- return true;
474
- } catch {
475
- return false;
476
- }
477
- return fsSync.existsSync(path3.join(directory, ".git", "HEAD"));
478
- }
479
- function parseTrackedDirtyPaths2(statusOutput) {
480
- const dirtyPaths = [];
481
- const tokens = statusOutput.split("\x00");
482
- for (let i = 0;i < tokens.length; i += 1) {
483
- const token = tokens[i];
484
- if (token === "" || token.length < 4)
485
- continue;
486
- const xy = token.slice(0, 2);
487
- if (xy === "??")
488
- continue;
489
- const filePath = token.slice(3);
490
- if (!filePath)
491
- continue;
492
- dirtyPaths.push(filePath);
493
- if (/[RC]/.test(xy) && i + 1 < tokens.length && tokens[i + 1] !== "") {
494
- dirtyPaths.push(tokens[i + 1]);
495
- i += 1;
496
- }
497
- }
498
- return dirtyPaths;
499
- }
500
- function untrackedPathsInTargetTree(directory, targetSha) {
501
- if (!isRealGitRepository(directory))
502
- return [];
503
- const targetTree = _rollbackGateInternals.runGitBuffered(["ls-tree", "-r", "-z", "--name-only", targetSha], directory);
504
- const index = _rollbackGateInternals.runGitBuffered(["ls-files", "-z"], directory);
505
- if (targetTree === null || index === null)
506
- return [];
507
- const indexed = new Set(index.split("\x00").filter((p) => p !== ""));
508
- const inWay = [];
509
- for (const rel of targetTree.split("\x00")) {
510
- if (rel === "" || indexed.has(rel))
511
- continue;
512
- if (fsSync.existsSync(path3.join(directory, rel)))
513
- inWay.push(rel);
514
- }
515
- return inWay;
516
- }
517
- function trackedDirtyCandidates(directory, dirtyRelPaths) {
518
- return dirtyRelPaths.map((rel) => ({
519
- path: path3.join(directory, rel),
520
- reason: "uncommitted tracked change \u2014 destroyed by git reset --hard"
521
- }));
522
- }
523
- function swarmOverwriteCandidates(directory, overwriteRelPaths) {
524
- return overwriteRelPaths.map((rel) => ({
525
- path: path3.join(directory, ".swarm", rel),
526
- reason: "live .swarm state replaced by the checkpoint copy"
527
- }));
528
- }
529
- function measureGitDestruction(directory, targetSha) {
530
- if (!isRealGitRepository(directory)) {
531
- return { kind: "ok", dirtyRelPaths: [] };
532
- }
533
- const status = _rollbackGateInternals.runGit(["status", "--porcelain", "-z"], directory);
534
- if (status === null) {
535
- return { kind: "unreadable" };
536
- }
537
- const dirtyRelPaths = parseTrackedDirtyPaths2(status);
538
- if (targetSha) {
539
- for (const rel of untrackedPathsInTargetTree(directory, targetSha)) {
540
- if (!dirtyRelPaths.includes(rel))
541
- dirtyRelPaths.push(rel);
542
- }
543
- }
544
- return { kind: "ok", dirtyRelPaths };
545
- }
546
-
547
779
  // src/tools/checkpoint.ts
548
780
  init_git_executable();
549
781
 
@@ -1214,7 +1446,7 @@ async function saveCheckpointRecord(label, directory) {
1214
1446
  })
1215
1447
  });
1216
1448
  }
1217
- function handleRestore(label, directory, confirmToken) {
1449
+ async function handleRestore(label, directory, confirmToken) {
1218
1450
  try {
1219
1451
  const log2 = readCheckpointLog(directory);
1220
1452
  const checkpoint = log2.checkpoints.find((candidate) => candidate.label === label);
@@ -1224,11 +1456,12 @@ function handleRestore(label, directory, confirmToken) {
1224
1456
  error: `checkpoint not found: "${label}"`
1225
1457
  });
1226
1458
  }
1227
- const measurement = measureGitDestruction(directory, checkpoint.sha);
1459
+ const measurement = await measureGitDestruction(directory, checkpoint.sha);
1228
1460
  if (measurement.kind === "unreadable") {
1461
+ const cause = describeUnreadableCause(measurement);
1229
1462
  return serializeResult("restore", {
1230
1463
  success: false,
1231
- error: "cannot verify the working tree (git status unreadable) \u2014 refusing to restore without a preview. Retry, or inspect git status manually."
1464
+ error: `cannot verify the working tree (git status unreadable; ${cause}) \u2014 refusing to restore without a preview.`
1232
1465
  });
1233
1466
  }
1234
1467
  if (measurement.dirtyRelPaths.length > 0) {
@@ -1509,7 +1742,7 @@ var checkpoint = createSwarmTool({
1509
1742
  action: "restore",
1510
1743
  directory,
1511
1744
  operationKey: `restore-${label}`,
1512
- run: async () => handleRestore(label, directory, confirmToken)
1745
+ run: async () => await handleRestore(label, directory, confirmToken)
1513
1746
  });
1514
1747
  case "list":
1515
1748
  return handleList(directory);
@@ -1531,4 +1764,4 @@ var checkpoint = createSwarmTool({
1531
1764
  }
1532
1765
  });
1533
1766
 
1534
- export { MAX_TRANSIENT_RETRIES, isTransientSpawnError, transientBackoff, GIT_STATUS_ARGS, parseTrackedDirtyPaths, recheckBeforeDestructive, previewDestructivePurge, issueConfirmToken, consumeConfirmToken, executeDestructivePurge, backupSwarmStateBeforeReset, ROLLBACK_GIT_KIND, ROLLBACK_PHASE_KIND, trackedDirtyCandidates, swarmOverwriteCandidates, measureGitDestruction, resolveWorkingDirectory, createSwarmTool, _internals2 as _internals, saveCheckpointRecord, checkpoint };
1767
+ export { MAX_TRANSIENT_RETRIES, isTransientSpawnError, transientBackoff, gitStatusReadInternals, readGitStatusAsync, readGitRepositoryStatusAsync, ROLLBACK_GIT_KIND, ROLLBACK_PHASE_KIND, trackedDirtyCandidates, swarmOverwriteCandidates, describeUnreadableCause, measureGitDestruction, GIT_STATUS_ARGS, parseTrackedDirtyPaths2 as parseTrackedDirtyPaths, recheckBeforeDestructive, previewDestructivePurge, issueConfirmToken, consumeConfirmToken, executeDestructivePurge, backupSwarmStateBeforeReset, resolveWorkingDirectory, createSwarmTool, _internals2 as _internals, saveCheckpointRecord, checkpoint };