opencode-swarm 7.86.0 → 7.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/cli/{capability-probe-jevmgwmf.js → capability-probe-wsjzcp48.js} +2 -2
  2. package/dist/cli/{config-doctor-zejarrr6.js → config-doctor-6h64pn8n.js} +4 -4
  3. package/dist/cli/{dispatch-k86d928w.js → dispatch-kb69qw40.js} +3 -3
  4. package/dist/cli/{evidence-summary-service-g2znnd33.js → evidence-summary-service-gg5m9z57.js} +4 -4
  5. package/dist/cli/{guardrail-explain-rtd1x26f.js → guardrail-explain-wb1cj312.js} +13 -13
  6. package/dist/cli/{guardrail-log-80116wmz.js → guardrail-log-eegabqcp.js} +5 -5
  7. package/dist/cli/{index-jwz50183.js → index-0m44n5qv.js} +14 -14
  8. package/dist/cli/{index-0sxvwjt0.js → index-1cb4wxnm.js} +2 -2
  9. package/dist/cli/{index-zfsbaaqh.js → index-5e4e2hvv.js} +1 -1
  10. package/dist/cli/{index-vq2321gg.js → index-5hvbw5xh.js} +2 -2
  11. package/dist/cli/{index-5cb86007.js → index-5vpe6vq9.js} +1 -1
  12. package/dist/cli/{index-red8fm8p.js → index-89xjr3h4.js} +1162 -214
  13. package/dist/cli/{index-f8r50m3h.js → index-adz3nk9b.js} +2 -2
  14. package/dist/cli/{index-7r2b453y.js → index-f13d3b69.js} +2 -2
  15. package/dist/cli/{index-ckntc5gf.js → index-gn8n22th.js} +2 -2
  16. package/dist/cli/{index-hw9b2xng.js → index-q9h0wb04.js} +36 -3
  17. package/dist/cli/{index-d9fbxaqd.js → index-s8bj492g.js} +1 -1
  18. package/dist/cli/{index-hz59hg4h.js → index-v4fcn4tr.js} +1 -1
  19. package/dist/cli/{index-eb85wtx9.js → index-vqyfscxd.js} +2 -2
  20. package/dist/cli/{index-5q66xc88.js → index-wv2yj8ka.js} +2598 -1406
  21. package/dist/cli/{index-yx44zd0p.js → index-zgwm4ryv.js} +9 -1
  22. package/dist/cli/index.js +12 -12
  23. package/dist/cli/{pending-delegations-rd40tv9s.js → pending-delegations-35fvcj7z.js} +3 -3
  24. package/dist/cli/{pr-subscriptions-y1nn36e5.js → pr-subscriptions-b18n1yd8.js} +4 -4
  25. package/dist/cli/{schema-8d32b2v6.js → schema-84146tvk.js} +3 -1
  26. package/dist/cli/{skill-generator-a5ehggyg.js → skill-generator-3pvpk4y2.js} +2 -2
  27. package/dist/commands/coupling.d.ts +36 -0
  28. package/dist/commands/epic.d.ts +52 -0
  29. package/dist/commands/registry.d.ts +18 -2
  30. package/dist/config/constants.d.ts +1 -0
  31. package/dist/config/schema.d.ts +145 -0
  32. package/dist/git/branch.d.ts +22 -1
  33. package/dist/hooks/delegation-gate/worktree-merge-status.d.ts +86 -0
  34. package/dist/index.js +8401 -5792
  35. package/dist/memory/schema.d.ts +3 -3
  36. package/dist/plan/manager.d.ts +10 -0
  37. package/dist/state.d.ts +16 -0
  38. package/dist/tools/epic-plan-waves.d.ts +79 -0
  39. package/dist/tools/epic-record-divergence.d.ts +73 -0
  40. package/dist/tools/epic-run-phase.d.ts +179 -0
  41. package/dist/tools/index.d.ts +3 -0
  42. package/dist/tools/manifest.d.ts +3 -0
  43. package/dist/tools/tool-metadata.d.ts +12 -0
  44. package/dist/turbo/epic/activation.d.ts +193 -0
  45. package/dist/turbo/epic/calibration-engine.d.ts +88 -0
  46. package/dist/turbo/epic/calibration.d.ts +65 -0
  47. package/dist/turbo/epic/cochange-conflict.d.ts +79 -0
  48. package/dist/turbo/epic/cochange-source.d.ts +80 -0
  49. package/dist/turbo/epic/coupling-report.d.ts +85 -0
  50. package/dist/turbo/epic/divergence-recorder.d.ts +112 -0
  51. package/dist/turbo/epic/index.d.ts +24 -0
  52. package/dist/turbo/epic/promotion-evidence.d.ts +42 -0
  53. package/dist/turbo/epic/state.d.ts +85 -0
  54. package/dist/turbo/epic/task-commit.d.ts +110 -0
  55. package/dist/turbo/epic/upstream-commits.d.ts +82 -0
  56. package/dist/turbo/epic/wave-planner.d.ts +83 -0
  57. package/dist/turbo/lean/partition-common.d.ts +85 -0
  58. package/dist/turbo/lean/planner.d.ts +12 -20
  59. package/dist/utils/index.d.ts +1 -1
  60. package/dist/utils/logger.d.ts +19 -0
  61. package/package.json +1 -1
@@ -8,13 +8,16 @@ import {
8
8
  import {
9
9
  readSwarmFileAsync,
10
10
  validateSwarmPath
11
- } from "./index-ckntc5gf.js";
11
+ } from "./index-gn8n22th.js";
12
12
  import {
13
13
  readCachedParsedFile
14
14
  } from "./index-jtqkh8jf.js";
15
15
  import {
16
+ criticalWarn,
17
+ error,
18
+ init_logger,
16
19
  warn
17
- } from "./index-yx44zd0p.js";
20
+ } from "./index-zgwm4ryv.js";
18
21
  import {
19
22
  withEvidenceLock
20
23
  } from "./index-bcp79s17.js";
