opencode-swarm 7.152.1 → 7.153.1

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 (121) hide show
  1. package/.opencode/skills/swarm-pr-review/SKILL.md +10 -10
  2. package/dist/background/pending-delegations.d.ts +7 -0
  3. package/dist/cli/{capability-probe-va4kk8vg.js → capability-probe-5wa7mcp6.js} +3 -2
  4. package/dist/cli/{config-doctor-bbqmye7a.js → config-doctor-ze21qs6b.js} +3 -3
  5. package/dist/cli/{core-fh4e6ex0.js → core-qdmhh1kx.js} +2 -2
  6. package/dist/cli/{curation-policy-nem98yc9.js → curation-policy-twa6agf8.js} +7 -7
  7. package/dist/cli/{curator-909s9dvs.js → curator-hxb3wsxr.js} +32 -33
  8. package/dist/cli/curator-llm-factory-s8atmc2n.js +64 -0
  9. package/dist/cli/{evidence-summary-service-kqw4y0yr.js → evidence-summary-service-wzzym9r7.js} +15 -15
  10. package/dist/cli/{gate-evidence-ycts62pj.js → gate-evidence-f71dn9vv.js} +8 -8
  11. package/dist/cli/guardrail-explain-5kzeem4m.js +65 -0
  12. package/dist/cli/{guardrail-log-e1tmdxxa.js → guardrail-log-38jnajpa.js} +6 -6
  13. package/dist/cli/{guardrail-reset-gdnaxxvb.js → guardrail-reset-wzvtmpn2.js} +32 -33
  14. package/dist/cli/{hive-promoter-d0xydg6r.js → hive-promoter-55qcqgfx.js} +32 -33
  15. package/dist/cli/{index-x6803sxh.js → index-0tyc8kdg.js} +2 -2
  16. package/dist/cli/{index-z8s2asdk.js → index-0tzv5zg2.js} +22 -150
  17. package/dist/cli/{index-3djxegsc.js → index-1akn19mp.js} +1 -1
  18. package/dist/cli/{index-q77e475x.js → index-1dtshrzg.js} +5 -5
  19. package/dist/cli/{index-73pmnsjg.js → index-1gzdnjg9.js} +2 -2
  20. package/dist/cli/{index-4tvvh7pn.js → index-23rneydq.js} +36 -35
  21. package/dist/cli/{index-z4bg1hv8.js → index-2mqmvxac.js} +9 -2
  22. package/dist/cli/index-3cegckkq.js +239 -0
  23. package/dist/cli/{index-pvrap7xg.js → index-3ttktt56.js} +1 -1
  24. package/dist/cli/{index-85gkedsf.js → index-4fwbbad3.js} +521 -15
  25. package/dist/cli/{index-qqrdmaxq.js → index-4g0g3dqz.js} +2 -2
  26. package/dist/cli/{index-44xdtqz8.js → index-4pjkdcgc.js} +1 -1
  27. package/dist/cli/{index-29vd7v3e.js → index-6vgb5fyb.js} +1 -1
  28. package/dist/cli/{index-sg2sx2q7.js → index-6ybjrqf7.js} +13095 -9360
  29. package/dist/cli/{index-txbd25bc.js → index-891g7hbf.js} +1 -1
  30. package/dist/cli/{index-02ajc6d1.js → index-8v9sj4aq.js} +2 -2
  31. package/dist/cli/{index-z9fyd0d6.js → index-9v8d3c0k.js} +450 -48
  32. package/dist/cli/{index-26vyr198.js → index-af0cqe6n.js} +16 -16
  33. package/dist/cli/{index-ryecg2st.js → index-ajkxx2k6.js} +3 -3
  34. package/dist/cli/{index-k3d919yf.js → index-gn26q90p.js} +85 -24
  35. package/dist/cli/{index-0tfgn5x0.js → index-k10qtq71.js} +9 -9
  36. package/dist/cli/{index-xyfdmrv7.js → index-mb7b1gye.js} +3 -3
  37. package/dist/cli/{index-0q2mjxp2.js → index-meg33yyv.js} +1 -1
  38. package/dist/cli/{index-cpg98bh1.js → index-myt57pht.js} +1 -1
  39. package/dist/cli/{index-2e1294d1.js → index-n5pxkera.js} +16 -10
  40. package/dist/cli/{index-n0vc5b5t.js → index-n823qsae.js} +16 -7
  41. package/dist/cli/{index-6zkm4p7p.js → index-pk1gbqmq.js} +1 -1
  42. package/dist/cli/{index-nd8tkb3g.js → index-smqsp8hs.js} +5 -5
  43. package/dist/cli/{index-7fh82sm1.js → index-td0jz8xe.js} +6 -6
  44. package/dist/cli/{index-dn6yt0xg.js → index-tdzbm974.js} +7 -7
  45. package/dist/cli/{index-rq6aetkv.js → index-v689bmr2.js} +4 -4
  46. package/dist/cli/{index-79g6edht.js → index-x3y6zhgj.js} +1 -1
  47. package/dist/cli/{index-aw492hpn.js → index-x8vw6ap1.js} +58 -41
  48. package/dist/cli/{index-96m8ckpq.js → index-xkjrg9k4.js} +4 -4
  49. package/dist/cli/{index-mken64yj.js → index-zppxpc3y.js} +2 -2
  50. package/dist/cli/index.js +32 -33
  51. package/dist/cli/{knowledge-escalator-4egcr928.js → knowledge-escalator-w05ztgvk.js} +13 -13
  52. package/dist/cli/{knowledge-events-kdyv4jzn.js → knowledge-events-pwm9jc0m.js} +11 -11
  53. package/dist/cli/{knowledge-link-h8cwj7af.js → knowledge-link-ge0rddxw.js} +6 -6
  54. package/dist/cli/{knowledge-store-dq3cvg53.js → knowledge-store-4xv65tj2.js} +7 -7
  55. package/dist/cli/{knowledge-validator-4bhtden9.js → knowledge-validator-0ttfsca7.js} +9 -9
  56. package/dist/cli/{model-preflight-7ea00h34.js → model-preflight-b95w8wxy.js} +1 -1
  57. package/dist/cli/{pending-delegations-a2nmssr1.js → pending-delegations-nk78wx7h.js} +4 -4
  58. package/dist/cli/{pr-subscriptions-7879nq5k.js → pr-subscriptions-dq1f61ye.js} +4 -4
  59. package/dist/cli/{runner-w81n9js3.js → runner-n50w1y4w.js} +7 -7
  60. package/dist/cli/{scan-cursor-2eezv81a.js → scan-cursor-b6n15w8d.js} +8 -8
  61. package/dist/cli/{schema-v4qcqhek.js → schema-jkbfwqr2.js} +2 -2
  62. package/dist/cli/{scope-persistence-y2r227r0.js → scope-persistence-5xt2m5ep.js} +10 -10
  63. package/dist/cli/{skill-generator-hhzxvb3h.js → skill-generator-3keadpf7.js} +15 -15
  64. package/dist/cli/{telemetry-52pw5xac.js → telemetry-hh1j99za.js} +1 -1
  65. package/dist/cli/{worktree-collision-ownership-p31zm5k0.js → worktree-collision-ownership-4drcjymy.js} +15 -10
  66. package/dist/cli/{worktree-isolation-ve338ez6.js → worktree-isolation-1ymaxn4h.js} +32 -33
  67. package/dist/commands/approve-write.d.ts +1 -0
  68. package/dist/commands/index.d.ts +1 -0
  69. package/dist/commands/lanes.d.ts +25 -0
  70. package/dist/commands/registry.d.ts +7 -0
  71. package/dist/config/schema.d.ts +39 -4
  72. package/dist/consensus/contracts.d.ts +14 -0
  73. package/dist/consensus/corpus.d.ts +16 -0
  74. package/dist/hooks/delegation-gate/worktree-isolation.d.ts +50 -3
  75. package/dist/hooks/delegation-gate/worktree-provisioning-owner.d.ts +40 -2
  76. package/dist/hooks/delegation-gate/worktree-recovery-authority.d.ts +201 -0
  77. package/dist/hooks/full-auto-permission.d.ts +7 -0
  78. package/dist/hooks/guardrails/index.d.ts +2 -1
  79. package/dist/hooks/guardrails/tool-before.d.ts +4 -0
  80. package/dist/hooks/init-orphan-recovery.d.ts +5 -1
  81. package/dist/hooks/pr-workflow-gate.d.ts +12 -0
  82. package/dist/hooks/scope-guard.d.ts +1 -3
  83. package/dist/hooks/trajectory-logger.d.ts +22 -6
  84. package/dist/hooks/trajectory-step-state.d.ts +43 -2
  85. package/dist/index.js +645 -622
  86. package/dist/learning/provenance.d.ts +9 -0
  87. package/dist/observability/catalog.d.ts +6 -4
  88. package/dist/prm/index.d.ts +3 -3
  89. package/dist/prm/replay.d.ts +29 -2
  90. package/dist/prm/trajectory-store.d.ts +210 -20
  91. package/dist/sandbox/capability-probe.d.ts +40 -1
  92. package/dist/sandbox/executor.d.ts +26 -1
  93. package/dist/sandbox/linux/bubblewrap-executor.d.ts +3 -1
  94. package/dist/sandbox/macos/sandbox-exec-executor.d.ts +3 -1
  95. package/dist/sandbox/skip-state.d.ts +24 -0
  96. package/dist/sandbox/win32/native-sandbox-executor.d.ts +5 -1
  97. package/dist/security/command-classifier.d.ts +22 -0
  98. package/dist/security/protected-input-integrity.d.ts +19 -0
  99. package/dist/security/protected-path-policy.d.ts +9 -0
  100. package/dist/security/write-authority.d.ts +46 -0
  101. package/dist/services/diagnose-service.d.ts +1 -1
  102. package/dist/services/skill-generator.d.ts +2 -0
  103. package/dist/services/skill-improver.d.ts +69 -0
  104. package/dist/telemetry.d.ts +21 -1
  105. package/dist/tools/dispatch-lanes.d.ts +47 -0
  106. package/dist/tools/repo-graph/query.d.ts +2 -1
  107. package/dist/tools/repo-graph/types.d.ts +64 -0
  108. package/dist/tools/repo-graph.d.ts +1 -1
  109. package/dist/tools/skill-improve.d.ts +7 -0
  110. package/dist/utils/atomic-write.d.ts +2 -0
  111. package/dist/utils/canonical-root.d.ts +31 -0
  112. package/dist/workflow/coder-settlement.d.ts +2 -0
  113. package/dist/worktree/index.d.ts +2 -2
  114. package/dist/worktree/merge.d.ts +47 -0
  115. package/package.json +2 -1
  116. package/dist/cli/curator-llm-factory-462rysph.js +0 -65
  117. package/dist/cli/guardrail-explain-7620hasq.js +0 -66
  118. package/dist/cli/index-3g0xk6tk.js +0 -219
  119. package/dist/cli/index-fxvgaeq4.js +0 -125
  120. package/dist/cli/worktree-provisioning-owner-cve95q4f.js +0 -22
  121. package/dist/cli/{curator-drift-2h1d2fnq.js → curator-drift-h57z6tm3.js} +1 -1
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  emit
4
- } from "./index-aw492hpn.js";
4
+ } from "./index-x8vw6ap1.js";
5
5
  import {
6
6
  require_proper_lockfile
7
7
  } from "./index-7g4c7s5r.js";
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  readKnowledge,
4
4
  transactKnowledge
