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.
- package/.opencode/skills/swarm-pr-feedback/references/followup-dispositions.md +1 -0
- package/.opencode/skills/swarm-pr-review/SKILL.md +3 -3
- package/binaries/win32-arm64/swarm-sandbox-runner.exe +0 -0
- package/binaries/win32-x64/swarm-sandbox-runner.exe +0 -0
- package/dist/agents/architect.d.ts +1 -1
- package/dist/background/pending-delegations.d.ts +46 -0
- package/dist/cli/{auto-checkpoint-8sxq4fam.js → auto-checkpoint-tje4xvtw.js} +12 -11
- package/dist/cli/{checkpoint-septjh9j.js → checkpoint-wyh8nkhb.js} +21 -21
- package/dist/cli/{coder-settlement-5e51gv83.js → coder-settlement-d0ca5fb3.js} +18 -18
- package/dist/cli/{config-doctor-szqpesb3.js → config-doctor-swg02esj.js} +19 -19
- package/dist/cli/{core-wawy5vxa.js → core-yh8ae69m.js} +7 -7
- package/dist/cli/{curation-policy-0smbd33w.js → curation-policy-w9y0db1n.js} +8 -8
- package/dist/cli/{curator-s699p3wr.js → curator-9vzqhesg.js} +51 -51
- package/dist/cli/{curator-drift-p4xkfxm3.js → curator-drift-85qect05.js} +12 -12
- package/dist/cli/curator-llm-factory-dwvftpvm.js +82 -0
- package/dist/cli/{dispatch-1pbmmj8z.js → dispatch-sftetpzv.js} +4 -4
- package/dist/cli/{doctor-knowledge-receipt-phase-id-xcczpaad.js → doctor-knowledge-receipt-phase-id-eqzsh3b7.js} +12 -12
- package/dist/cli/{evidence-summary-service-smwfa1sk.js → evidence-summary-service-hc513kyq.js} +27 -27
- package/dist/cli/{gate-evidence-y1591qqg.js → gate-evidence-a10epye0.js} +13 -13
- package/dist/cli/guardrail-explain-rqqhmb44.js +83 -0
- package/dist/cli/guardrail-log-caspzygc.js +23 -0
- package/dist/cli/{guardrail-reset-fq7tby85.js → guardrail-reset-48r2n8mz.js} +51 -51
- package/dist/cli/hive-promoter-sd3a61mq.js +97 -0
- package/dist/cli/{index-zh3fxcnn.js → index-0aj9tvms.js} +51 -51
- package/dist/cli/{index-dyp5807d.js → index-0je0mees.js} +10 -8
- package/dist/cli/{index-2a8xvtba.js → index-0ra0vs2p.js} +13 -11
- package/dist/cli/{index-2mx2gn97.js → index-0veqvgny.js} +1 -1
- package/dist/cli/{index-j1kcy808.js → index-10wwrgj2.js} +6 -6
- package/dist/cli/{index-c36fnjz3.js → index-26dmsdx3.js} +4884 -5746
- package/dist/cli/{index-ywb5er8g.js → index-270zfq1f.js} +2 -2
- package/dist/cli/{index-krz83azd.js → index-34jat4f2.js} +2 -2
- package/dist/cli/{index-dgtvf04w.js → index-3ckvw3j2.js} +2 -2
- package/dist/cli/{index-wamvtpcn.js → index-3fz5w2wb.js} +15 -6
- package/dist/cli/{index-h349p91m.js → index-3mzc5rqc.js} +2 -2
- package/dist/cli/{index-bkscmz4z.js → index-4cyc18bc.js} +11 -11
- package/dist/cli/{index-wer76f2n.js → index-4pbzepgw.js} +1645 -124
- package/dist/cli/{index-7vzvj8ry.js → index-6ssraqaa.js} +15 -11
- package/dist/cli/{index-s7ftr7ka.js → index-6xv2hz0e.js} +5 -5
- package/dist/cli/{index-qy55ytz4.js → index-6xyt6d5m.js} +13 -13
- package/dist/cli/{index-ddq1vt2f.js → index-76skvj8z.js} +7 -7
- package/dist/cli/{index-2zwk30cc.js → index-85vd6sxy.js} +10 -10
- package/dist/cli/{index-68k5agm2.js → index-9c0vp5yj.js} +2 -2
- package/dist/cli/{index-36anctab.js → index-9n40q82y.js} +4 -4
- package/dist/cli/{index-nr1pj3hy.js → index-9y6yk1n0.js} +1 -1
- package/dist/cli/{index-j2vv0h13.js → index-axqyjreb.js} +6 -4
- package/dist/cli/{index-eh27whw4.js → index-b0kr8720.js} +53 -53
- package/dist/cli/{index-820pzqd6.js → index-b3ws03kp.js} +7 -5
- package/dist/cli/{index-dp7362hg.js → index-bgydmx8k.js} +11 -11
- package/dist/cli/{index-r0mapyst.js → index-d7y3cafq.js} +5 -5
- package/dist/cli/{index-5p1md309.js → index-dengtwpp.js} +5 -4
- package/dist/cli/{index-6dtt0brw.js → index-dtwj4hsk.js} +4 -4
- package/dist/cli/{index-4s6kdsfr.js → index-dz15f98h.js} +1 -1
- package/dist/cli/{index-fnqk017s.js → index-esakwcr3.js} +1 -1
- package/dist/cli/{index-hz2609qt.js → index-eyq1q1xn.js} +9 -7
- package/dist/cli/{index-5jp79fag.js → index-gyz59cbh.js} +25 -21
- package/dist/cli/{index-7c432abn.js → index-hx2f3j9w.js} +2 -2
- package/dist/cli/{index-p5pgjp7n.js → index-j3rfbs45.js} +1 -1
- package/dist/cli/{index-w7d8gcj0.js → index-jmhn6ab5.js} +2 -2
- package/dist/cli/{index-sn3z9bq2.js → index-my753e0g.js} +21 -17
- package/dist/cli/{index-2bc7zfw3.js → index-n1ddn12j.js} +2 -2
- package/dist/cli/{index-w4dbmngb.js → index-p5d32v0x.js} +11 -11
- package/dist/cli/{index-2s7dvzff.js → index-qbxk2rn6.js} +42 -41
- package/dist/cli/{index-w00dj8p5.js → index-snx2vb1x.js} +2 -2
- package/dist/cli/{index-zxdawwc7.js → index-sp2cxpaq.js} +131 -8
- package/dist/cli/{index-g4fs6z4e.js → index-spggmr30.js} +6 -2
- package/dist/cli/{index-pxdc0qn1.js → index-tsg61z0r.js} +2 -2
- package/dist/cli/{index-5c6h1d0s.js → index-v4mremxw.js} +6 -5
- package/dist/cli/{index-cjapb4hy.js → index-x5jwegqw.js} +7 -5
- package/dist/cli/{index-4925h28w.js → index-xtda4xsn.js} +403 -170
- package/dist/cli/{index-2acc95ec.js → index-xyg7des8.js} +4 -4
- package/dist/cli/{index-ccpxq4yh.js → index-ybvnf7rt.js} +8 -8
- package/dist/cli/{index-r7swzftd.js → index-yg5xd4am.js} +18 -16
- package/dist/cli/{index-hc6wa3yg.js → index-zbygz217.js} +3 -3
- package/dist/cli/{index-yvjpwsrd.js → index-zdfzrwbk.js} +7 -7
- package/dist/cli/{index-vdhr11qv.js → index-zte3djpf.js} +2 -2
- package/dist/cli/index.js +52 -52
- package/dist/cli/{knowledge-escalator-ebvnynz8.js → knowledge-escalator-9wqe0m8j.js} +18 -18
- package/dist/cli/{knowledge-events-crh7ax0w.js → knowledge-events-m5vdchaa.js} +16 -16
- package/dist/cli/{knowledge-link-1f91bzcc.js → knowledge-link-t0ce3mw7.js} +7 -7
- package/dist/cli/{knowledge-store-58rh7jbp.js → knowledge-store-ff4hy057.js} +8 -8
- package/dist/cli/{knowledge-validator-0vmhxf5s.js → knowledge-validator-erj5thtq.js} +10 -10
- package/dist/cli/{mcp-kjatmx4e.js → mcp-d0hz5gfp.js} +1 -1
- package/dist/cli/{model-preflight-0c7xkq6x.js → model-preflight-p34x0k25.js} +51 -51
- package/dist/cli/{pending-delegations-j8g6zmnx.js → pending-delegations-1j6dx1mf.js} +18 -15
- package/dist/cli/{pr-subscriptions-5zfjmma9.js → pr-subscriptions-b1g41jce.js} +15 -15
- package/dist/cli/{pr-workflow-gate-y0yfj38r.js → pr-workflow-gate-zjwt050h.js} +59 -59
- package/dist/cli/{runner-7sd43gan.js → runner-wq954cda.js} +9 -9
- package/dist/cli/{scan-cursor-gegs7kjt.js → scan-cursor-enz1rp21.js} +11 -10
- package/dist/cli/{schema-znqyq1kp.js → schema-9r8sggpb.js} +1 -1
- package/dist/cli/{scope-persistence-sx4qgy4b.js → scope-persistence-c5n4g9f0.js} +20 -19
- package/dist/cli/{server-rbknas06.js → server-8z7pd66d.js} +56 -56
- package/dist/cli/{skill-generator-gtg3yenw.js → skill-generator-nezzfa0t.js} +20 -20
- package/dist/cli/{snapshot-coordination-init-a0tt6s4t.js → snapshot-coordination-init-2j06c7ck.js} +51 -51
- package/dist/cli/{speckit-checkoff-gqcw669v.js → speckit-checkoff-805cqmrf.js} +7 -6
- package/dist/cli/{telemetry-6yv06xyz.js → telemetry-gena5typ.js} +3 -3
- package/dist/cli/{workspace-snapshot-4zfj5wnd.js → workspace-snapshot-hzhz0rxw.js} +7 -7
- package/dist/cli/{worktree-collision-ownership-6qwxygnn.js → worktree-collision-ownership-xpr0yv7h.js} +22 -21
- package/dist/cli/{worktree-isolation-6sc66ka0.js → worktree-isolation-z6ytes0j.js} +51 -51
- package/dist/commands/close/dry-run.d.ts +2 -1
- package/dist/commands/close/orchestrator.d.ts +16 -5
- package/dist/commands/destructive-purge.d.ts +53 -12
- package/dist/commands/git-status-read.d.ts +76 -0
- package/dist/commands/rollback-gate.d.ts +24 -5
- package/dist/config/schema.d.ts +5 -3
- package/dist/evaluation/contracts.d.ts +5 -5
- package/dist/hooks/lane-liveness-watchdog.d.ts +6 -1
- package/dist/hooks/pr-workflow-gate.d.ts +61 -1
- package/dist/index.js +254 -252
- package/dist/memory/schema.d.ts +3 -3
- package/dist/pr-review/completion.d.ts +63 -2
- package/dist/services/diagnose-service.d.ts +7 -8
- package/dist/tools/dispatch-lanes.d.ts +2 -1
- package/dist/utils/git-executable.d.ts +4 -0
- package/opencode-swarm.schema.json +3 -2
- package/package.json +1 -1
- package/dist/cli/curator-llm-factory-m6w5axpg.js +0 -82
- package/dist/cli/guardrail-explain-1fvbaenr.js +0 -83
- package/dist/cli/guardrail-log-nd644x5c.js +0 -23
- package/dist/cli/hive-promoter-bhnm4sf7.js +0 -97
- 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-
|
|
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-
|
|
17
|
+
} from "./index-spggmr30.js";
|
|
18
18
|
import {
|
|
19
19
|
validateSwarmPath
|
|
20
|
-
} from "./index-
|
|
20
|
+
} from "./index-b3ws03kp.js";
|
|
21
21
|
import {
|
|
22
22
|
readLedgerEvents
|
|
23
|
-
} from "./index-
|
|
23
|
+
} from "./index-ybvnf7rt.js";
|
|
24
24
|
import {
|
|
25
25
|
appendCoreEventSync
|
|
26
|
-
} from "./index-
|
|
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-
|
|
41
|
+
} from "./index-270zfq1f.js";
|
|
42
42
|
import {
|
|
43
43
|
loadPluginConfigWithMeta
|
|
44
|
-
} from "./index-
|
|
44
|
+
} from "./index-3ckvw3j2.js";
|
|
45
45
|
import {
|
|
46
46
|
init_git_executable,
|
|
47
|
-
resolveGitExecutable
|
|
48
|
-
|
|
47
|
+
resolveGitExecutable,
|
|
48
|
+
resolveGitExecutableAsync
|
|
49
|
+
} from "./index-sp2cxpaq.js";
|
|
49
50
|
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} from "./index-
|
|
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
|
|
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:
|
|
421
|
+
runGitStatus: (args, cwd) => readGitStatusAsync(args, cwd)
|
|
82
422
|
};
|
|
83
|
-
var GIT_STATUS_ARGS = [
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
122
|
-
if (
|
|
463
|
+
async function readTrackedDirtyPaths(directory) {
|
|
464
|
+
const read = await runGitStatusRead(GIT_STATUS_ARGS, directory);
|
|
465
|
+
if (read === null)
|
|
123
466
|
return { ok: false };
|
|
124
|
-
|
|
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:
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
310
|
-
const backupDir =
|
|
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 =
|
|
331
|
-
fs2.mkdirSync(
|
|
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,
|
|
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(
|
|
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 =
|
|
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 =
|
|
398
|
-
const backupDir =
|
|
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 =
|
|
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 =
|
|
415
|
-
fs2.mkdirSync(
|
|
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,
|
|
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:
|
|
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,
|
|
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 };
|