@@ -33,13 +36,13 @@ import {
33
36
  // src/plan/manager.ts
34
37
  import {
35
38
  copyFileSync,
36
- existsSync as existsSync3,
39
+ existsSync as existsSync6,
37
40
  readdirSync as readdirSync2,
38
- renameSync as renameSync3,
39
- unlinkSync
41
+ renameSync as renameSync5,
42
+ unlinkSync as unlinkSync3
40
43
  } from "fs";
41
44
  import * as fsPromises from "fs/promises";
42
- import * as path3 from "path";
45
+ import * as path6 from "path";
43
46
 
44
47
  // src/config/plan-schema.ts
45
48
  var ExecutionProfileSchema = exports_external.object({
@@ -102,13 +105,953 @@ var PlanSchema = exports_external.object({
102
105
  execution_profile: ExecutionProfileSchema.optional()
103
106
  });
104
107
 
108
+ // src/git/branch.ts
109
+ import * as child_process from "child_process";
110
+ import path from "path";
111
+
112
+ // src/utils/git-binary-missing-error.ts
113
+ class GitBinaryMissingError extends Error {
114
+ name = "GitBinaryMissingError";
115
+ constructor(message = "git binary is not available", options) {
116
+ super(message, options);
117
+ }
118
+ }
119
+ function isGitBinaryMissing(err) {
120
+ return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
121
+ }
122
+
123
+ // src/git/branch.ts
124
+ init_logger();
125
+ var GIT_TIMEOUT_MS = 30000;
126
+ var GIT_MAX_BUFFER_BYTES = 5 * 1024 * 1024;
127
+ function unique(values) {
128
+ return [...new Set(values.filter(Boolean))];
129
+ }
130
+ function windowsGitCandidates() {
131
+ if (process.platform !== "win32")
132
+ return ["git"];
133
+ const roots = unique([
134
+ process.env.ProgramFiles ?? "",
135
+ process.env["ProgramFiles(x86)"] ?? "",
136
+ process.env.LOCALAPPDATA ? path.join(process.env.LOCALAPPDATA, "Programs") : ""
137
+ ]);
138
+ const installed = roots.flatMap((root) => [
139
+ path.join(root, "Git", "cmd", "git.exe"),
140
+ path.join(root, "Git", "bin", "git.exe")
141
+ ]);
142
+ return unique(["git", ...installed]);
143
+ }
144
+ function errorMessage(err) {
145
+ return err instanceof Error ? err.message : String(err);
146
+ }
147
+ function isNotGitRepositoryMessage(message) {
148
+ const lower = message.toLowerCase();
149
+ return lower.includes("not a git repository") || lower.includes("not a git repo");
150
+ }
151
+ function gitExec(args, cwd) {
152
+ let missingGitError;
153
+ const subcommand = args[0];
154
+ const hardenedArgs = subcommand === "commit" || subcommand === "tag" ? ["-c", "commit.gpgsign=false", "-c", "tag.gpgsign=false", ...args] : args;
155
+ for (const command of windowsGitCandidates()) {
156
+ const result = child_process.spawnSync(command, hardenedArgs, {
157
+ cwd,
158
+ encoding: "utf-8",
159
+ timeout: GIT_TIMEOUT_MS,
160
+ windowsHide: true,
161
+ maxBuffer: GIT_MAX_BUFFER_BYTES,
162
+ stdio: ["ignore", "pipe", "pipe"],
163
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }
164
+ });
165
+ if (result.error) {
166
+ if (isGitBinaryMissing(result.error)) {
167
+ missingGitError ??= result.error;
168
+ continue;
169
+ }
170
+ throw new Error(errorMessage(result.error));
171
+ }
172
+ if (result.status !== 0) {
173
+ throw new Error(result.stderr || result.stdout || `git exited with ${result.status}`);
174
+ }
175
+ return result.stdout;
176
+ }
177
+ throw new GitBinaryMissingError(process.platform === "win32" ? "git executable is not available on PATH or common Windows install locations" : "git executable is not available on PATH", { cause: missingGitError });
178
+ }
179
+ function getGitRepositoryStatus(cwd) {
180
+ try {
181
+ gitExec(["rev-parse", "--git-dir"], cwd);
182
+ return { isRepo: true };
183
+ } catch (err) {
184
+ if (err instanceof GitBinaryMissingError) {
185
+ return {
186
+ isRepo: false,
187
+ reason: "git_unavailable",
188
+ message: err.message
189
+ };
190
+ }
191
+ const message = errorMessage(err);
192
+ return {
193
+ isRepo: false,
194
+ reason: isNotGitRepositoryMessage(message) ? "not_git_repo" : "git_error",
195
+ message
196
+ };
197
+ }
198
+ }
199
+ function isGitRepo(cwd) {
200
+ return getGitRepositoryStatus(cwd).isRepo;
201
+ }
202
+ function getCurrentBranch(cwd) {
203
+ const output = gitExec(["rev-parse", "--abbrev-ref", "HEAD"], cwd);
204
+ return output.trim();
205
+ }
206
+ function getDefaultBaseBranch(cwd) {
207
+ try {
208
+ gitExec(["rev-parse", "--verify", "origin/main"], cwd);
209
+ return "origin/main";
210
+ } catch {
211
+ try {
212
+ gitExec(["rev-parse", "--verify", "origin/master"], cwd);
213
+ return "origin/master";
214
+ } catch {
215
+ return "origin/main";
216
+ }
217
+ }
218
+ }
219
+ function hasUncommittedChanges(cwd) {
220
+ const status = gitExec(["status", "--porcelain"], cwd);
221
+ return status.trim().length > 0;
222
+ }
223
+ function detectDefaultRemoteBranch(cwd) {
224
+ try {
225
+ const output = gitExec(["symbolic-ref", "refs/remotes/origin/HEAD"], cwd);
226
+ const trimmed = output.trim();
227
+ if (trimmed.startsWith("refs/remotes/origin/")) {
228
+ return trimmed.slice("refs/remotes/origin/".length);
229
+ }
230
+ } catch {}
231
+ try {
232
+ const output = gitExec(["config", "init.defaultBranch"], cwd);
233
+ const branch = output.trim();
234
+ if (branch) {
235
+ return branch;
236
+ }
237
+ } catch {}
238
+ try {
239
+ gitExec(["rev-parse", "--verify", "origin/main"], cwd);
240
+ return "main";
241
+ } catch {}
242
+ try {
243
+ gitExec(["rev-parse", "--verify", "origin/master"], cwd);
244
+ return "master";
245
+ } catch {
246
+ return null;
247
+ }
248
+ }
249
+ async function resetToRemoteBranch(cwd, options) {
250
+ const warnings = [];
251
+ const prunedBranches = [];
252
+ try {
253
+ const currentBranch = getCurrentBranch(cwd);
254
+ const defaultRemoteBranch = _internals.detectDefaultRemoteBranch(cwd);
255
+ if (!defaultRemoteBranch) {
256
+ return {
257
+ success: false,
258
+ targetBranch: "",
259
+ localBranch: currentBranch,
260
+ message: "Could not detect default remote branch",
261
+ alreadyAligned: false,
262
+ prunedBranches: [],
263
+ warnings: []
264
+ };
265
+ }
266
+ const targetBranch = `origin/${defaultRemoteBranch}`;
267
+ if (currentBranch === "HEAD") {
268
+ return {
269
+ success: false,
270
+ targetBranch,
271
+ localBranch: "HEAD",
272
+ message: "Cannot reset: detached HEAD state",
273
+ alreadyAligned: false,
274
+ prunedBranches: [],
275
+ warnings: []
276
+ };
277
+ }
278
+ if (hasUncommittedChanges(cwd)) {
279
+ return {
280
+ success: false,
281
+ targetBranch,
282
+ localBranch: currentBranch,
283
+ message: "Cannot reset: uncommitted changes in working tree",
284
+ alreadyAligned: false,
285
+ prunedBranches: [],
286
+ warnings: []
287
+ };
288
+ }
289
+ try {
290
+ const logOutput = gitExec(["log", `${targetBranch}..HEAD`, "--oneline"], cwd);
291
+ if (logOutput.trim().length > 0) {
292
+ return {
293
+ success: false,
294
+ targetBranch,
295
+ localBranch: currentBranch,
296
+ message: "Cannot reset: unpushed commits",
297
+ alreadyAligned: false,
298
+ prunedBranches: [],
299
+ warnings: []
300
+ };
301
+ }
302
+ } catch {}
303
+ try {
304
+ gitExec(["fetch", "--prune", "origin"], cwd);
305
+ } catch (err) {
306
+ return {
307
+ success: false,
308
+ targetBranch,
309
+ localBranch: currentBranch,
310
+ message: `Fetch failed: ${err instanceof Error ? err.message : String(err)}`,
311
+ alreadyAligned: false,
312
+ prunedBranches: [],
313
+ warnings: []
314
+ };
315
+ }
316
+ const headSha = gitExec(["rev-parse", "HEAD"], cwd).trim();
317
+ const remoteSha = gitExec(["rev-parse", `${targetBranch}`], cwd).trim();
318
+ if (headSha === remoteSha) {
319
+ return {
320
+ success: true,
321
+ targetBranch,
322
+ localBranch: currentBranch,
323
+ message: "Already aligned with remote",
324
+ alreadyAligned: true,
325
+ prunedBranches: [],
326
+ warnings: []
327
+ };
328
+ }
329
+ try {
330
+ gitExec(["checkout", currentBranch], cwd);
331
+ } catch (err) {
332
+ return {
333
+ success: false,
334
+ targetBranch,
335
+ localBranch: currentBranch,
336
+ message: `Checkout failed: ${err instanceof Error ? err.message : String(err)}`,
337
+ alreadyAligned: false,
338
+ prunedBranches: [],
339
+ warnings: []
340
+ };
341
+ }
342
+ let resetSucceeded = false;
343
+ let lastError;
344
+ for (let retry = 0;retry < 4; retry++) {
345
+ if (retry > 0 && process.platform === "win32") {
346
+ await new Promise((resolve) => setTimeout(resolve, 500));
347
+ }
348
+ try {
349
+ gitExec(["reset", "--hard", targetBranch], cwd);
350
+ resetSucceeded = true;
351
+ break;
352
+ } catch (err) {
353
+ lastError = err;
354
+ }
355
+ }
356
+ if (!resetSucceeded) {
357
+ return {
358
+ success: false,
359
+ targetBranch,
360
+ localBranch: currentBranch,
361
+ message: `Reset failed: ${lastError instanceof Error ? lastError.message : String(lastError)}`,
362
+ alreadyAligned: false,
363
+ prunedBranches: [],
364
+ warnings: []
365
+ };
366
+ }
367
+ if (options?.pruneBranches) {
368
+ try {
369
+ const mergedOutput = gitExec(["branch", "--merged", targetBranch], cwd);
370
+ const mergedLines = mergedOutput.split(`
371
+ `);
372
+ for (const line of mergedLines) {
373
+ const trimmedLine = line.trim();
374
+ if (!trimmedLine || trimmedLine.startsWith("*")) {
375
+ continue;
376
+ }
377
+ try {
378
+ gitExec(["branch", "-d", trimmedLine], cwd);
379
+ prunedBranches.push(trimmedLine);
380
+ } catch {
381
+ warnings.push(`Could not safely delete branch: ${trimmedLine}`);
382
+ }
383
+ }
384
+ } catch (err) {
385
+ warnings.push(`Failed to get merged branches: ${err instanceof Error ? err.message : String(err)}`);
386
+ }
387
+ try {
388
+ const branchVvOutput = gitExec(["branch", "-vv"], cwd);
389
+ const vvLines = branchVvOutput.split(`
390
+ `);
391
+ for (const line of vvLines) {
392
+ const trimmedLine = line.trim();
393
+ if (!trimmedLine || trimmedLine.startsWith("*")) {
394
+ continue;
395
+ }
396
+ if (trimmedLine.includes(": gone]")) {
397
+ const parts = trimmedLine.split(/\s+/);
398
+ const branchName = parts[0];
399
+ try {
400
+ gitExec(["branch", "-d", branchName], cwd);
401
+ prunedBranches.push(branchName);
402
+ } catch {
403
+ warnings.push(`Could not delete gone branch: ${branchName}`);
404
+ }
405
+ }
406
+ }
407
+ } catch (err) {
408
+ warnings.push(`Failed to prune gone branches: ${err instanceof Error ? err.message : String(err)}`);
409
+ }
410
+ }
411
+ return {
412
+ success: true,
413
+ targetBranch,
414
+ localBranch: currentBranch,
415
+ message: "Successfully reset to remote branch",
416
+ alreadyAligned: false,
417
+ prunedBranches,
418
+ warnings
419
+ };
420
+ } catch (err) {
421
+ return {
422
+ success: false,
423
+ targetBranch: "",
424
+ localBranch: "",
425
+ message: `Unexpected error: ${err instanceof Error ? err.message : String(err)}`,
426
+ alreadyAligned: false,
427
+ prunedBranches: [],
428
+ warnings: []
429
+ };
430
+ }
431
+ }
432
+ async function resetToMainAfterMerge(cwd, options) {
433
+ const warnings = [];
434
+ try {
435
+ const defaultBranch = _internals.detectDefaultRemoteBranch(cwd);
436
+ if (!defaultBranch) {
437
+ return {
438
+ success: false,
439
+ targetBranch: "",
440
+ previousBranch: "",
441
+ message: "Could not detect default remote branch",
442
+ branchDeleted: false,
443
+ changesDiscarded: false,
444
+ warnings
445
+ };
446
+ }
447
+ const currentBranch = getCurrentBranch(cwd);
448
+ const targetBranch = `origin/${defaultBranch}`;
449
+ if (currentBranch === "HEAD") {
450
+ return {
451
+ success: false,
452
+ targetBranch,
453
+ previousBranch: "HEAD",
454
+ message: "Cannot reset: detached HEAD state",
455
+ branchDeleted: false,
456
+ changesDiscarded: false,
457
+ warnings
458
+ };
459
+ }
460
+ if (currentBranch === defaultBranch) {
461
+ try {
462
+ const logOutput = _internals.gitExec(["log", `${targetBranch}..HEAD`, "--oneline"], cwd);
463
+ if (logOutput.trim().length > 0) {
464
+ return {
465
+ success: false,
466
+ targetBranch,
467
+ previousBranch: currentBranch,
468
+ message: `Cannot reset: ${defaultBranch} has unpushed commits. Push them first.`,
469
+ branchDeleted: false,
470
+ changesDiscarded: false,
471
+ warnings
472
+ };
473
+ }
474
+ } catch {}
475
+ } else {
476
+ try {
477
+ _internals.gitExec(["rev-parse", "--abbrev-ref", `${currentBranch}@{upstream}`], cwd);
478
+ } catch {
479
+ try {
480
+ const localSha = _internals.gitExec(["rev-parse", "HEAD"], cwd).trim();
481
+ const remoteSha = _internals.gitExec(["rev-parse", targetBranch], cwd).trim();
482
+ if (localSha !== remoteSha) {
483
+ return {
484
+ success: false,
485
+ targetBranch,
486
+ previousBranch: currentBranch,
487
+ message: `Cannot reset: branch ${currentBranch} is local-only and diverges from ${defaultBranch}. Push or check manually.`,
488
+ branchDeleted: false,
489
+ changesDiscarded: false,
490
+ warnings
491
+ };
492
+ }
493
+ } catch {
494
+ return {
495
+ success: false,
496
+ targetBranch,
497
+ previousBranch: currentBranch,
498
+ message: `Cannot reset: unable to compare ${currentBranch} with ${defaultBranch}`,
499
+ branchDeleted: false,
500
+ changesDiscarded: false,
501
+ warnings
502
+ };
503
+ }
504
+ }
505
+ }
506
+ try {
507
+ _internals.gitExec(["fetch", "--prune", "origin"], cwd);
508
+ } catch (err) {
509
+ return {
510
+ success: false,
511
+ targetBranch,
512
+ previousBranch: currentBranch,
513
+ message: `Cannot reset: fetch failed \u2014 ${err instanceof Error ? err.message : String(err)}`,
514
+ branchDeleted: false,
515
+ changesDiscarded: false,
516
+ warnings
517
+ };
518
+ }
519
+ const previousBranch = currentBranch;
520
+ let switchedBranch = false;
521
+ if (currentBranch !== defaultBranch) {
522
+ try {
523
+ _internals.gitExec(["checkout", defaultBranch], cwd);
524
+ switchedBranch = true;
525
+ } catch (err) {
526
+ return {
527
+ success: false,
528
+ targetBranch,
529
+ previousBranch,
530
+ message: `Checkout to ${defaultBranch} failed: ${err instanceof Error ? err.message : String(err)}`,
531
+ branchDeleted: false,
532
+ changesDiscarded: false,
533
+ warnings
534
+ };
535
+ }
536
+ }
537
+ try {
538
+ _internals.gitExec(["reset", "--hard", targetBranch], cwd);
539
+ } catch (err) {
540
+ return {
541
+ success: false,
542
+ targetBranch,
543
+ previousBranch,
544
+ message: `Reset to ${targetBranch} failed: ${err instanceof Error ? err.message : String(err)}`,
545
+ branchDeleted: false,
546
+ changesDiscarded: false,
547
+ warnings
548
+ };
549
+ }
550
+ let changesDiscarded = false;
551
+ if (hasUncommittedChanges(cwd)) {
552
+ let discardSucceeded = false;
553
+ for (let retry = 0;retry < 4; retry++) {
554
+ if (retry > 0 && process.platform === "win32") {
555
+ await new Promise((resolve) => setTimeout(resolve, 500));
556
+ }
557
+ try {
558
+ _internals.gitExec(["checkout", "--", "."], cwd);
559
+ discardSucceeded = true;
560
+ break;
561
+ } catch {}
562
+ }
563
+ if (!discardSucceeded) {
564
+ warnings.push("Could not discard all uncommitted changes after reset");
565
+ }
566
+ changesDiscarded = discardSucceeded;
567
+ }
568
+ try {
569
+ _internals.gitExec(["clean", "-fdX"], cwd);
570
+ } catch {
571
+ warnings.push("Could not clean untracked files");
572
+ }
573
+ let branchDeleted = false;
574
+ if (switchedBranch && previousBranch !== defaultBranch) {
575
+ try {
576
+ const mergedOutput = _internals.gitExec(["branch", "--merged", defaultBranch], cwd);
577
+ const isMerged = mergedOutput.split(`
578
+ `).some((line) => line.trim() === previousBranch || line.trim() === `* ${previousBranch}`);
579
+ if (isMerged) {
580
+ _internals.gitExec(["branch", "-d", previousBranch], cwd);
581
+ branchDeleted = true;
582
+ } else {
583
+ warnings.push(`Branch ${previousBranch} is not merged into ${defaultBranch} \u2014 keeping it`);
584
+ }
585
+ } catch {
586
+ warnings.push(`Could not delete branch ${previousBranch}`);
587
+ }
588
+ }
589
+ if (options?.pruneBranches) {
590
+ try {
591
+ const mergedOutput = _internals.gitExec(["branch", "--merged", defaultBranch], cwd);
592
+ const mergedLines = mergedOutput.split(`
593
+ `);
594
+ for (const line of mergedLines) {
595
+ const trimmedLine = line.trim();
596
+ if (!trimmedLine || trimmedLine.startsWith("*") || trimmedLine === defaultBranch) {
597
+ continue;
598
+ }
599
+ try {
600
+ _internals.gitExec(["branch", "-d", trimmedLine], cwd);
601
+ } catch {
602
+ warnings.push(`Could not prune branch: ${trimmedLine}`);
603
+ }
604
+ }
605
+ } catch (err) {
606
+ warnings.push(`Prune failed: ${err instanceof Error ? err.message : String(err)}`);
607
+ }
608
+ }
609
+ return {
610
+ success: true,
611
+ targetBranch,
612
+ previousBranch,
613
+ message: branchDeleted ? `Reset to ${defaultBranch} and deleted branch ${previousBranch}` : `Reset to ${defaultBranch}`,
614
+ branchDeleted,
615
+ changesDiscarded,
616
+ warnings
617
+ };
618
+ } catch (err) {
619
+ return {
620
+ success: false,
621
+ targetBranch: "",
622
+ previousBranch: "",
623
+ message: `Unexpected error: ${err instanceof Error ? err.message : String(err)}`,
624
+ branchDeleted: false,
625
+ changesDiscarded: false,
626
+ warnings
627
+ };
628
+ }
629
+ }
630
+ var _internals = {
631
+ gitExec,
632
+ detectDefaultRemoteBranch,
633
+ getDefaultBaseBranch,
634
+ getGitRepositoryStatus,
635
+ resetToRemoteBranch,
636
+ resetToMainAfterMerge
637
+ };
638
+
639
+ // src/hooks/delegation-gate/worktree-merge-status.ts
640
+ import * as fs from "fs";
641
+ var failuresByTask = new Map;
642
+ var durableStatusPath;
643
+ var hasLoaded = false;
644
+ function loadDurableStatus(statusPath) {
645
+ try {
646
+ hasLoaded = true;
647
+ if (!fs.existsSync(statusPath)) {
648
+ failuresByTask.clear();
649
+ return;
650
+ }
651
+ const data = JSON.parse(fs.readFileSync(statusPath, "utf-8"));
652
+ if (data && typeof data === "object") {
653
+ failuresByTask.clear();
654
+ for (const [taskId, failure] of Object.entries(data)) {
655
+ failuresByTask.set(taskId, failure);
656
+ }
657
+ }
658
+ } catch {
659
+ failuresByTask.clear();
660
+ }
661
+ }
662
+ function getWorktreeMergeFailure(taskId) {
663
+ if (!hasLoaded && durableStatusPath) {
664
+ loadDurableStatus(durableStatusPath);
665
+ }
666
+ return failuresByTask.get(taskId);
667
+ }
668
+
669
+ // src/turbo/epic/state.ts
670
+ init_logger();
671
+ import * as fs2 from "fs";
672
+ import * as path2 from "path";
673
+ var STATE_FILE = "epic-state.json";
674
+ function nowISO() {
675
+ return new Date().toISOString();
676
+ }
677
+ function ensureSwarmDir(directory) {
678
+ const swarmDir = path2.resolve(directory, ".swarm");
679
+ if (!fs2.existsSync(swarmDir)) {
680
+ fs2.mkdirSync(swarmDir, { recursive: true });
681
+ }
682
+ return swarmDir;
683
+ }
684
+ function emptyPersisted() {
685
+ return { version: 1, updatedAt: nowISO(), sessions: {} };
686
+ }
687
+ function emptySessionState(sessionID) {
688
+ return { sessionID, active: false };
689
+ }
690
+ var stateUnreadableMap = new Map;
691
+ function isStateUnreadable(directory) {
692
+ return stateUnreadableMap.get(directory) ?? false;
693
+ }
694
+ function markStateUnreadable(directory, reason) {
695
+ stateUnreadableMap.set(directory, true);
696
+ error(`[turbo/epic/state] state file unreadable for ${directory}: ${reason} \u2014 failing closed`);
697
+ }
698
+ function readPersisted(directory) {
699
+ try {
700
+ const filePath = path2.join(directory, ".swarm", STATE_FILE);
701
+ if (!fs2.existsSync(filePath)) {
702
+ const seed = emptyPersisted();
703
+ try {
704
+ ensureSwarmDir(directory);
705
+ fs2.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
706
+ `, "utf-8");
707
+ } catch {}
708
+ return seed;
709
+ }
710
+ const raw = fs2.readFileSync(filePath, "utf-8");
711
+ const parsed = JSON.parse(raw);
712
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 1 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
713
+ markStateUnreadable(directory, `malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
714
+ return null;
715
+ }
716
+ return {
717
+ version: 1,
718
+ updatedAt: parsed.updatedAt ?? nowISO(),
719
+ sessions: parsed.sessions
720
+ };
721
+ } catch (error2) {
722
+ const reason = error2 instanceof Error ? error2.message : String(error2);
723
+ markStateUnreadable(directory, reason);
724
+ return null;
725
+ }
726
+ }
727
+ function writePersisted(directory, persisted) {
728
+ if (stateUnreadableMap.get(directory)) {
729
+ throw new Error(`Epic state is unreadable. Please repair .swarm/${STATE_FILE} before continuing.`);
730
+ }
731
+ let filePath;
732
+ let tmpPath;
733
+ let payload;
734
+ try {
735
+ ensureSwarmDir(directory);
736
+ filePath = path2.join(directory, ".swarm", STATE_FILE);
737
+ tmpPath = `${filePath}.tmp.${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
738
+ persisted.updatedAt = nowISO();
739
+ payload = `${JSON.stringify(persisted, null, 2)}
740
+ `;
741
+ } catch (error2) {
742
+ const msg = error2 instanceof Error ? error2.message : String(error2);
743
+ error(`[turbo/epic/state] Failed to prepare ${STATE_FILE} write: ${msg}`);
744
+ throw new Error(`Epic state persistence prepare failed: ${msg}`);
745
+ }
746
+ try {
747
+ fs2.writeFileSync(tmpPath, payload, "utf-8");
748
+ fs2.renameSync(tmpPath, filePath);
749
+ } catch (error2) {
750
+ const msg = error2 instanceof Error ? error2.message : String(error2);
751
+ error(`[turbo/epic/state] Failed to persist ${STATE_FILE} atomically: ${msg}`);
752
+ try {
753
+ if (fs2.existsSync(tmpPath))
754
+ fs2.unlinkSync(tmpPath);
755
+ } catch {}
756
+ throw new Error(`Epic state persistence failed: ${msg}`);
757
+ }
758
+ }
759
+ function loadEpicSessionState(directory, sessionID) {
760
+ if (stateUnreadableMap.get(directory))
761
+ return null;
762
+ const persisted = readPersisted(directory);
763
+ if (!persisted)
764
+ return null;
765
+ return persisted.sessions[sessionID] ?? null;
766
+ }
767
+ function saveEpicSessionState(directory, state) {
768
+ if (stateUnreadableMap.get(directory)) {
769
+ throw new Error(`Epic state is unreadable for ${directory}. Repair .swarm/${STATE_FILE} before continuing.`);
770
+ }
771
+ const persisted = readPersisted(directory);
772
+ if (!persisted) {
773
+ throw new Error(`Epic state is unreadable for ${directory}. Repair .swarm/${STATE_FILE} before continuing.`);
774
+ }
775
+ persisted.sessions[state.sessionID] = state;
776
+ writePersisted(directory, persisted);
777
+ }
778
+ function isEpicModeActive(directory, sessionID) {
779
+ const state = loadEpicSessionState(directory, sessionID);
780
+ return state?.active === true;
781
+ }
782
+ function isEpicModeActiveForProject(directory) {
783
+ if (stateUnreadableMap.get(directory))
784
+ return false;
785
+ if (!fs2.existsSync(path2.join(directory, ".swarm", STATE_FILE))) {
786
+ return false;
787
+ }
788
+ const persisted = readPersisted(directory);
789
+ if (!persisted)
790
+ return false;
791
+ for (const session of Object.values(persisted.sessions)) {
792
+ if (session?.active === true)
793
+ return true;
794
+ }
795
+ return false;
796
+ }
797
+ function enableEpicMode(directory, sessionID) {
798
+ const current = loadEpicSessionState(directory, sessionID) ?? emptySessionState(sessionID);
799
+ current.active = true;
800
+ current.enabledAt = nowISO();
801
+ current.disabledAt = undefined;
802
+ saveEpicSessionState(directory, current);
803
+ }
804
+ function disableEpicMode(directory, sessionID) {
805
+ const current = loadEpicSessionState(directory, sessionID);
806
+ if (!current) {
807
+ saveEpicSessionState(directory, {
808
+ ...emptySessionState(sessionID),
809
+ disabledAt: nowISO()
810
+ });
811
+ return;
812
+ }
813
+ current.active = false;
814
+ current.disabledAt = nowISO();
815
+ saveEpicSessionState(directory, current);
816
+ }
817
+
818
+ // src/turbo/epic/task-commit.ts
819
+ init_logger();
820
+ function scrubTaskIdForGitSubject(taskId) {
821
+ return taskId.replace(/[^a-zA-Z0-9._-]/g, "_");
822
+ }
823
+ function formatTaskCommitMessage(taskId, description) {
824
+ const safeId = scrubTaskIdForGitSubject(taskId);
825
+ const summary = (description ?? "completed").replace(/\s+/g, " ").trim();
826
+ const truncated = summary.length > 60 ? `${summary.slice(0, 57)}...` : summary;
827
+ return `swarm(task ${safeId}): ${truncated || "completed"}`;
828
+ }
829
+ var INDEX_LOCK_BACKOFF_MS = [100, 200, 400, 800];
830
+ var INDEX_LOCK_ERROR_RE = /index\.lock|unable to create.*\.lock/i;
831
+ function isLockContentionError(err) {
832
+ const msg = err instanceof Error ? err.message : String(err);
833
+ return INDEX_LOCK_ERROR_RE.test(msg);
834
+ }
835
+ async function commitTaskCompletion(directory, taskId, description, scopePaths) {
836
+ if (!_internals2.isGitRepo(directory)) {
837
+ return { committed: false, reason: "no-git" };
838
+ }
839
+ try {
840
+ if (_internals2.hasExistingTaskCommit(directory, taskId)) {
841
+ return { committed: true, reason: "idempotent-skip" };
842
+ }
843
+ } catch {}
844
+ const rawPaths = (scopePaths ?? []).filter((p) => typeof p === "string" && p.trim().length > 0);
845
+ const droppedMagic = [];
846
+ const paths = rawPaths.filter((p) => {
847
+ if (p.startsWith(":")) {
848
+ droppedMagic.push(p);
849
+ return false;
850
+ }
851
+ return true;
852
+ });
853
+ if (droppedMagic.length > 0) {
854
+ criticalWarn(`[epic:task-commit] dropped ${droppedMagic.length} scope path(s) starting with ':' (git pathspec magic, not allowed): ${droppedMagic.slice(0, 5).join(", ")}${droppedMagic.length > 5 ? `, +${droppedMagic.length - 5} more` : ""}. Architect should declare literal file paths only.`);
855
+ }
856
+ const message = formatTaskCommitMessage(taskId, description);
857
+ let lastError = null;
858
+ for (let attempt = 0;attempt <= INDEX_LOCK_BACKOFF_MS.length; attempt++) {
859
+ try {
860
+ if (paths.length > 0) {
861
+ _internals2.stageScopedPaths(directory, paths);
862
+ }
863
+ _internals2.commitAllowEmpty(directory, message);
864
+ const sha = _internals2.gitHeadSha(directory);
865
+ return { committed: true, reason: "success", sha };
866
+ } catch (err) {
867
+ lastError = err;
868
+ if (attempt < INDEX_LOCK_BACKOFF_MS.length && isLockContentionError(err)) {
869
+ await _internals2.sleep(INDEX_LOCK_BACKOFF_MS[attempt]);
870
+ continue;
871
+ }
872
+ break;
873
+ }
874
+ }
875
+ const msg = lastError instanceof Error ? lastError.message : String(lastError);
876
+ criticalWarn(`[epic:task-commit] commit for task ${taskId} failed (non-fatal): ${msg}`);
877
+ return { committed: false, reason: "commit-failed", error: msg };
878
+ }
879
+ var _internals2 = {
880
+ isGitRepo: (cwd) => isGitRepo(cwd),
881
+ stageScopedPaths: (cwd, paths) => {
882
+ const CHUNK = 200;
883
+ for (let i = 0;i < paths.length; i += CHUNK) {
884
+ const chunk = paths.slice(i, i + CHUNK);
885
+ _internals.gitExec(["add", "--", ...chunk, ":(exclude,glob)**/.swarm/**"], cwd);
886
+ }
887
+ },
888
+ commitAllowEmpty: (cwd, message) => {
889
+ _internals.gitExec(["commit", "--allow-empty", "--no-verify", "-m", message], cwd);
890
+ },
891
+ gitHeadSha: (cwd) => {
892
+ return _internals.gitExec(["rev-parse", "HEAD"], cwd).trim();
893
+ },
894
+ sleep: (ms) => new Promise((resolve2) => setTimeout(resolve2, ms)),
895
+ hasExistingTaskCommit: (cwd, taskId) => {
896
+ const safeId = scrubTaskIdForGitSubject(taskId);
897
+ const escaped = safeId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
898
+ const output = _internals.gitExec([
899
+ "log",
900
+ "--extended-regexp",
901
+ `--grep=^swarm\\(task ${escaped}\\):`,
902
+ "--pretty=format:%H",
903
+ "-n",
904
+ "1"
905
+ ], cwd);
906
+ return output.trim().length > 0;
907
+ }
908
+ };
909
+
910
+ // src/turbo/lean/conflicts.ts
911
+ import * as fs3 from "fs";
912
+ import * as path3 from "path";
913
+ var DEFAULT_GLOBAL_FILES = [
914
+ "package.json",
915
+ "package-lock.json",
916
+ "bun.lock",
917
+ "bun.lockb",
918
+ "pnpm-lock.yaml",
919
+ "yarn.lock",
920
+ "Cargo.lock",
921
+ "Gemfile.lock",
922
+ "composer.lock",
923
+ "poetry.lock",
924
+ "go.mod",
925
+ "go.sum",
926
+ "tsconfig.json",
927
+ "bunfig.toml",
928
+ "CHANGELOG.md",
929
+ ".release-please-manifest.json",
930
+ "src/index.ts",
931
+ "src/tools/index.ts",
932
+ "src/agents/index.ts",
933
+ "src/config/index.ts",
934
+ "src/hooks/index.ts",
935
+ "turbo.json",
936
+ "nx.json",
937
+ "packageManager",
938
+ ".npmrc",
939
+ ".nvmrc",
940
+ ".node-version"
941
+ ];
942
+ var DEFAULT_PROTECTED_PATTERNS = [
943
+ "guardrail",
944
+ "delegation",
945
+ "authority",
946
+ "permission",
947
+ "crypto",
948
+ "secret",
949
+ "security",
950
+ "auth",
951
+ "/auth/",
952
+ "/auth.",
953
+ "auth.",
954
+ ".env",
955
+ "credentials",
956
+ "secrets",
957
+ "private",
958
+ "/security/",
959
+ "/security.",
960
+ "/protect/",
961
+ "/protect."
962
+ ];
963
+ var BARREL_FILE_PATTERNS = [
964
+ /\/index\.ts$/,
965
+ /\/index\.tsx$/,
966
+ /\/index\.js$/,
967
+ /\/index\.mjs$/,
968
+ /\/exports\.ts$/,
969
+ /\/types\.ts$/
970
+ ];
971
+ function normalizePath(filePath) {
972
+ if (filePath === "." || filePath === "./") {
973
+ return ".";
974
+ }
975
+ let result = filePath.replace(/\\/g, "/").replace(/\/+/g, "/").replace(/^\.\//, "").replace(/(?:^|\/)\.\//g, "/");
976
+ result = result.replace(/\/$/, "");
977
+ result = result.replace(/\/\.$/, "");
978
+ if (process.platform === "win32") {
979
+ result = result.toLowerCase();
980
+ }
981
+ return result;
982
+ }
983
+ function pathsConflict(path1, path22) {
984
+ if (process.platform === "win32") {
985
+ path1 = path1.toLowerCase();
986
+ path22 = path22.toLowerCase();
987
+ }
988
+ if (path1 === path22) {
989
+ return true;
990
+ }
991
+ const [shorter, longer] = path1.length <= path22.length ? [path1, path22] : [path22, path1];
992
+ if (longer.startsWith(`${shorter}/`)) {
993
+ return true;
994
+ }
995
+ return false;
996
+ }
997
+ function isGlobalFile(normalizedPath) {
998
+ if (DEFAULT_GLOBAL_FILES.some((gf) => normalizedPath.endsWith(gf))) {
999
+ return true;
1000
+ }
1001
+ for (const pattern of BARREL_FILE_PATTERNS) {
1002
+ if (pattern.test(normalizedPath)) {
1003
+ return true;
1004
+ }
1005
+ }
1006
+ return false;
1007
+ }
1008
+ function isProtectedPath(normalizedPath) {
1009
+ const lowerPath = normalizedPath.toLowerCase();
1010
+ for (const pattern of DEFAULT_PROTECTED_PATTERNS) {
1011
+ if (lowerPath.includes(pattern.toLowerCase())) {
1012
+ if (pattern === "auth" || pattern === "/auth/") {
1013
+ if (lowerPath === "auth" || lowerPath.endsWith("/auth") || lowerPath.includes("/auth/")) {
1014
+ return true;
1015
+ }
1016
+ } else if (pattern === "auth.") {
1017
+ const idx = lowerPath.indexOf("auth.");
1018
+ if (idx !== -1) {
1019
+ const before = idx === 0 || lowerPath[idx - 1] === "/";
1020
+ if (before) {
1021
+ return true;
1022
+ }
1023
+ }
1024
+ } else {
1025
+ return true;
1026
+ }
1027
+ }
1028
+ }
1029
+ return false;
1030
+ }
1031
+ function readTaskScopes(directory, taskId) {
1032
+ const scopePath = path3.join(directory, ".swarm", "scopes", `scope-${taskId}.json`);
1033
+ try {
1034
+ if (!fs3.existsSync(scopePath)) {
1035
+ return null;
1036
+ }
1037
+ const raw = fs3.readFileSync(scopePath, "utf-8");
1038
+ const parsed = JSON.parse(raw);
1039
+ if (!parsed || !Array.isArray(parsed.files)) {
1040
+ return null;
1041
+ }
1042
+ return parsed.files;
1043
+ } catch {
1044
+ return null;
1045
+ }
1046
+ }
1047
+
105
1048
  // src/utils/spec-hash.ts
106
1049
  import { createHash as createHash2 } from "crypto";
107
1050
 
108
1051
  // src/sdd/effective-spec.ts
109
1052
  import { createHash } from "crypto";
110
- import * as fs from "fs";
111
- import * as path from "path";
1053
+ import * as fs4 from "fs";
1054
+ import * as path4 from "path";
112
1055
 
113
1056
  // src/config/spec-schema.ts
114
1057
  var ObligationSchema = exports_external.enum(["MUST", "SHALL", "SHOULD", "MAY"]);
@@ -198,32 +1141,32 @@ function validateSpecContent(content) {
198
1141
  }
199
1142
 
200
1143
  // src/sdd/effective-spec.ts
201
- var SWARM_SPEC_REL = path.join(".swarm", "spec.md");
1144
+ var SWARM_SPEC_REL = path4.join(".swarm", "spec.md");
202
1145
  var OPENSPEC_ROOT = "openspec";
203
1146
  var MAX_SPEC_BYTES = 256 * 1024;
204
1147
  var MAX_SOURCE_BYTES = 512 * 1024;
205
1148
  var MAX_SPEC_FILES = 100;
206
1149
  var MAX_WALK_DEPTH = 10;
207
1150
  function toPosix(relPath) {
208
- return relPath.split(path.sep).join("/");
1151
+ return relPath.split(path4.sep).join("/");
209
1152
  }
210
1153
  function hash(content) {
211
1154
  return createHash("sha256").update(content, "utf-8").digest("hex");
212
1155
  }
213
1156
  function readTextBounded(absPath) {
214
- const stat = fs.lstatSync(absPath);
1157
+ const stat = fs4.lstatSync(absPath);
215
1158
  if (!stat.isFile() || stat.size > MAX_SOURCE_BYTES) {
216
1159
  return null;
217
1160
  }
218
- return fs.readFileSync(absPath, "utf-8");
1161
+ return fs4.readFileSync(absPath, "utf-8");
219
1162
  }
220
1163
  function fileArtifact(root, absPath) {
221
1164
  try {
222
- const stat = fs.lstatSync(absPath);
1165
+ const stat = fs4.lstatSync(absPath);
223
1166
  if (!stat.isFile() || stat.size > MAX_SOURCE_BYTES)
224
1167
  return null;
225
1168
  return {
226
- relPath: toPosix(path.relative(root, absPath)),
1169
+ relPath: toPosix(path4.relative(root, absPath)),
227
1170
  bytes: stat.size,
228
1171
  mtimeMs: stat.mtimeMs
229
1172
  };
@@ -232,8 +1175,8 @@ function fileArtifact(root, absPath) {
232
1175
  }
233
1176
  }
234
1177
  function walkSpecFiles(root, startRel) {
235
- const start = path.join(root, startRel);
236
- if (!fs.existsSync(start))
1178
+ const start = path4.join(root, startRel);
1179
+ if (!fs4.existsSync(start))
237
1180
  return [];
238
1181
  const artifacts = [];
239
1182
  const stack = [
@@ -245,13 +1188,13 @@ function walkSpecFiles(root, startRel) {
245
1188
  continue;
246
1189
  let entries;
247
1190
  try {
248
- entries = fs.readdirSync(item.abs, { withFileTypes: true });
1191
+ entries = fs4.readdirSync(item.abs, { withFileTypes: true });
249
1192
  } catch {
250
1193
  continue;
251
1194
  }
252
1195
  const dirents = entries.filter((entry) => typeof entry?.name === "string");
253
1196
  for (const entry of dirents.sort((a, b) => b.name.localeCompare(a.name))) {
254
- const abs = path.join(item.abs, entry.name);
1197
+ const abs = path4.join(item.abs, entry.name);
255
1198
  if (entry.isSymbolicLink())
256
1199
  continue;
257
1200
  if (entry.isDirectory()) {
@@ -268,23 +1211,23 @@ function walkSpecFiles(root, startRel) {
268
1211
  return artifacts.sort((a, b) => a.relPath.localeCompare(b.relPath));
269
1212
  }
270
1213
  function listOpenSpecChanges(root) {
271
- const changesDir = path.join(root, OPENSPEC_ROOT, "changes");
272
- if (!fs.existsSync(changesDir))
1214
+ const changesDir = path4.join(root, OPENSPEC_ROOT, "changes");
1215
+ if (!fs4.existsSync(changesDir))
273
1216
  return [];
274
1217
  let entries;
275
1218
  try {
276
- entries = fs.readdirSync(changesDir, { withFileTypes: true });
1219
+ entries = fs4.readdirSync(changesDir, { withFileTypes: true });
277
1220
  } catch {
278
1221
  return [];
279
1222
  }
280
1223
  return entries.filter((entry) => entry.isDirectory() && entry.name !== "archive").sort((a, b) => a.name.localeCompare(b.name)).map((entry) => {
281
- const rel = path.join(OPENSPEC_ROOT, "changes", entry.name);
1224
+ const rel = path4.join(OPENSPEC_ROOT, "changes", entry.name);
282
1225
  return {
283
1226
  id: entry.name,
284
- proposal: fs.existsSync(path.join(root, rel, "proposal.md")),
285
- design: fs.existsSync(path.join(root, rel, "design.md")),
286
- tasks: fs.existsSync(path.join(root, rel, "tasks.md")),
287
- specs: walkSpecFiles(root, path.join(rel, "specs"))
1227
+ proposal: fs4.existsSync(path4.join(root, rel, "proposal.md")),
1228
+ design: fs4.existsSync(path4.join(root, rel, "design.md")),
1229
+ tasks: fs4.existsSync(path4.join(root, rel, "tasks.md")),
1230
+ specs: walkSpecFiles(root, path4.join(rel, "specs"))
288
1231
  };
289
1232
  });
290
1233
  }
@@ -379,14 +1322,14 @@ function renderRequirement(req, used, warnings) {
379
1322
  return `- ${text} _(source: ${req.sourceRel})_`;
380
1323
  }
381
1324
  function loadSddStatusSync(directory) {
382
- const root = path.resolve(directory);
383
- const swSpecPath = path.join(root, SWARM_SPEC_REL);
384
- const openSpecPath = path.join(root, OPENSPEC_ROOT);
1325
+ const root = path4.resolve(directory);
1326
+ const swSpecPath = path4.join(root, SWARM_SPEC_REL);
1327
+ const openSpecPath = path4.join(root, OPENSPEC_ROOT);
385
1328
  const errors = [];
386
1329
  const warnings = [];
387
- const swSpecExists = fs.existsSync(swSpecPath);
388
- const openSpecExists = fs.existsSync(openSpecPath);
389
- const currentSpecs = walkSpecFiles(root, path.join(OPENSPEC_ROOT, "specs"));
1330
+ const swSpecExists = fs4.existsSync(swSpecPath);
1331
+ const openSpecExists = fs4.existsSync(openSpecPath);
1332
+ const currentSpecs = walkSpecFiles(root, path4.join(OPENSPEC_ROOT, "specs"));
390
1333
  const changes = listOpenSpecChanges(root);
391
1334
  const effectiveSpec = readEffectiveSpecSync(root);
392
1335
  if (openSpecExists && currentSpecs.length === 0 && changes.length === 0) {
@@ -415,8 +1358,8 @@ function loadSddStatusSync(directory) {
415
1358
  };
416
1359
  }
417
1360
  function buildOpenSpecProjectionSync(directory, options = {}) {
418
- const root = path.resolve(directory);
419
- const currentSpecs = walkSpecFiles(root, path.join(OPENSPEC_ROOT, "specs"));
1361
+ const root = path4.resolve(directory);
1362
+ const currentSpecs = walkSpecFiles(root, path4.join(OPENSPEC_ROOT, "specs"));
420
1363
  const allChanges = listOpenSpecChanges(root);
421
1364
  const changes = options.changeId ? allChanges.filter((change) => change.id === options.changeId) : allChanges;
422
1365
  const sourcePaths = [];
@@ -431,7 +1374,7 @@ function buildOpenSpecProjectionSync(directory, options = {}) {
431
1374
  if (currentSpecs.length === 0 && changes.length === 0)
432
1375
  return null;
433
1376
  for (const artifact of currentSpecs) {
434
- const abs = path.join(root, artifact.relPath);
1377
+ const abs = path4.join(root, artifact.relPath);
435
1378
  const content2 = readTextBounded(abs);
436
1379
  if (content2 === null) {
437
1380
  warnings.push(`Skipped unreadable or oversized spec ${artifact.relPath}.`);
@@ -446,7 +1389,7 @@ function buildOpenSpecProjectionSync(directory, options = {}) {
446
1389
  for (const change of changes) {
447
1390
  const reqs = [];
448
1391
  for (const artifact of change.specs) {
449
- const abs = path.join(root, artifact.relPath);
1392
+ const abs = path4.join(root, artifact.relPath);
450
1393
  const content2 = readTextBounded(abs);
451
1394
  if (content2 === null) {
452
1395
  warnings.push(`Skipped unreadable or oversized spec ${artifact.relPath}.`);
@@ -513,12 +1456,12 @@ function buildOpenSpecProjectionSync(directory, options = {}) {
513
1456
  };
514
1457
  }
515
1458
  function readEffectiveSpecSync(directory) {
516
- const root = path.resolve(directory);
517
- const swSpecPath = path.join(root, SWARM_SPEC_REL);
1459
+ const root = path4.resolve(directory);
1460
+ const swSpecPath = path4.join(root, SWARM_SPEC_REL);
518
1461
  try {
519
- const stat = fs.lstatSync(swSpecPath);
1462
+ const stat = fs4.lstatSync(swSpecPath);
520
1463
  if (stat.isFile() && stat.size <= MAX_SPEC_BYTES) {
521
- const content = fs.readFileSync(swSpecPath, "utf-8");
1464
+ const content = fs4.readFileSync(swSpecPath, "utf-8");
522
1465
  return {
523
1466
  source: "swarm",
524
1467
  content,
@@ -528,49 +1471,49 @@ function readEffectiveSpecSync(directory) {
528
1471
  warnings: []
529
1472
  };
530
1473
  }
531
- } catch (error) {
532
- if (error.code !== "ENOENT") {
533
- throw error;
1474
+ } catch (error2) {
1475
+ if (error2.code !== "ENOENT") {
1476
+ throw error2;
534
1477
  }
535
1478
  }
536
1479
  return buildOpenSpecProjectionSync(root);
537
1480
  }
538
1481
  function writeProjectedSpecSync(directory, options = {}) {
539
- const root = path.resolve(directory);
1482
+ const root = path4.resolve(directory);
540
1483
  const projection = buildOpenSpecProjectionSync(root, {
541
1484
  changeId: options.changeId
542
1485
  });
543
- const target = path.join(root, SWARM_SPEC_REL);
1486
+ const target = path4.join(root, SWARM_SPEC_REL);
544
1487
  if (!projection || options.dryRun) {
545
1488
  return { written: false, projection, path: target };
546
1489
  }
547
- fs.mkdirSync(path.dirname(target), { recursive: true });
1490
+ fs4.mkdirSync(path4.dirname(target), { recursive: true });
548
1491
  let archivePath;
549
- if (fs.existsSync(target)) {
550
- const prior = fs.readFileSync(target, "utf-8");
1492
+ if (fs4.existsSync(target)) {
1493
+ const prior = fs4.readFileSync(target, "utf-8");
551
1494
  if (prior !== projection.content) {
552
- const archiveDir = path.join(root, ".swarm", "spec-archive");
553
- fs.mkdirSync(archiveDir, { recursive: true });
1495
+ const archiveDir = path4.join(root, ".swarm", "spec-archive");
1496
+ fs4.mkdirSync(archiveDir, { recursive: true });
554
1497
  const stamp = new Date().toISOString().replace(/[:.]/g, "-");
555
- archivePath = path.join(archiveDir, `sdd-projection-${stamp}.md`);
556
- fs.writeFileSync(archivePath, prior, "utf-8");
1498
+ archivePath = path4.join(archiveDir, `sdd-projection-${stamp}.md`);
1499
+ fs4.writeFileSync(archivePath, prior, "utf-8");
557
1500
  }
558
1501
  }
559
1502
  const tmp = `${target}.tmp-${process.pid}-${Date.now()}`;
560
- fs.writeFileSync(tmp, projection.content, "utf-8");
561
- fs.renameSync(tmp, target);
1503
+ fs4.writeFileSync(tmp, projection.content, "utf-8");
1504
+ fs4.renameSync(tmp, target);
562
1505
  return { written: true, projection, archivePath, path: target };
563
1506
  }
564
1507
 
565
1508
  // src/utils/spec-hash.ts
566
1509
  async function computeSpecHash(directory) {
567
- const spec = _internals.readEffectiveSpecSync(directory);
1510
+ const spec = _internals3.readEffectiveSpecSync(directory);
568
1511
  if (!spec)
569
1512
  return null;
570
1513
  return createHash2("sha256").update(spec.content, "utf-8").digest("hex");
571
1514
  }
572
1515
  async function isSpecStale(directory, plan) {
573
- const currentHash = await _internals.computeSpecHash(directory);
1516
+ const currentHash = await _internals3.computeSpecHash(directory);
574
1517
  if (!plan.specHash) {
575
1518
  return { stale: false };
576
1519
  }
@@ -590,7 +1533,7 @@ async function isSpecStale(directory, plan) {
590
1533
  }
591
1534
  return { stale: false };
592
1535
  }
593
- var _internals = {
1536
+ var _internals3 = {
594
1537
  computeSpecHash,
595
1538
  isSpecStale,
596
1539
  readEffectiveSpecSync
@@ -598,8 +1541,8 @@ var _internals = {
598
1541
 
599
1542
  // src/plan/ledger.ts
600
1543
  import * as crypto from "crypto";
601
- import * as fs2 from "fs";
602
- import * as path2 from "path";
1544
+ import * as fs5 from "fs";
1545
+ import * as path5 from "path";
603
1546
 
604
1547
  // src/plan/utils.ts
605
1548
  function derivePlanId(plan) {
@@ -618,10 +1561,10 @@ class LedgerStaleWriterError extends Error {
618
1561
  }
619
1562
  }
620
1563
  function getLedgerPath(directory) {
621
- return path2.join(directory, ".swarm", LEDGER_FILENAME);
1564
+ return path5.join(directory, ".swarm", LEDGER_FILENAME);
622
1565
  }
623
1566
  function getPlanJsonPath(directory) {
624
- return path2.join(directory, ".swarm", PLAN_JSON_FILENAME);
1567
+ return path5.join(directory, ".swarm", PLAN_JSON_FILENAME);
625
1568
  }
626
1569
  function computePlanHash(plan) {
627
1570
  const normalized = {
@@ -656,7 +1599,7 @@ function computePlanHash(plan) {
656
1599
  function computeCurrentPlanHash(directory) {
657
1600
  const planPath = getPlanJsonPath(directory);
658
1601
  try {
659
- const content = fs2.readFileSync(planPath, "utf8");
1602
+ const content = fs5.readFileSync(planPath, "utf8");
660
1603
  const plan = JSON.parse(content);
661
1604
  return computePlanHash(plan);
662
1605
  } catch {
@@ -665,15 +1608,15 @@ function computeCurrentPlanHash(directory) {
665
1608
  }
666
1609
  async function ledgerExists(directory) {
667
1610
  const ledgerPath = getLedgerPath(directory);
668
- return fs2.existsSync(ledgerPath);
1611
+ return fs5.existsSync(ledgerPath);
669
1612
  }
670
1613
  async function getLatestLedgerSeq(directory) {
671
1614
  const ledgerPath = getLedgerPath(directory);
672
- if (!fs2.existsSync(ledgerPath)) {
1615
+ if (!fs5.existsSync(ledgerPath)) {
673
1616
  return 0;
674
1617
  }
675
1618
  try {
676
- const content = fs2.readFileSync(ledgerPath, "utf8");
1619
+ const content = fs5.readFileSync(ledgerPath, "utf8");
677
1620
  const lines = content.trim().split(`
678
1621
  `).filter((line) => line.trim() !== "");
679
1622
  if (lines.length === 0) {
@@ -695,11 +1638,11 @@ async function getLatestLedgerSeq(directory) {
695
1638
  }
696
1639
  async function readLedgerEvents(directory) {
697
1640
  const ledgerPath = getLedgerPath(directory);
698
- if (!fs2.existsSync(ledgerPath)) {
1641
+ if (!fs5.existsSync(ledgerPath)) {
699
1642
  return [];
700
1643
  }
701
1644
  try {
702
- const content = fs2.readFileSync(ledgerPath, "utf8");
1645
+ const content = fs5.readFileSync(ledgerPath, "utf8");
703
1646
  const lines = content.trim().split(`
704
1647
  `).filter((line) => line.trim() !== "");
705
1648
  const events = [];
@@ -724,15 +1667,15 @@ async function readLedgerEvents(directory) {
724
1667
  async function initLedger(directory, planId, initialPlanHash, initialPlan) {
725
1668
  const ledgerPath = getLedgerPath(directory);
726
1669
  const planJsonPath = getPlanJsonPath(directory);
727
- if (fs2.existsSync(ledgerPath)) {
1670
+ if (fs5.existsSync(ledgerPath)) {
728
1671
  throw new Error("Ledger already initialized. Use appendLedgerEvent to add events.");
729
1672
  }
730
1673
  let planHashAfter = initialPlanHash ?? "";
731
1674
  let embeddedPlan = initialPlan;
732
1675
  if (!initialPlanHash) {
733
1676
  try {
734
- if (fs2.existsSync(planJsonPath)) {
735
- const content = fs2.readFileSync(planJsonPath, "utf8");
1677
+ if (fs5.existsSync(planJsonPath)) {
1678
+ const content = fs5.readFileSync(planJsonPath, "utf8");
736
1679
  const plan = JSON.parse(content);
737
1680
  planHashAfter = computePlanHash(plan);
738
1681
  if (!embeddedPlan)
@@ -752,12 +1695,12 @@ async function initLedger(directory, planId, initialPlanHash, initialPlan) {
752
1695
  schema_version: LEDGER_SCHEMA_VERSION,
753
1696
  ...payload ? { payload } : {}
754
1697
  };
755
- fs2.mkdirSync(path2.join(directory, ".swarm"), { recursive: true });
1698
+ fs5.mkdirSync(path5.join(directory, ".swarm"), { recursive: true });
756
1699
  const tempPath = `${ledgerPath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
757
1700
  const line = `${JSON.stringify(event)}
758
1701
  `;
759
- fs2.writeFileSync(tempPath, line, "utf8");
760
- fs2.renameSync(tempPath, ledgerPath);
1702
+ fs5.writeFileSync(tempPath, line, "utf8");
1703
+ fs5.renameSync(tempPath, ledgerPath);
761
1704
  }
762
1705
  async function appendLedgerEvent(directory, eventInput, options) {
763
1706
  const ledgerPath = getLedgerPath(directory);
@@ -779,17 +1722,17 @@ async function appendLedgerEvent(directory, eventInput, options) {
779
1722
  plan_hash_after: planHashAfter,
780
1723
  schema_version: LEDGER_SCHEMA_VERSION
781
1724
  };
782
- fs2.mkdirSync(path2.join(directory, ".swarm"), { recursive: true });
1725
+ fs5.mkdirSync(path5.join(directory, ".swarm"), { recursive: true });
783
1726
  const tempPath = `${ledgerPath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
784
1727
  const line = `${JSON.stringify(event)}
785
1728
  `;
786
- if (fs2.existsSync(ledgerPath)) {
787
- const existingContent = fs2.readFileSync(ledgerPath, "utf8");
788
- fs2.writeFileSync(tempPath, existingContent + line, "utf8");
1729
+ if (fs5.existsSync(ledgerPath)) {
1730
+ const existingContent = fs5.readFileSync(ledgerPath, "utf8");
1731
+ fs5.writeFileSync(tempPath, existingContent + line, "utf8");
789
1732
  } else {
790
1733
  throw new Error("Ledger not initialized. Call initLedger() first.");
791
1734
  }
792
- fs2.renameSync(tempPath, ledgerPath);
1735
+ fs5.renameSync(tempPath, ledgerPath);
793
1736
  return event;
794
1737
  }
795
1738
  async function takeSnapshotWithRetry(directory, plan, options) {
@@ -876,12 +1819,12 @@ async function replayFromLedger(directory, _options) {
876
1819
  }
877
1820
  }
878
1821
  const planJsonPath = getPlanJsonPath(directory);
879
- if (!fs2.existsSync(planJsonPath)) {
1822
+ if (!fs5.existsSync(planJsonPath)) {
880
1823
  return null;
881
1824
  }
882
1825
  let plan;
883
1826
  try {
884
- const content = fs2.readFileSync(planJsonPath, "utf8");
1827
+ const content = fs5.readFileSync(planJsonPath, "utf8");
885
1828
  plan = JSON.parse(content);
886
1829
  } catch {
887
1830
  return null;
@@ -976,11 +1919,11 @@ function applyEventToPlan(plan, event) {
976
1919
  }
977
1920
  async function readLedgerEventsWithIntegrity(directory) {
978
1921
  const ledgerPath = getLedgerPath(directory);
979
- if (!fs2.existsSync(ledgerPath)) {
1922
+ if (!fs5.existsSync(ledgerPath)) {
980
1923
  return { events: [], truncated: false, badSuffix: null };
981
1924
  }
982
1925
  try {
983
- const content = fs2.readFileSync(ledgerPath, "utf8");
1926
+ const content = fs5.readFileSync(ledgerPath, "utf8");
984
1927
  const lines = content.split(`
985
1928
  `);
986
1929
  const events = [];
@@ -1009,9 +1952,9 @@ async function readLedgerEventsWithIntegrity(directory) {
1009
1952
  }
1010
1953
  async function quarantineLedgerSuffix(directory, badSuffix) {
1011
1954
  try {
1012
- const quarantinePath = path2.join(directory, ".swarm", "plan-ledger.quarantine");
1013
- fs2.writeFileSync(quarantinePath, badSuffix, "utf8");
1014
- console.warn(`[ledger] Corrupted suffix quarantined to ${path2.relative(directory, quarantinePath)}`);
1955
+ const quarantinePath = path5.join(directory, ".swarm", "plan-ledger.quarantine");
1956
+ fs5.writeFileSync(quarantinePath, badSuffix, "utf8");
1957
+ console.warn(`[ledger] Corrupted suffix quarantined to ${path5.relative(directory, quarantinePath)}`);
1015
1958
  } catch {}
1016
1959
  }
1017
1960
  async function loadLastApprovedPlan(directory, expectedPlanId) {
@@ -1069,10 +2012,15 @@ class PlanTaskRemovalNotAcknowledgedError extends Error {
1069
2012
  var startupLedgerCheckedWorkspaces = new Set;
1070
2013
  var recoveryMutexes = new Map;
1071
2014
  var PLAN_JSON_CACHE_NAMESPACE = "plan-json:validated:v1";
1072
- var _internals2 = {
2015
+ var _internals4 = {
1073
2016
  loadPlan,
1074
2017
  loadPlanJsonOnly,
1075
- regeneratePlanMarkdown
2018
+ regeneratePlanMarkdown,
2019
+ isGitRepo,
2020
+ isEpicModeActiveForProject,
2021
+ readTaskScopes,
2022
+ commitTaskCompletion,
2023
+ getWorktreeMergeFailure
1076
2024
  };
1077
2025
  var CAS_BACKOFF_START_MS = 5;
1078
2026
  var CAS_BACKOFF_CAP_MS = 250;
@@ -1088,9 +2036,9 @@ async function retryCasWithBackoff(directory, eventInput, options) {
1088
2036
  expectedHash: currentExpected,
1089
2037
  planHashAfter: options.planHashAfter
1090
2038
  });
1091
- } catch (error) {
1092
- if (!(error instanceof LedgerStaleWriterError) || attempt >= maxRetries) {
1093
- throw error;
2039
+ } catch (error2) {
2040
+ if (!(error2 instanceof LedgerStaleWriterError) || attempt >= maxRetries) {
2041
+ throw error2;
1094
2042
  }
1095
2043
  attempt++;
1096
2044
  const base = Math.min(CAS_BACKOFF_START_MS * 2 ** (attempt - 1), CAS_BACKOFF_CAP_MS);
@@ -1101,7 +2049,7 @@ async function retryCasWithBackoff(directory, eventInput, options) {
1101
2049
  expectedHashPrefix: currentExpected.slice(0, 8),
1102
2050
  delayMs
1103
2051
  });
1104
- await new Promise((resolve3) => setTimeout(resolve3, delayMs));
2052
+ await new Promise((resolve4) => setTimeout(resolve4, delayMs));
1105
2053
  if (options.verifyValid) {
1106
2054
  const stillValid = await options.verifyValid();
1107
2055
  if (!stillValid)
@@ -1114,8 +2062,8 @@ async function retryCasWithBackoff(directory, eventInput, options) {
1114
2062
  async function loadPlanJsonOnly(directory) {
1115
2063
  try {
1116
2064
  return await parsePlanJsonCached(directory);
1117
- } catch (error) {
1118
- warn(`Plan validation failed for .swarm/plan.json: ${error instanceof Error ? error.message : String(error)}`);
2065
+ } catch (error2) {
2066
+ warn(`Plan validation failed for .swarm/plan.json: ${error2 instanceof Error ? error2.message : String(error2)}`);
1119
2067
  }
1120
2068
  return null;
1121
2069
  }
@@ -1144,7 +2092,7 @@ async function getLatestLedgerHash(directory) {
1144
2092
  }
1145
2093
  }
1146
2094
  async function parsePlanJsonCached(directory) {
1147
- const planJsonPath = path3.resolve(directory, ".swarm", "plan.json");
2095
+ const planJsonPath = path6.resolve(directory, ".swarm", "plan.json");
1148
2096
  return readCachedParsedFile(planJsonPath, PLAN_JSON_CACHE_NAMESPACE, () => readSwarmFileAsync(directory, "plan.json"), (planJsonContent) => {
1149
2097
  if (planJsonContent.includes("\x00") || planJsonContent.includes("\uFFFD")) {
1150
2098
  throw new Error("Plan rejected: .swarm/plan.json contains null bytes or invalid encoding");
@@ -1204,19 +2152,19 @@ async function isPlanMdInSync(directory, plan) {
1204
2152
  return normalizedActual.includes(normalizedExpected) || normalizedExpected.includes(normalizedActual.replace(/^#.*$/gm, "").trim());
1205
2153
  }
1206
2154
  async function regeneratePlanMarkdown(directory, plan) {
1207
- const swarmDir = path3.resolve(directory, ".swarm");
2155
+ const swarmDir = path6.resolve(directory, ".swarm");
1208
2156
  const contentHash = computePlanContentHash(plan);
1209
2157
  const markdown = derivePlanMarkdown(plan);
1210
2158
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
1211
2159
  ${markdown}`;
1212
- const mdPath = path3.join(swarmDir, "plan.md");
1213
- const mdTempPath = path3.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2160
+ const mdPath = path6.join(swarmDir, "plan.md");
2161
+ const mdTempPath = path6.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
1214
2162
  try {
1215
2163
  await bunWrite(mdTempPath, markdownWithHash);
1216
- renameSync3(mdTempPath, mdPath);
2164
+ renameSync5(mdTempPath, mdPath);
1217
2165
  } finally {
1218
2166
  try {
1219
- unlinkSync(mdTempPath);
2167
+ unlinkSync3(mdTempPath);
1220
2168
  } catch {}
1221
2169
  }
1222
2170
  }
@@ -1234,7 +2182,7 @@ async function loadPlan(directory) {
1234
2182
  const inSync = await isPlanMdInSync(directory, validated);
1235
2183
  if (!inSync) {
1236
2184
  try {
1237
- await _internals2.regeneratePlanMarkdown(directory, validated);
2185
+ await _internals4.regeneratePlanMarkdown(directory, validated);
1238
2186
  } catch (regenError) {
1239
2187
  warn(`Failed to regenerate plan.md: ${regenError instanceof Error ? regenError.message : String(regenError)}. Proceeding with plan.json only.`);
1240
2188
  }
@@ -1242,7 +2190,7 @@ async function loadPlan(directory) {
1242
2190
  if (await ledgerExists(directory)) {
1243
2191
  const planHash = computePlanHash(validated);
1244
2192
  const ledgerHash = await getLatestLedgerHash(directory);
1245
- const resolvedWorkspace = path3.resolve(directory);
2193
+ const resolvedWorkspace = path6.resolve(directory);
1246
2194
  if (!startupLedgerCheckedWorkspaces.has(resolvedWorkspace)) {
1247
2195
  startupLedgerCheckedWorkspaces.add(resolvedWorkspace);
1248
2196
  if (ledgerHash !== "" && planHash !== ledgerHash) {
@@ -1299,7 +2247,7 @@ async function loadPlan(directory) {
1299
2247
  runtimePlan._specStale = true;
1300
2248
  runtimePlan._specStaleReason = staleResult.reason;
1301
2249
  try {
1302
- const specStalenessPath = path3.join(directory, ".swarm", "spec-staleness.json");
2250
+ const specStalenessPath = path6.join(directory, ".swarm", "spec-staleness.json");
1303
2251
  await fsPromises.writeFile(specStalenessPath, JSON.stringify({
1304
2252
  type: "spec_stale_detected",
1305
2253
  timestamp: new Date().toISOString(),
@@ -1311,7 +2259,7 @@ async function loadPlan(directory) {
1311
2259
  }, null, 2), "utf-8");
1312
2260
  } catch {}
1313
2261
  try {
1314
- const eventsPath = path3.join(directory, ".swarm", "events.jsonl");
2262
+ const eventsPath = path6.join(directory, ".swarm", "events.jsonl");
1315
2263
  const event = {
1316
2264
  type: "spec_stale_detected",
1317
2265
  timestamp: new Date().toISOString(),
@@ -1328,8 +2276,8 @@ async function loadPlan(directory) {
1328
2276
  }
1329
2277
  return validated;
1330
2278
  }
1331
- } catch (error) {
1332
- warn(`[loadPlan] plan.json validation failed: ${error instanceof Error ? error.message : String(error)}. Attempting rebuild from ledger. If rebuild fails, check .swarm/SWARM_PLAN.md for a checkpoint.`);
2279
+ } catch (error2) {
2280
+ warn(`[loadPlan] plan.json validation failed: ${error2 instanceof Error ? error2.message : String(error2)}. Attempting rebuild from ledger. If rebuild fails, check .swarm/SWARM_PLAN.md for a checkpoint.`);
1333
2281
  let rawPlanId = null;
1334
2282
  try {
1335
2283
  const rawParsed = JSON.parse(planJsonContent);
@@ -1376,11 +2324,11 @@ async function loadPlan(directory) {
1376
2324
  return migrated;
1377
2325
  }
1378
2326
  if (await ledgerExists(directory)) {
1379
- const resolvedDir = path3.resolve(directory);
2327
+ const resolvedDir = path6.resolve(directory);
1380
2328
  const existingMutex = recoveryMutexes.get(resolvedDir);
1381
2329
  if (existingMutex) {
1382
2330
  await existingMutex;
1383
- const postRecoveryPlan = await _internals2.loadPlanJsonOnly(directory);
2331
+ const postRecoveryPlan = await _internals4.loadPlanJsonOnly(directory);
1384
2332
  if (postRecoveryPlan)
1385
2333
  return postRecoveryPlan;
1386
2334
  }
@@ -1440,7 +2388,7 @@ async function loadPlan(directory) {
1440
2388
  return null;
1441
2389
  }
1442
2390
  async function savePlanWithAutoAcknowledgedRemovals(directory, plan, source, reason, options) {
1443
- const existing = await _internals2.loadPlanJsonOnly(directory);
2391
+ const existing = await _internals4.loadPlanJsonOnly(directory);
1444
2392
  const newIds = new Set;
1445
2393
  for (const phase of plan.phases) {
1446
2394
  for (const task of phase.tasks)
@@ -1468,7 +2416,7 @@ async function savePlan(directory, plan, options) {
1468
2416
  const validated = PlanSchema.parse(plan);
1469
2417
  if (options?.preserveCompletedStatuses !== false) {
1470
2418
  try {
1471
- const currentPlan2 = await _internals2.loadPlanJsonOnly(directory);
2419
+ const currentPlan2 = await _internals4.loadPlanJsonOnly(directory);
1472
2420
  if (currentPlan2) {
1473
2421
  const completedTaskIds = new Set;
1474
2422
  for (const phase of currentPlan2.phases) {
@@ -1501,7 +2449,7 @@ async function savePlan(directory, plan, options) {
1501
2449
  phase.status = "pending";
1502
2450
  }
1503
2451
  }
1504
- const currentPlan = await _internals2.loadPlanJsonOnly(directory);
2452
+ const currentPlan = await _internals4.loadPlanJsonOnly(directory);
1505
2453
  const planId = derivePlanId(validated);
1506
2454
  const planHashForInit = computePlanHash(validated);
1507
2455
  if (!await ledgerExists(directory)) {
@@ -1516,13 +2464,13 @@ async function savePlan(directory, plan, options) {
1516
2464
  } else {
1517
2465
  const existingEvents = await readLedgerEvents(directory);
1518
2466
  if (existingEvents.length > 0 && existingEvents[0].plan_id !== planId) {
1519
- const swarmDir2 = path3.resolve(directory, ".swarm");
1520
- const oldLedgerPath = path3.join(swarmDir2, "plan-ledger.jsonl");
1521
- const oldLedgerBackupPath = path3.join(swarmDir2, `plan-ledger.backup-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
2467
+ const swarmDir2 = path6.resolve(directory, ".swarm");
2468
+ const oldLedgerPath = path6.join(swarmDir2, "plan-ledger.jsonl");
2469
+ const oldLedgerBackupPath = path6.join(swarmDir2, `plan-ledger.backup-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
1522
2470
  let backupExists = false;
1523
- if (existsSync3(oldLedgerPath)) {
2471
+ if (existsSync6(oldLedgerPath)) {
1524
2472
  try {
1525
- renameSync3(oldLedgerPath, oldLedgerBackupPath);
2473
+ renameSync5(oldLedgerPath, oldLedgerBackupPath);
1526
2474
  backupExists = true;
1527
2475
  } catch (renameErr) {
1528
2476
  throw new Error(`[savePlan] Cannot reinitialize ledger: could not move old ledger aside (rename failed: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}). The existing ledger has plan_id="${existingEvents[0].plan_id}" which does not match the current plan="${planId}". To proceed, close any programs that may have the ledger file open, or run /swarm reset-session to clear the ledger.`);
@@ -1534,20 +2482,20 @@ async function savePlan(directory, plan, options) {
1534
2482
  await initLedger(directory, planId, planHashForInit, validated);
1535
2483
  initSucceeded = true;
1536
2484
  } catch (initErr) {
1537
- const errorMessage = String(initErr);
1538
- if (errorMessage.includes("already initialized")) {
2485
+ const errorMessage2 = String(initErr);
2486
+ if (errorMessage2.includes("already initialized")) {
1539
2487
  try {
1540
- if (existsSync3(oldLedgerBackupPath))
1541
- unlinkSync(oldLedgerBackupPath);
2488
+ if (existsSync6(oldLedgerBackupPath))
2489
+ unlinkSync3(oldLedgerBackupPath);
1542
2490
  } catch {}
1543
2491
  } else {
1544
- if (existsSync3(oldLedgerBackupPath)) {
2492
+ if (existsSync6(oldLedgerBackupPath)) {
1545
2493
  try {
1546
- renameSync3(oldLedgerBackupPath, oldLedgerPath);
2494
+ renameSync5(oldLedgerBackupPath, oldLedgerPath);
1547
2495
  } catch {
1548
2496
  copyFileSync(oldLedgerBackupPath, oldLedgerPath);
1549
2497
  try {
1550
- unlinkSync(oldLedgerBackupPath);
2498
+ unlinkSync3(oldLedgerBackupPath);
1551
2499
  } catch {}
1552
2500
  }
1553
2501
  }
@@ -1556,21 +2504,21 @@ async function savePlan(directory, plan, options) {
1556
2504
  }
1557
2505
  }
1558
2506
  if (initSucceeded && backupExists) {
1559
- const archivePath = path3.join(swarmDir2, `plan-ledger.archived-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
2507
+ const archivePath = path6.join(swarmDir2, `plan-ledger.archived-${Date.now()}-${Math.floor(Math.random() * 1e9)}.jsonl`);
1560
2508
  try {
1561
- renameSync3(oldLedgerBackupPath, archivePath);
2509
+ renameSync5(oldLedgerBackupPath, archivePath);
1562
2510
  warn(`[savePlan] Ledger identity mismatch (was "${existingEvents[0].plan_id}", now "${planId}") \u2014 archived old ledger to ${archivePath} and reinitializing.`);
1563
2511
  } catch (renameErr) {
1564
2512
  warn(`[savePlan] Could not archive old ledger (rename failed: ${renameErr instanceof Error ? renameErr.message : String(renameErr)}). Old ledger may still exist at ${oldLedgerBackupPath}.`);
1565
2513
  try {
1566
- if (existsSync3(oldLedgerBackupPath))
1567
- unlinkSync(oldLedgerBackupPath);
2514
+ if (existsSync6(oldLedgerBackupPath))
2515
+ unlinkSync3(oldLedgerBackupPath);
1568
2516
  } catch {}
1569
2517
  }
1570
2518
  } else if (!initSucceeded && backupExists) {
1571
2519
  try {
1572
- if (existsSync3(oldLedgerBackupPath))
1573
- unlinkSync(oldLedgerBackupPath);
2520
+ if (existsSync6(oldLedgerBackupPath))
2521
+ unlinkSync3(oldLedgerBackupPath);
1574
2522
  } catch {}
1575
2523
  }
1576
2524
  const MAX_ARCHIVED_SIBLINGS = 5;
@@ -1581,7 +2529,7 @@ async function savePlan(directory, plan, options) {
1581
2529
  const toRemove = archivedSiblings.slice(0, archivedSiblings.length - MAX_ARCHIVED_SIBLINGS);
1582
2530
  for (const file of toRemove) {
1583
2531
  try {
1584
- unlinkSync(path3.join(swarmDir2, file));
2532
+ unlinkSync3(path6.join(swarmDir2, file));
1585
2533
  } catch {}
1586
2534
  }
1587
2535
  }
@@ -1646,7 +2594,7 @@ async function savePlan(directory, plan, options) {
1646
2594
  expectedHash: currentHash,
1647
2595
  planHashAfter: hashAfter,
1648
2596
  verifyValid: async () => {
1649
- const onDisk = await _internals2.loadPlanJsonOnly(directory);
2597
+ const onDisk = await _internals4.loadPlanJsonOnly(directory);
1650
2598
  if (!onDisk)
1651
2599
  return true;
1652
2600
  for (const p of onDisk.phases) {
@@ -1657,11 +2605,11 @@ async function savePlan(directory, plan, options) {
1657
2605
  }
1658
2606
  });
1659
2607
  }
1660
- } catch (error) {
1661
- if (error instanceof LedgerStaleWriterError) {
1662
- throw new PlanConcurrentModificationError(`Concurrent plan modification detected after retries: ${error.message}. Please retry the operation.`);
2608
+ } catch (error2) {
2609
+ if (error2 instanceof LedgerStaleWriterError) {
2610
+ throw new PlanConcurrentModificationError(`Concurrent plan modification detected after retries: ${error2.message}. Please retry the operation.`);
1663
2611
  }
1664
- throw error;
2612
+ throw error2;
1665
2613
  }
1666
2614
  }
1667
2615
  try {
@@ -1684,7 +2632,7 @@ async function savePlan(directory, plan, options) {
1684
2632
  expectedHash: currentHash,
1685
2633
  planHashAfter: hashAfter,
1686
2634
  verifyValid: async () => {
1687
- const onDisk = await _internals2.loadPlanJsonOnly(directory);
2635
+ const onDisk = await _internals4.loadPlanJsonOnly(directory);
1688
2636
  if (!onDisk)
1689
2637
  return true;
1690
2638
  for (const p of onDisk.phases) {
@@ -1699,11 +2647,11 @@ async function savePlan(directory, plan, options) {
1699
2647
  }
1700
2648
  }
1701
2649
  }
1702
- } catch (error) {
1703
- if (error instanceof LedgerStaleWriterError) {
1704
- throw new PlanConcurrentModificationError(`Concurrent plan modification detected after retries: ${error.message}. Please retry the operation.`);
2650
+ } catch (error2) {
2651
+ if (error2 instanceof LedgerStaleWriterError) {
2652
+ throw new PlanConcurrentModificationError(`Concurrent plan modification detected after retries: ${error2.message}. Please retry the operation.`);
1705
2653
  }
1706
- throw error;
2654
+ throw error2;
1707
2655
  }
1708
2656
  }
1709
2657
  const SNAPSHOT_INTERVAL = 50;
@@ -1714,19 +2662,19 @@ async function savePlan(directory, plan, options) {
1714
2662
  source: "savePlan_manager"
1715
2663
  });
1716
2664
  }
1717
- const swarmDir = path3.resolve(directory, ".swarm");
1718
- const planPath = path3.join(swarmDir, "plan.json");
1719
- const tempPath = path3.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2665
+ const swarmDir = path6.resolve(directory, ".swarm");
2666
+ const planPath = path6.join(swarmDir, "plan.json");
2667
+ const tempPath = path6.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
1720
2668
  try {
1721
2669
  await bunWrite(tempPath, JSON.stringify(validated, null, 2));
1722
- renameSync3(tempPath, planPath);
2670
+ renameSync5(tempPath, planPath);
1723
2671
  } finally {
1724
2672
  try {
1725
- unlinkSync(tempPath);
2673
+ unlinkSync3(tempPath);
1726
2674
  } catch {}
1727
2675
  }
1728
2676
  try {
1729
- const markerPath = path3.join(swarmDir, ".plan-write-marker");
2677
+ const markerPath = path6.join(swarmDir, ".plan-write-marker");
1730
2678
  const inProgressMarker = JSON.stringify({
1731
2679
  source: "plan_manager",
1732
2680
  timestamp: new Date().toISOString(),
@@ -1741,14 +2689,14 @@ async function savePlan(directory, plan, options) {
1741
2689
  const markdown = derivePlanMarkdown(validated);
1742
2690
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
1743
2691
  ${markdown}`;
1744
- const mdPath = path3.join(swarmDir, "plan.md");
1745
- const mdTempPath = path3.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2692
+ const mdPath = path6.join(swarmDir, "plan.md");
2693
+ const mdTempPath = path6.join(swarmDir, `plan.md.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
1746
2694
  try {
1747
2695
  await bunWrite(mdTempPath, markdownWithHash);
1748
- renameSync3(mdTempPath, mdPath);
2696
+ renameSync5(mdTempPath, mdPath);
1749
2697
  } finally {
1750
2698
  try {
1751
- unlinkSync(mdTempPath);
2699
+ unlinkSync3(mdTempPath);
1752
2700
  } catch {}
1753
2701
  }
1754
2702
  } catch (mdError) {
@@ -1763,7 +2711,7 @@ ${markdown}`;
1763
2711
  } catch {}
1764
2712
  }
1765
2713
  try {
1766
- const markerPath = path3.join(swarmDir, ".plan-write-marker");
2714
+ const markerPath = path6.join(swarmDir, ".plan-write-marker");
1767
2715
  const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
1768
2716
  const marker = JSON.stringify({
1769
2717
  source: "plan_manager",
@@ -1779,14 +2727,14 @@ async function rebuildPlan(directory, plan, options) {
1779
2727
  const targetPlan = plan ?? await replayFromLedger(directory);
1780
2728
  if (!targetPlan)
1781
2729
  return null;
1782
- const swarmDir = path3.join(directory, ".swarm");
1783
- const planPath = path3.join(swarmDir, "plan.json");
1784
- const mdPath = path3.join(swarmDir, "plan.md");
1785
- const tempPlanPath = path3.join(swarmDir, `plan.json.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2730
+ const swarmDir = path6.join(directory, ".swarm");
2731
+ const planPath = path6.join(swarmDir, "plan.json");
2732
+ const mdPath = path6.join(swarmDir, "plan.md");
2733
+ const tempPlanPath = path6.join(swarmDir, `plan.json.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
1786
2734
  await bunWrite(tempPlanPath, JSON.stringify(targetPlan, null, 2));
1787
- renameSync3(tempPlanPath, planPath);
2735
+ renameSync5(tempPlanPath, planPath);
1788
2736
  try {
1789
- const markerPath = path3.join(swarmDir, ".plan-write-marker");
2737
+ const markerPath = path6.join(swarmDir, ".plan-write-marker");
1790
2738
  const inProgressMarker = JSON.stringify({
1791
2739
  source: "plan_manager",
1792
2740
  timestamp: new Date().toISOString(),
@@ -1801,12 +2749,12 @@ async function rebuildPlan(directory, plan, options) {
1801
2749
  const markdown = derivePlanMarkdown(targetPlan);
1802
2750
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
1803
2751
  ${markdown}`;
1804
- const tempMdPath = path3.join(swarmDir, `plan.md.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2752
+ const tempMdPath = path6.join(swarmDir, `plan.md.rebuild.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
1805
2753
  await bunWrite(tempMdPath, markdownWithHash);
1806
- renameSync3(tempMdPath, mdPath);
2754
+ renameSync5(tempMdPath, mdPath);
1807
2755
  } finally {
1808
2756
  try {
1809
- const markerPath = path3.join(swarmDir, ".plan-write-marker");
2757
+ const markerPath = path6.join(swarmDir, ".plan-write-marker");
1810
2758
  const tasksCount = targetPlan.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
1811
2759
  const marker = JSON.stringify({
1812
2760
  source: "plan_manager",
@@ -1869,13 +2817,13 @@ async function closePlanTerminalState(directory, plan, options) {
1869
2817
  planHashAfter: hashAfter,
1870
2818
  source: "close_terminal"
1871
2819
  });
1872
- const swarmDir = path3.join(directory, ".swarm");
1873
- const planPath = path3.join(swarmDir, "plan.json");
1874
- const tempPlanPath = path3.join(swarmDir, `plan.json.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2820
+ const swarmDir = path6.join(directory, ".swarm");
2821
+ const planPath = path6.join(swarmDir, "plan.json");
2822
+ const tempPlanPath = path6.join(swarmDir, `plan.json.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
1875
2823
  await bunWrite(tempPlanPath, JSON.stringify(validated, null, 2));
1876
- renameSync3(tempPlanPath, planPath);
2824
+ renameSync5(tempPlanPath, planPath);
1877
2825
  try {
1878
- const markerPath = path3.join(swarmDir, ".plan-write-marker");
2826
+ const markerPath = path6.join(swarmDir, ".plan-write-marker");
1879
2827
  const inProgressMarker = JSON.stringify({
1880
2828
  source: "plan_manager_close",
1881
2829
  timestamp: new Date().toISOString(),
@@ -1886,17 +2834,17 @@ async function closePlanTerminalState(directory, plan, options) {
1886
2834
  await bunWrite(markerPath, inProgressMarker);
1887
2835
  } catch {}
1888
2836
  try {
1889
- const mdPath = path3.join(swarmDir, "plan.md");
2837
+ const mdPath = path6.join(swarmDir, "plan.md");
1890
2838
  const contentHash = computePlanContentHash(validated);
1891
2839
  const markdown = derivePlanMarkdown(validated);
1892
2840
  const markdownWithHash = `<!-- PLAN_HASH: ${contentHash} -->
1893
2841
  ${markdown}`;
1894
- const mdTempPath = path3.join(swarmDir, `plan.md.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
2842
+ const mdTempPath = path6.join(swarmDir, `plan.md.close.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
1895
2843
  await bunWrite(mdTempPath, markdownWithHash);
1896
- renameSync3(mdTempPath, mdPath);
2844
+ renameSync5(mdTempPath, mdPath);
1897
2845
  } finally {
1898
2846
  try {
1899
- const markerPath = path3.join(swarmDir, ".plan-write-marker");
2847
+ const markerPath = path6.join(swarmDir, ".plan-write-marker");
1900
2848
  const tasksCount = validated.phases.reduce((sum, phase) => sum + phase.tasks.length, 0);
1901
2849
  const marker = JSON.stringify({
1902
2850
  source: "plan_manager_close",
@@ -2180,14 +3128,14 @@ function migrateLegacyPlan(planContent, swarmId) {
2180
3128
 
2181
3129
  // src/evidence/manager.ts
2182
3130
  import {
2183
- mkdirSync as mkdirSync3,
3131
+ mkdirSync as mkdirSync5,
2184
3132
  readdirSync as readdirSync3,
2185
3133
  realpathSync,
2186
3134
  rmSync,
2187
3135
  statSync
2188
3136
  } from "fs";
2189
- import * as fs3 from "fs/promises";
2190
- import * as path4 from "path";
3137
+ import * as fs6 from "fs/promises";
3138
+ import * as path7 from "path";
2191
3139
 
2192
3140
  // src/config/evidence-schema.ts
2193
3141
  var EVIDENCE_MAX_JSON_BYTES = 500 * 1024;
@@ -2519,22 +3467,22 @@ function validateProjectRoot(directory) {
2519
3467
  if (depth >= MAX_DEPTH)
2520
3468
  break;
2521
3469
  depth++;
2522
- const parent = path4.dirname(current);
3470
+ const parent = path7.dirname(current);
2523
3471
  if (parent === current)
2524
3472
  break;
2525
- const parentSwarm = path4.join(parent, ".swarm");
3473
+ const parentSwarm = path7.join(parent, ".swarm");
2526
3474
  try {
2527
3475
  if (statSync(parentSwarm).isDirectory()) {
2528
3476
  let hasProjectIndicator = false;
2529
3477
  for (const indicator of PROJECT_INDICATORS) {
2530
3478
  try {
2531
- const indicatorStat = statSync(path4.join(parent, indicator));
3479
+ const indicatorStat = statSync(path7.join(parent, indicator));
2532
3480
  if (indicatorStat.isFile() || indicatorStat.isDirectory()) {
2533
3481
  hasProjectIndicator = true;
2534
3482
  break;
2535
3483
  }
2536
- } catch (error) {
2537
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {} else {
3484
+ } catch (error2) {
3485
+ if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT") {} else {
2538
3486
  hasProjectIndicator = true;
2539
3487
  break;
2540
3488
  }
@@ -2545,30 +3493,30 @@ function validateProjectRoot(directory) {
2545
3493
  throw new Error(`Cannot write evidence in "${resolved}" \u2014 parent directory "${parent}" already contains a .swarm/ folder. Evidence must be written to the project root.`);
2546
3494
  }
2547
3495
  }
2548
- } catch (error) {
2549
- if (error instanceof Error && error.message.startsWith("Cannot write evidence")) {
2550
- throw error;
3496
+ } catch (error2) {
3497
+ if (error2 instanceof Error && error2.message.startsWith("Cannot write evidence")) {
3498
+ throw error2;
2551
3499
  }
2552
3500
  }
2553
3501
  current = parent;
2554
3502
  }
2555
3503
  }
2556
3504
  async function saveEvidence(directory, taskId, evidence) {
2557
- _internals3.validateProjectRoot(directory);
3505
+ _internals5.validateProjectRoot(directory);
2558
3506
  const sanitizedTaskId = sanitizeTaskId2(taskId);
2559
- const relativePath = path4.join("evidence", sanitizedTaskId, "evidence.json");
3507
+ const relativePath = path7.join("evidence", sanitizedTaskId, "evidence.json");
2560
3508
  validateSwarmPath(directory, relativePath);
2561
3509
  return withEvidenceLock(directory, relativePath, "evidence-manager", sanitizedTaskId, async () => {
2562
3510
  const evidencePath = validateSwarmPath(directory, relativePath);
2563
- const evidenceDir = path4.dirname(evidencePath);
3511
+ const evidenceDir = path7.dirname(evidencePath);
2564
3512
  let bundle;
2565
3513
  const existingContent = await readSwarmFileAsync(directory, relativePath);
2566
3514
  if (existingContent !== null) {
2567
3515
  try {
2568
3516
  const parsed = JSON.parse(existingContent);
2569
3517
  bundle = EvidenceBundleSchema.parse(parsed);
2570
- } catch (error) {
2571
- warn(`Existing evidence bundle invalid for task ${sanitizedTaskId}, creating new: ${error instanceof Error ? error.message : String(error)}`);
3518
+ } catch (error2) {
3519
+ warn(`Existing evidence bundle invalid for task ${sanitizedTaskId}, creating new: ${error2 instanceof Error ? error2.message : String(error2)}`);
2572
3520
  const now = new Date().toISOString();
2573
3521
  bundle = {
2574
3522
  schema_version: "1.0.0",
@@ -2602,16 +3550,16 @@ async function saveEvidence(directory, taskId, evidence) {
2602
3550
  if (bundleJson.length > EVIDENCE_MAX_JSON_BYTES) {
2603
3551
  throw new Error(`Evidence bundle size (${bundleJson.length} bytes) exceeds maximum (${EVIDENCE_MAX_JSON_BYTES} bytes)`);
2604
3552
  }
2605
- mkdirSync3(evidenceDir, { recursive: true });
2606
- const tempPath = path4.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
3553
+ mkdirSync5(evidenceDir, { recursive: true });
3554
+ const tempPath = path7.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
2607
3555
  try {
2608
3556
  await bunWrite(tempPath, bundleJson);
2609
- await fs3.rename(tempPath, evidencePath);
2610
- } catch (error) {
3557
+ await fs6.rename(tempPath, evidencePath);
3558
+ } catch (error2) {
2611
3559
  try {
2612
3560
  rmSync(tempPath, { force: true });
2613
3561
  } catch {}
2614
- throw error;
3562
+ throw error2;
2615
3563
  }
2616
3564
  return updatedBundle;
2617
3565
  });
@@ -2647,7 +3595,7 @@ function wrapFlatRetrospective(flatEntry, taskId) {
2647
3595
  }
2648
3596
  async function loadEvidence(directory, taskId) {
2649
3597
  const sanitizedTaskId = sanitizeTaskId2(taskId);
2650
- const relativePath = path4.join("evidence", sanitizedTaskId, "evidence.json");
3598
+ const relativePath = path7.join("evidence", sanitizedTaskId, "evidence.json");
2651
3599
  if (relativePath.length > 4096) {
2652
3600
  return { status: "not_found" };
2653
3601
  }
@@ -2663,17 +3611,17 @@ async function loadEvidence(directory, taskId) {
2663
3611
  return { status: "invalid_schema", errors: ["Invalid JSON"] };
2664
3612
  }
2665
3613
  if (isFlatRetrospective(parsed)) {
2666
- const wrappedBundle = _internals3.wrapFlatRetrospective(parsed, sanitizedTaskId);
3614
+ const wrappedBundle = _internals5.wrapFlatRetrospective(parsed, sanitizedTaskId);
2667
3615
  try {
2668
3616
  const validated = EvidenceBundleSchema.parse(wrappedBundle);
2669
3617
  try {
2670
3618
  await withEvidenceLock(directory, relativePath, "evidence-loader", sanitizedTaskId, async () => {
2671
- const evidenceDir = path4.dirname(evidencePath);
3619
+ const evidenceDir = path7.dirname(evidencePath);
2672
3620
  const bundleJson = JSON.stringify(validated);
2673
- const tempPath = path4.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
3621
+ const tempPath = path7.join(evidenceDir, `evidence.json.tmp.${Date.now()}.${process.pid}`);
2674
3622
  try {
2675
3623
  await bunWrite(tempPath, bundleJson);
2676
- await fs3.rename(tempPath, evidencePath);
3624
+ await fs6.rename(tempPath, evidencePath);
2677
3625
  } catch (writeError) {
2678
3626
  try {
2679
3627
  rmSync(tempPath, { force: true });
@@ -2685,18 +3633,18 @@ async function loadEvidence(directory, taskId) {
2685
3633
  warn(`Evidence lock failed during flat-retrospective write-back for task ${sanitizedTaskId}: ${lockErr instanceof Error ? lockErr.message : String(lockErr)}`);
2686
3634
  }
2687
3635
  return { status: "found", bundle: validated };
2688
- } catch (error) {
2689
- warn(`Wrapped flat retrospective failed validation for task ${sanitizedTaskId}: ${error instanceof Error ? error.message : String(error)}`);
2690
- const errors = error instanceof ZodError ? error.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [error instanceof Error ? error.message : String(error)];
3636
+ } catch (error2) {
3637
+ warn(`Wrapped flat retrospective failed validation for task ${sanitizedTaskId}: ${error2 instanceof Error ? error2.message : String(error2)}`);
3638
+ const errors = error2 instanceof ZodError ? error2.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [error2 instanceof Error ? error2.message : String(error2)];
2691
3639
  return { status: "invalid_schema", errors };
2692
3640
  }
2693
3641
  }
2694
3642
  try {
2695
3643
  const validated = EvidenceBundleSchema.parse(parsed);
2696
3644
  return { status: "found", bundle: validated };
2697
- } catch (error) {
2698
- warn(`Evidence bundle validation failed for task ${sanitizedTaskId}: ${error instanceof Error ? error.message : String(error)}`);
2699
- const errors = error instanceof ZodError ? error.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [error instanceof Error ? error.message : String(error)];
3645
+ } catch (error2) {
3646
+ warn(`Evidence bundle validation failed for task ${sanitizedTaskId}: ${error2 instanceof Error ? error2.message : String(error2)}`);
3647
+ const errors = error2 instanceof ZodError ? error2.issues.map((e) => `${e.path.join(".")}: ${e.message}`) : [error2 instanceof Error ? error2.message : String(error2)];
2700
3648
  return { status: "invalid_schema", errors };
2701
3649
  }
2702
3650
  }
@@ -2715,7 +3663,7 @@ async function listEvidenceTaskIds(directory) {
2715
3663
  }
2716
3664
  const taskIds = [];
2717
3665
  for (const entry of entries) {
2718
- const entryPath = path4.join(evidenceBasePath, entry);
3666
+ const entryPath = path7.join(evidenceBasePath, entry);
2719
3667
  try {
2720
3668
  const stats = statSync(entryPath);
2721
3669
  if (!stats.isDirectory()) {
@@ -2723,9 +3671,9 @@ async function listEvidenceTaskIds(directory) {
2723
3671
  }
2724
3672
  sanitizeTaskId2(entry);
2725
3673
  taskIds.push(entry);
2726
- } catch (error) {
2727
- if (error instanceof Error && !error.message.startsWith("Invalid task ID")) {
2728
- warn(`Error reading evidence entry '${entry}': ${error.message}`);
3674
+ } catch (error2) {
3675
+ if (error2 instanceof Error && !error2.message.startsWith("Invalid task ID")) {
3676
+ warn(`Error reading evidence entry '${entry}': ${error2.message}`);
2729
3677
  }
2730
3678
  }
2731
3679
  }
@@ -2733,7 +3681,7 @@ async function listEvidenceTaskIds(directory) {
2733
3681
  }
2734
3682
  async function deleteEvidence(directory, taskId) {
2735
3683
  const sanitizedTaskId = sanitizeTaskId2(taskId);
2736
- const relativePath = path4.join("evidence", sanitizedTaskId);
3684
+ const relativePath = path7.join("evidence", sanitizedTaskId);
2737
3685
  const evidenceDir = validateSwarmPath(directory, relativePath);
2738
3686
  try {
2739
3687
  statSync(evidenceDir);
@@ -2743,30 +3691,30 @@ async function deleteEvidence(directory, taskId) {
2743
3691
  try {
2744
3692
  rmSync(evidenceDir, { recursive: true, force: true });
2745
3693
  return true;
2746
- } catch (error) {
2747
- warn(`Failed to delete evidence for task ${sanitizedTaskId}: ${error instanceof Error ? error.message : String(error)}`);
3694
+ } catch (error2) {
3695
+ warn(`Failed to delete evidence for task ${sanitizedTaskId}: ${error2 instanceof Error ? error2.message : String(error2)}`);
2748
3696
  return false;
2749
3697
  }
2750
3698
  }
2751
3699
  async function checkRequirementCoverage(phase, directory) {
2752
- const relativePath = path4.join("evidence", `req-coverage-phase-${phase}.json`);
2753
- const absolutePath = path4.resolve(directory, ".swarm", relativePath);
3700
+ const relativePath = path7.join("evidence", `req-coverage-phase-${phase}.json`);
3701
+ const absolutePath = path7.resolve(directory, ".swarm", relativePath);
2754
3702
  try {
2755
- await fs3.access(absolutePath);
3703
+ await fs6.access(absolutePath);
2756
3704
  return { exists: true, path: absolutePath };
2757
3705
  } catch {
2758
3706
  return { exists: false, path: absolutePath };
2759
3707
  }
2760
3708
  }
2761
3709
  async function archiveEvidence(directory, maxAgeDays, maxBundles) {
2762
- const taskIds = await _internals3.listEvidenceTaskIds(directory);
3710
+ const taskIds = await _internals5.listEvidenceTaskIds(directory);
2763
3711
  const cutoffDate = new Date;
2764
3712
  cutoffDate.setDate(cutoffDate.getDate() - maxAgeDays);
2765
3713
  const cutoffIso = cutoffDate.toISOString();
2766
3714
  const archived = [];
2767
3715
  const remainingBundles = [];
2768
3716
  for (const taskId of taskIds) {
2769
- const result = await _internals3.loadEvidence(directory, taskId);
3717
+ const result = await _internals5.loadEvidence(directory, taskId);
2770
3718
  if (result.status !== "found") {
2771
3719
  continue;
2772
3720
  }
@@ -2794,7 +3742,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles) {
2794
3742
  }
2795
3743
  return archived;
2796
3744
  }
2797
- var _internals3 = {
3745
+ var _internals5 = {
2798
3746
  wrapFlatRetrospective,
2799
3747
  loadEvidence,
2800
3748
  listEvidenceTaskIds,
@@ -2911,4 +3859,4 @@ function mergeDurableGateEntriesFromEvidence(taskId, entries, evidence) {
2911
3859
  return merged;
2912
3860
  }
2913
3861
 
2914
- export { PlanSchema, loadSddStatusSync, buildOpenSpecProjectionSync, readEffectiveSpecSync, writeProjectedSpecSync, computeSpecHash, derivePlanId, computePlanHash, initLedger, appendLedgerEvent, loadPlanJsonOnly, loadPlan, savePlan, closePlanTerminalState, derivePlanMarkdown, RetrospectiveEvidenceSchema, isValidEvidenceType, sanitizeTaskId2 as sanitizeTaskId, validateProjectRoot, saveEvidence, loadEvidence, listEvidenceTaskIds, checkRequirementCoverage, archiveEvidence, readDurableGateEvidence, getDurableGateEvidenceStatus, getDurableGateEvidenceStatusForTask, mergeDurableGateEntriesFromEvidence };
3862
+ export { PlanSchema, getGitRepositoryStatus, isGitRepo, resetToRemoteBranch, resetToMainAfterMerge, isStateUnreadable, loadEpicSessionState, isEpicModeActive, enableEpicMode, disableEpicMode, normalizePath, pathsConflict, isGlobalFile, isProtectedPath, readTaskScopes, loadSddStatusSync, buildOpenSpecProjectionSync, readEffectiveSpecSync, writeProjectedSpecSync, computeSpecHash, derivePlanId, computePlanHash, initLedger, appendLedgerEvent, loadPlanJsonOnly, loadPlan, savePlan, closePlanTerminalState, derivePlanMarkdown, RetrospectiveEvidenceSchema, isValidEvidenceType, sanitizeTaskId2 as sanitizeTaskId, validateProjectRoot, saveEvidence, loadEvidence, listEvidenceTaskIds, checkRequirementCoverage, archiveEvidence, readDurableGateEvidence, getDurableGateEvidenceStatus, getDurableGateEvidenceStatusForTask, mergeDurableGateEntriesFromEvidence };