5
- } from "./index-0tfgn5x0.js";
5
+ } from "./index-k10qtq71.js";
6
6
  import {
7
7
  init_git_executable,
8
8
  resolveGitExecutableAsync
9
9
  } from "./index-9e6fdz2h.js";
10
10
  import {
11
11
  resolveKnowledgeStoreDir
12
- } from "./index-79g6edht.js";
12
+ } from "./index-x3y6zhgj.js";
13
13
  import {
14
14
  init_knowledge_types,
15
15
  isActiveStatus
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  autoCommitDirty,
4
4
  cleanUntrackedFiles
5
- } from "./index-qqrdmaxq.js";
5
+ } from "./index-4g0g3dqz.js";
6
6
  import {
7
7
  isPathWithinDeclaredScope,
8
8
  unsafePathTextReason
@@ -26,13 +26,13 @@ import {
26
26
  atomicWriteFile,
27
27
  taskEvidencePath,
28
28
  withTaskEvidenceLock
29
- } from "./index-mken64yj.js";
29
+ } from "./index-zppxpc3y.js";
30
30
  import {
31
31
  assertProjectRoot
32
- } from "./index-txbd25bc.js";
32
+ } from "./index-891g7hbf.js";
33
33
  import {
34
34
  telemetry
35
- } from "./index-aw492hpn.js";
35
+ } from "./index-x8vw6ap1.js";
36
36
  import {
37
37
  exports_external,
38
38
  init_zod
@@ -44,7 +44,7 @@ import {
44
44
  // src/gate-evidence.ts
45
45
  init_zod();
46
46
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, realpathSync as realpathSync2 } from "fs";
47
- import * as path3 from "path";
47
+ import * as path4 from "path";
48
48
 
49
49
  // src/evidence/task-gate-requirements.ts
50
50
  init_zod();
@@ -299,12 +299,14 @@ function sanitizeTaskId(taskId) {
299
299
  }
300
300
 
301
301
  // src/workflow/workflow-wal-file.ts
302
- import * as fs3 from "fs";
302
+ import * as fs4 from "fs";
303
303
  import { mkdir, open } from "fs/promises";
304
304
  import { dirname } from "path";
305
305
 
306
306
  // src/worktree/merge.ts
307
307
  init_warning_buffer();
308
+ import * as fs3 from "fs";
309
+ import * as path3 from "path";
308
310
 
309
311
  // src/turbo/lean/recovery.ts
310
312
  import * as fs2 from "fs";
@@ -398,9 +400,10 @@ init_git_executable();
398
400
  var _internals = {
399
401
  bunSpawn,
400
402
  platform: process.platform,
401
- sleep: (ms) => new Promise((resolve2) => setTimeout(resolve2, ms)),
403
+ sleep: (ms) => new Promise((resolve3) => setTimeout(resolve3, ms)),
402
404
  cleanupOrphanedBranches,
403
405
  startupOrphanRecovery,
406
+ captureMergeOverlapSnapshot,
404
407
  extractSessionId,
405
408
  resolveGitExecutable
406
409
  };
@@ -471,6 +474,285 @@ function parseConflictFiles(output) {
471
474
  return files;
472
475
  }
473
476
  var GIT_OBJECT_ID_PATTERN = /^[0-9a-f]{40}$|^[0-9a-f]{64}$/;
477
+ function abortArgsForStrategy(strategy) {
478
+ return strategy === "rebase" ? ["rebase", "--abort"] : strategy === "cherry-pick" ? ["cherry-pick", "--abort"] : ["merge", "--abort"];
479
+ }
480
+ async function finalizeMergeStrategyResult(primaryDir, strategy, result, metadata) {
481
+ if (result.exitCode === 0) {
482
+ return { merged: true, strategy, ...metadata };
483
+ }
484
+ const combinedOutput = `${result.stderr}
485
+ ${result.stdout}`;
486
+ const hasConflict = /CONFLICT/i.test(combinedOutput);
487
+ const operationState = await detectInProgressOperation(primaryDir);
488
+ if (hasConflict || operationState.inProgress) {
489
+ const abortResult = await runGit(abortArgsForStrategy(strategy), primaryDir);
490
+ if (abortResult.exitCode !== 0) {
491
+ return {
492
+ error: `${strategy} abort failed after a non-zero merge result: ${abortResult.stderr.trim() || abortResult.stdout.trim() || "unknown abort failure"}`,
493
+ ...metadata
494
+ };
495
+ }
496
+ return {
497
+ conflict: true,
498
+ files: parseConflictFiles(combinedOutput),
499
+ message: result.stderr.trim() || result.stdout.trim() || (operationState.inProgress ? `${strategy} left an in-progress operation; it was aborted` : `${strategy} reported a conflict`),
500
+ ...metadata
501
+ };
502
+ }
503
+ return {
504
+ error: result.stderr.trim() || result.stdout.trim(),
505
+ ...metadata
506
+ };
507
+ }
508
+ async function detectInProgressOperation(primaryDir) {
509
+ for (const marker of [
510
+ "MERGE_HEAD",
511
+ "CHERRY_PICK_HEAD",
512
+ "rebase-merge",
513
+ "rebase-apply",
514
+ "sequencer"
515
+ ]) {
516
+ const result = await runGit(["rev-parse", "--git-path", marker], primaryDir);
517
+ if (result.exitCode !== 0)
518
+ continue;
519
+ const rawPath = result.stdout.trim();
520
+ if (!rawPath)
521
+ continue;
522
+ const markerPath = path3.isAbsolute(rawPath) ? rawPath : path3.resolve(primaryDir, rawPath);
523
+ if (fs3.existsSync(markerPath))
524
+ return { inProgress: true };
525
+ }
526
+ return { inProgress: false };
527
+ }
528
+ function currentPathCasePolicy() {
529
+ return _internals.platform === "win32" ? "insensitive" : "sensitive";
530
+ }
531
+ function normalizeGitPath(rawPath, casePolicy) {
532
+ if (rawPath.includes("\x00")) {
533
+ return null;
534
+ }
535
+ const slashNormalized = rawPath.replaceAll("\\", "/");
536
+ const segments = slashNormalized.split("/");
537
+ const normalizedSegments = [];
538
+ const displaySegments = [];
539
+ for (const segment of segments) {
540
+ if (segment.length === 0 || segment === ".") {
541
+ continue;
542
+ }
543
+ if (segment === "..") {
544
+ return null;
545
+ }
546
+ displaySegments.push(segment);
547
+ normalizedSegments.push(casePolicy === "insensitive" ? segment.toLowerCase() : segment);
548
+ }
549
+ if (displaySegments.length === 0) {
550
+ return null;
551
+ }
552
+ return {
553
+ normalized: normalizedSegments.join("/"),
554
+ display: displaySegments.join("/")
555
+ };
556
+ }
557
+ function collapseOverlapPaths(paths) {
558
+ return Array.from(new Set(paths)).sort((a, b) => a.localeCompare(b));
559
+ }
560
+ function extractRecordPath(record, spacesToSkip) {
561
+ let cursor = 0;
562
+ for (let index = 0;index < spacesToSkip; index++) {
563
+ const next = record.indexOf(" ", cursor);
564
+ if (next === -1) {
565
+ return null;
566
+ }
567
+ cursor = next + 1;
568
+ }
569
+ return record.slice(cursor);
570
+ }
571
+ function parsePrimaryDirtyPaths(rawStatus, casePolicy) {
572
+ const paths = new Map;
573
+ const records = rawStatus.split("\x00");
574
+ for (let index = 0;index < records.length; index++) {
575
+ const record = records[index];
576
+ if (!record) {
577
+ continue;
578
+ }
579
+ switch (record[0]) {
580
+ case "1": {
581
+ const path4 = extractRecordPath(record, 8);
582
+ const normalized = path4 ? normalizeGitPath(path4, casePolicy) : null;
583
+ if (!normalized) {
584
+ return { error: `Malformed porcelain v2 entry: ${record}` };
585
+ }
586
+ paths.set(normalized.normalized, normalized.display);
587
+ break;
588
+ }
589
+ case "2": {
590
+ const path4 = extractRecordPath(record, 9);
591
+ const previousPath = records[++index];
592
+ const normalizedPath = path4 ? normalizeGitPath(path4, casePolicy) : null;
593
+ const normalizedPrevious = previousPath ? normalizeGitPath(previousPath, casePolicy) : null;
594
+ if (!normalizedPath || !normalizedPrevious) {
595
+ return {
596
+ error: `Malformed porcelain v2 rename/copy entry: ${record}`
597
+ };
598
+ }
599
+ paths.set(normalizedPath.normalized, normalizedPath.display);
600
+ paths.set(normalizedPrevious.normalized, normalizedPrevious.display);
601
+ break;
602
+ }
603
+ case "u": {
604
+ const path4 = extractRecordPath(record, 10);
605
+ const normalized = path4 ? normalizeGitPath(path4, casePolicy) : null;
606
+ if (!normalized) {
607
+ return { error: `Malformed porcelain v2 unmerged entry: ${record}` };
608
+ }
609
+ paths.set(normalized.normalized, normalized.display);
610
+ break;
611
+ }
612
+ case "?": {
613
+ const normalized = normalizeGitPath(record.slice(2), casePolicy);
614
+ if (!normalized) {
615
+ return { error: `Malformed porcelain v2 untracked entry: ${record}` };
616
+ }
617
+ paths.set(normalized.normalized, normalized.display);
618
+ break;
619
+ }
620
+ case "!":
621
+ break;
622
+ default:
623
+ return { error: `Malformed porcelain v2 record kind: ${record}` };
624
+ }
625
+ }
626
+ return { paths };
627
+ }
628
+ function parseIncomingPaths(rawDiff, casePolicy) {
629
+ const paths = new Map;
630
+ const records = rawDiff.split("\x00");
631
+ for (let index = 0;index < records.length; ) {
632
+ const status = records[index++];
633
+ if (!status) {
634
+ continue;
635
+ }
636
+ if (status.startsWith("R") || status.startsWith("C")) {
637
+ const fromPath = records[index++];
638
+ const toPath = records[index++];
639
+ const normalizedFrom = fromPath ? normalizeGitPath(fromPath, casePolicy) : null;
640
+ const normalizedTo = toPath ? normalizeGitPath(toPath, casePolicy) : null;
641
+ if (!normalizedFrom || !normalizedTo) {
642
+ return { error: `Malformed diff rename/copy entry: ${status}` };
643
+ }
644
+ paths.set(normalizedFrom.normalized, normalizedFrom.display);
645
+ paths.set(normalizedTo.normalized, normalizedTo.display);
646
+ continue;
647
+ }
648
+ const path4 = records[index++];
649
+ const normalized = path4 ? normalizeGitPath(path4, casePolicy) : null;
650
+ if (!normalized) {
651
+ return { error: `Malformed diff entry: ${status}` };
652
+ }
653
+ paths.set(normalized.normalized, normalized.display);
654
+ }
655
+ return { paths };
656
+ }
657
+ function pathsOverlap(left, right) {
658
+ return left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`);
659
+ }
660
+ function buildOverlapPaths(dirtyPaths, incomingPaths) {
661
+ const collisions = new Set;
662
+ for (const dirtyNormalized of dirtyPaths.keys()) {
663
+ for (const incomingNormalized of incomingPaths.keys()) {
664
+ if (!pathsOverlap(dirtyNormalized, incomingNormalized)) {
665
+ continue;
666
+ }
667
+ collisions.add(dirtyNormalized);
668
+ collisions.add(incomingNormalized);
669
+ }
670
+ }
671
+ return collapseOverlapPaths(collisions);
672
+ }
673
+ async function readVerifiedGitObjectId(cwd, ref, description) {
674
+ const result = await runGit(["rev-parse", "--verify", `${ref}^0`], cwd);
675
+ const oid = result.stdout.trim();
676
+ if (result.exitCode !== 0 || !GIT_OBJECT_ID_PATTERN.test(oid)) {
677
+ return {
678
+ error: `Unable to verify ${description} for overlap preflight`
679
+ };
680
+ }
681
+ return { oid };
682
+ }
683
+ async function captureMergeOverlapSnapshot(primaryDir, branchName) {
684
+ const casePolicy = currentPathCasePolicy();
685
+ const targetHead = await readVerifiedGitObjectId(primaryDir, "HEAD", "primary HEAD");
686
+ if ("error" in targetHead) {
687
+ return targetHead;
688
+ }
689
+ const laneHead = await readVerifiedGitObjectId(primaryDir, branchName, "lane HEAD");
690
+ if ("error" in laneHead) {
691
+ return laneHead;
692
+ }
693
+ const mergeBaseResult = await runGit(["merge-base", targetHead.oid, laneHead.oid], primaryDir);
694
+ const mergeBase = mergeBaseResult.stdout.trim();
695
+ if (mergeBaseResult.exitCode !== 0 || !GIT_OBJECT_ID_PATTERN.test(mergeBase)) {
696
+ return {
697
+ error: "Unable to determine incoming lane changes for overlap preflight"
698
+ };
699
+ }
700
+ const statusResult = await runGit(["status", "--porcelain=v2", "-z", "--untracked-files=all"], primaryDir);
701
+ if (statusResult.exitCode !== 0) {
702
+ return {
703
+ error: "Unable to inspect primary dirty state for overlap preflight"
704
+ };
705
+ }
706
+ const parsedStatus = parsePrimaryDirtyPaths(statusResult.stdout, casePolicy);
707
+ if ("error" in parsedStatus) {
708
+ return { error: parsedStatus.error };
709
+ }
710
+ const indexResult = await runGit(["ls-files", "--stage", "-z"], primaryDir);
711
+ if (indexResult.exitCode !== 0) {
712
+ return { error: "Unable to inspect primary index for overlap preflight" };
713
+ }
714
+ const incomingResult = await runGit([
715
+ "diff",
716
+ "--name-status",
717
+ "-z",
718
+ "--find-renames",
719
+ `${mergeBase}..${laneHead.oid}`
720
+ ], primaryDir);
721
+ if (incomingResult.exitCode !== 0) {
722
+ return {
723
+ error: "Unable to inspect incoming lane paths for overlap preflight"
724
+ };
725
+ }
726
+ const parsedIncoming = parseIncomingPaths(incomingResult.stdout, casePolicy);
727
+ if ("error" in parsedIncoming) {
728
+ return { error: parsedIncoming.error };
729
+ }
730
+ return {
731
+ snapshot: {
732
+ targetHead: targetHead.oid,
733
+ laneHead: laneHead.oid,
734
+ mergeBase,
735
+ indexDigest: indexResult.stdout,
736
+ statusDigest: statusResult.stdout,
737
+ incomingDigest: incomingResult.stdout,
738
+ overlapPaths: buildOverlapPaths(parsedStatus.paths, parsedIncoming.paths)
739
+ }
740
+ };
741
+ }
742
+ async function captureImmutableMergeOverlapSnapshot(primaryDir, coordinates) {
743
+ const snapshot = await captureMergeOverlapSnapshot(primaryDir, coordinates.sourceHeadOid);
744
+ if ("error" in snapshot)
745
+ return snapshot;
746
+ if (snapshot.snapshot.laneHead !== coordinates.sourceHeadOid || snapshot.snapshot.mergeBase !== coordinates.sourceBaseOid) {
747
+ return {
748
+ error: "Immutable recovery coordinates changed during overlap preflight; refusing merge-back"
749
+ };
750
+ }
751
+ return snapshot;
752
+ }
753
+ function sameOverlapSnapshot(left, right) {
754
+ return left.targetHead === right.targetHead && left.laneHead === right.laneHead && left.mergeBase === right.mergeBase && left.indexDigest === right.indexDigest && left.statusDigest === right.statusDigest && left.incomingDigest === right.incomingDigest;
755
+ }
474
756
  function getMergeStrategy(config) {
475
757
  return config.mergeStrategy ?? config.merge_strategy ?? "merge";
476
758
  }
@@ -495,24 +777,123 @@ async function mergeLaneBranch(primaryDir, branchName, strategy) {
495
777
  break;
496
778
  }
497
779
  }
498
- if (result.exitCode === 0) {
499
- return { merged: true, strategy };
780
+ return finalizeMergeStrategyResult(primaryDir, strategy, result, {});
781
+ }
782
+ async function requireAncestorRelation(primaryDir, ancestor, descendant, description) {
783
+ const relation = await runGit(["merge-base", "--is-ancestor", ancestor, descendant], primaryDir);
784
+ if (relation.exitCode === 0) {
785
+ return { ok: true };
500
786
  }
501
- const combinedOutput = `${result.stderr}
502
- ${result.stdout}`;
503
- const hasConflict = /CONFLICT/i.test(combinedOutput) || /conflict/i.test(combinedOutput);
504
- if (hasConflict) {
505
- const files = parseConflictFiles(combinedOutput);
506
- const abortArgs = strategy === "rebase" ? ["rebase", "--abort"] : strategy === "cherry-pick" ? ["cherry-pick", "--abort"] : ["merge", "--abort"];
507
- await runGit(abortArgs, primaryDir);
787
+ if (relation.exitCode === 1) {
788
+ return { ok: false, error: description };
789
+ }
790
+ return {
791
+ ok: false,
792
+ error: relation.stderr.trim() || relation.stdout.trim() || `git merge-base exited ${relation.exitCode}`
793
+ };
794
+ }
795
+ async function readOrderedCommitRange(primaryDir, fromExclusive, toInclusive, description) {
796
+ const revList = await runGit([
797
+ "rev-list",
798
+ "--reverse",
799
+ "--topo-order",
800
+ `${fromExclusive}..${toInclusive}`
801
+ ], primaryDir);
802
+ if (revList.exitCode !== 0) {
508
803
  return {
509
- conflict: true,
510
- files,
511
- message: result.stderr.trim()
804
+ error: revList.stderr.trim() || revList.stdout.trim() || `${description}: git rev-list exited ${revList.exitCode}`
805
+ };
806
+ }
807
+ const commits = revList.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
808
+ if (!commits.every((commit) => GIT_OBJECT_ID_PATTERN.test(commit))) {
809
+ return {
810
+ error: `${description}: git rev-list returned a malformed object id`
811
+ };
812
+ }
813
+ return { commits };
814
+ }
815
+ async function recoverMergeBackFromImmutableCoordinates(primaryDir, coordinates) {
816
+ if (!GIT_OBJECT_ID_PATTERN.test(coordinates.sourceBaseOid) || !GIT_OBJECT_ID_PATTERN.test(coordinates.sourceHeadOid) || !GIT_OBJECT_ID_PATTERN.test(coordinates.targetHeadOid)) {
817
+ return {
818
+ error: "Malformed preserved lane recovery coordinates"
819
+ };
820
+ }
821
+ const laneAncestry = await requireAncestorRelation(primaryDir, coordinates.sourceBaseOid, coordinates.sourceHeadOid, "Preserved lane recovery base does not reach the preserved lane head");
822
+ if (!laneAncestry.ok) {
823
+ return { error: laneAncestry.error };
824
+ }
825
+ const targetBaseRelation = await requireAncestorRelation(primaryDir, coordinates.sourceBaseOid, coordinates.targetHeadOid, "Preserved lane recovery base does not reach the captured target head");
826
+ if (!targetBaseRelation.ok) {
827
+ return { error: targetBaseRelation.error };
828
+ }
829
+ const currentTargetRelation = await requireAncestorRelation(primaryDir, coordinates.targetHeadOid, "HEAD", "Current primary HEAD no longer descends from the captured recovery target");
830
+ if (!currentTargetRelation.ok) {
831
+ return { error: currentTargetRelation.error };
832
+ }
833
+ const initialOverlapSnapshot = await captureImmutableMergeOverlapSnapshot(primaryDir, coordinates);
834
+ if ("error" in initialOverlapSnapshot) {
835
+ return { error: initialOverlapSnapshot.error };
836
+ }
837
+ if (initialOverlapSnapshot.snapshot.overlapPaths.length > 0) {
838
+ return {
839
+ error: `Primary checkout has overlapping dirty paths with incoming preserved lane changes: ${initialOverlapSnapshot.snapshot.overlapPaths.join(", ")}`
840
+ };
841
+ }
842
+ const finalOverlapSnapshot = await captureImmutableMergeOverlapSnapshot(primaryDir, coordinates);
843
+ if ("error" in finalOverlapSnapshot) {
844
+ return { error: finalOverlapSnapshot.error };
845
+ }
846
+ if (!sameOverlapSnapshot(initialOverlapSnapshot.snapshot, finalOverlapSnapshot.snapshot)) {
847
+ return {
848
+ error: "Primary or preserved lane state changed during overlap preflight; refusing merge-back"
849
+ };
850
+ }
851
+ if (coordinates.strategy === "merge") {
852
+ return finalizeMergeStrategyResult(primaryDir, "merge", await runGit(["merge", "--no-edit", coordinates.sourceHeadOid], primaryDir), {});
853
+ }
854
+ if (coordinates.strategy === "rebase") {
855
+ return finalizeMergeStrategyResult(primaryDir, "rebase", await runGit([
856
+ "rebase",
857
+ "--onto",
858
+ coordinates.sourceHeadOid,
859
+ coordinates.sourceBaseOid
860
+ ], primaryDir), {});
861
+ }
862
+ const sourceCommitOrder = await readOrderedCommitRange(primaryDir, coordinates.sourceBaseOid, coordinates.sourceHeadOid, "Malformed preserved lane recovery coordinates: exact cherry-pick order could not be reconstructed");
863
+ if ("error" in sourceCommitOrder) {
864
+ return { error: sourceCommitOrder.error };
865
+ }
866
+ if (sourceCommitOrder.commits.length === 0) {
867
+ return {
868
+ merged: true,
869
+ strategy: "cherry-pick",
870
+ sourceCommitOrder: []
871
+ };
872
+ }
873
+ const headBefore = await readVerifiedGitObjectId(primaryDir, "HEAD", "current primary HEAD before preserved cherry-pick recovery");
874
+ if ("error" in headBefore) {
875
+ return { error: headBefore.error };
876
+ }
877
+ const cherryPickResult = await finalizeMergeStrategyResult(primaryDir, "cherry-pick", await runGit(["cherry-pick", ...sourceCommitOrder.commits, "-x"], primaryDir), { sourceCommitOrder: sourceCommitOrder.commits });
878
+ if (!("merged" in cherryPickResult) || !cherryPickResult.merged) {
879
+ return cherryPickResult;
880
+ }
881
+ const rewrittenCommitOrder = await readOrderedCommitRange(primaryDir, headBefore.oid, "HEAD", "Unable to reconstruct rewritten preserved cherry-pick order");
882
+ if ("error" in rewrittenCommitOrder) {
883
+ return {
884
+ error: rewrittenCommitOrder.error,
885
+ sourceCommitOrder: sourceCommitOrder.commits
886
+ };
887
+ }
888
+ if (rewrittenCommitOrder.commits.length !== sourceCommitOrder.commits.length) {
889
+ return {
890
+ error: "Unable to reconstruct rewritten preserved cherry-pick order: rewritten commit count did not match the captured lane range",
891
+ sourceCommitOrder: sourceCommitOrder.commits
512
892
  };
513
893
  }
514
894
  return {
515
- error: result.stderr.trim() || result.stdout.trim()
895
+ ...cherryPickResult,
896
+ rewrittenCommitOrder: rewrittenCommitOrder.commits
516
897
  };
517
898
  }
518
899
  async function reconcileLandedMerge(primaryDir, provenance) {
@@ -703,6 +1084,15 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
703
1084
  };
704
1085
  }
705
1086
  }
1087
+ const initialOverlapSnapshot = await _internals.captureMergeOverlapSnapshot(primaryDir, branchName);
1088
+ if ("error" in initialOverlapSnapshot) {
1089
+ return {
1090
+ failed: true,
1091
+ stage: "pre-merge",
1092
+ message: initialOverlapSnapshot.error,
1093
+ ...provenance ? { provenance } : {}
1094
+ };
1095
+ }
706
1096
  if (!provenance && (options.operationId || options.onBeforeMerge)) {
707
1097
  if (!options.operationId) {
708
1098
  return {
@@ -711,26 +1101,10 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
711
1101
  message: "A pre-merge callback requires a stable operationId"
712
1102
  };
713
1103
  }
714
- const source = await captureLaneSourceHead(worktreePath, branchName, primaryDir, sourceWorktreeMissing);
715
- if (source.sourceWorktreeMissing && !sourceWorktreeMissing) {
716
- const unrecoverable = await handleSourceWorktreeGone(source.result, worktreePath, branchName, primaryDir, provenance);
717
- if (unrecoverable)
718
- return unrecoverable;
719
- sourceWorktreeMissing = true;
720
- }
721
- const sourceHead = source.result;
722
- const targetHead = await runGit(["rev-parse", "HEAD"], primaryDir);
723
- if (sourceHead.exitCode !== 0 || targetHead.exitCode !== 0 || !sourceHead.stdout.trim() || !targetHead.stdout.trim()) {
724
- return {
725
- failed: true,
726
- stage: "pre-merge",
727
- message: "Unable to capture source and target HEAD before merge-back"
728
- };
729
- }
730
1104
  provenance = {
731
1105
  operationId: options.operationId,
732
- sourceHead: sourceHead.stdout.trim(),
733
- targetHeadBefore: targetHead.stdout.trim(),
1106
+ sourceHead: initialOverlapSnapshot.snapshot.laneHead,
1107
+ targetHeadBefore: initialOverlapSnapshot.snapshot.targetHead,
734
1108
  branchName,
735
1109
  strategy
736
1110
  };
@@ -747,6 +1121,34 @@ async function attemptMergeBackFromDirty(worktreePath, branchName, primaryDir, s
747
1121
  }
748
1122
  }
749
1123
  }
1124
+ const finalOverlapSnapshot = await _internals.captureMergeOverlapSnapshot(primaryDir, branchName);
1125
+ if ("error" in finalOverlapSnapshot) {
1126
+ return {
1127
+ failed: true,
1128
+ stage: "pre-merge",
1129
+ message: finalOverlapSnapshot.error,
1130
+ ...provenance ? { provenance } : {}
1131
+ };
1132
+ }
1133
+ if (finalOverlapSnapshot.snapshot.overlapPaths.length > 0) {
1134
+ return {
1135
+ partial: true,
1136
+ stage: "pre-merge-overlap",
1137
+ autoCommitted,
1138
+ cleaned,
1139
+ message: `Primary checkout has overlapping dirty paths with incoming lane changes: ${finalOverlapSnapshot.snapshot.overlapPaths.join(", ")}`,
1140
+ conflictFiles: finalOverlapSnapshot.snapshot.overlapPaths,
1141
+ ...provenance ? { provenance } : {}
1142
+ };
1143
+ }
1144
+ if (!sameOverlapSnapshot(initialOverlapSnapshot.snapshot, finalOverlapSnapshot.snapshot)) {
1145
+ return {
1146
+ failed: true,
1147
+ stage: "pre-merge",
1148
+ message: "Primary or lane state changed during overlap preflight; refusing merge-back",
1149
+ ...provenance ? { provenance } : {}
1150
+ };
1151
+ }
750
1152
  const mergeResult = await mergeLaneBranch(primaryDir, branchName, strategy);
751
1153
  if ("merged" in mergeResult && mergeResult.merged) {
752
1154
  return {
@@ -972,9 +1374,9 @@ var SMALL_WORKFLOW_WAL_MAX_BYTES = 1024 * 1024;
972
1374
  var CHUNK_BYTES = 64 * 1024;
973
1375
  var _internals2 = {
974
1376
  openFile: open,
975
- openFileSync: fs3.openSync,
976
- readFileSync: fs3.readSync,
977
- closeFileSync: fs3.closeSync
1377
+ openFileSync: fs4.openSync,
1378
+ readFileSync: fs4.readSync,
1379
+ closeFileSync: fs4.closeSync
978
1380
  };
979
1381
  function maxBytesFor(kind) {
980
1382
  return kind === "coder-settlement" ? CODER_SETTLEMENT_MAX_BYTES : SMALL_WORKFLOW_WAL_MAX_BYTES;
@@ -1474,18 +1876,18 @@ function reduceTaskWorkflowSnapshot(current, event, context) {
1474
1876
  }
1475
1877
  }
1476
1878
  function getEvidenceDir(directory) {
1477
- const swarmDir = path3.resolve(directory, ".swarm");
1478
- const evidenceDir = path3.join(swarmDir, "evidence");
1879
+ const swarmDir = path4.resolve(directory, ".swarm");
1880
+ const evidenceDir = path4.join(swarmDir, "evidence");
1479
1881
  mkdirSync3(evidenceDir, { recursive: true });
1480
1882
  let resolvedSwarmDir;
1481
1883
  let resolvedEvidenceDir;
1482
1884
  try {
1483
- resolvedSwarmDir = path3.normalize(realpathSync2(swarmDir));
1484
- resolvedEvidenceDir = path3.normalize(realpathSync2(evidenceDir));
1885
+ resolvedSwarmDir = path4.normalize(realpathSync2(swarmDir));
1886
+ resolvedEvidenceDir = path4.normalize(realpathSync2(evidenceDir));
1485
1887
  } catch (error) {
1486
1888
  throw new Error(`Unable to resolve evidence directory: ${error.message}`);
1487
1889
  }
1488
- const swarmPrefix = `${resolvedSwarmDir}${path3.sep}`;
1890
+ const swarmPrefix = `${resolvedSwarmDir}${path4.sep}`;
1489
1891
  const withinSwarmBoundary = process.platform === "win32" ? resolvedEvidenceDir.toLowerCase().startsWith(swarmPrefix.toLowerCase()) : resolvedEvidenceDir.startsWith(swarmPrefix);
1490
1892
  if (!withinSwarmBoundary) {
1491
1893
  throw new Error(`Evidence path escapes .swarm boundary: ${resolvedEvidenceDir}`);
@@ -1614,7 +2016,7 @@ async function withTaskEvidenceTransaction(directory, taskId, agent, callback) {
1614
2016
  assertValidTaskId(taskId);
1615
2017
  return withTaskEvidenceLock(directory, taskId, agent, async () => {
1616
2018
  const resolvedEvidenceDir = getEvidenceDir(directory);
1617
- const evidencePath = path3.join(resolvedEvidenceDir, `${taskId}.json`);
2019
+ const evidencePath = path4.join(resolvedEvidenceDir, `${taskId}.json`);
1618
2020
  let current = null;
1619
2021
  try {
1620
2022
  current = readExisting(evidencePath, taskId);
@@ -1719,4 +2121,4 @@ function compareTaskWorkflowStateRank(left, right) {
1719
2121
  return WORKFLOW_STATE_RANK[left] - WORKFLOW_STATE_RANK[right];
1720
2122
  }
1721
2123
 
1722
- export { isStrictTaskId, sanitizeTaskId, listRecoveryRecords, GitBinaryMissingError, GitSpawnCwdError, isGitBinaryMissing, isSpawnCwdMissing, isSpawnCwdUnreadable, _internals, SOURCE_WORKTREE_GONE_STAGE, SOURCE_WORKTREE_UNCERTAIN_STAGE, getMergeStrategy, reconcileLandedMerge, postMergeCleanup, pruneStaleWorktreeMetadata, attemptMergeBackFromDirty, cleanupOrphanedBranches, startupOrphanRecovery, readWorkflowWalFile, writeWorkflowWalFile, TASK_WORKFLOW_SCHEMA_MARKER, assertTaskEvidenceWriteAllowed, parseTaskEvidence, DEFAULT_REQUIRED_GATES, isValidTaskId, getTaskWorkflowSnapshot, reduceTaskWorkflowSnapshot, deriveRequiredGates, expandRequiredGates, transitionTaskWorkflowEvidence, withTaskEvidenceTransaction, recordGateEvidence, recordAgentDispatch, readTaskEvidence, readTaskEvidenceRaw, hasPassedAllGates, compareTaskWorkflowStateRank };
2124
+ export { isStrictTaskId, sanitizeTaskId, listRecoveryRecords, GitBinaryMissingError, GitSpawnCwdError, isGitBinaryMissing, isSpawnCwdMissing, isSpawnCwdUnreadable, _internals, SOURCE_WORKTREE_GONE_STAGE, SOURCE_WORKTREE_UNCERTAIN_STAGE, getMergeStrategy, recoverMergeBackFromImmutableCoordinates, reconcileLandedMerge, postMergeCleanup, pruneStaleWorktreeMetadata, attemptMergeBackFromDirty, cleanupOrphanedBranches, startupOrphanRecovery, readWorkflowWalFile, writeWorkflowWalFile, TASK_WORKFLOW_SCHEMA_MARKER, assertTaskEvidenceWriteAllowed, parseTaskEvidence, DEFAULT_REQUIRED_GATES, isValidTaskId, getTaskWorkflowSnapshot, reduceTaskWorkflowSnapshot, deriveRequiredGates, expandRequiredGates, transitionTaskWorkflowEvidence, withTaskEvidenceTransaction, recordGateEvidence, recordAgentDispatch, readTaskEvidence, readTaskEvidenceRaw, hasPassedAllGates, compareTaskWorkflowStateRank };