opencode-swarm 7.8.1 → 7.10.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.
package/dist/cli/index.js CHANGED
@@ -34,7 +34,7 @@ var package_default;
34
34
  var init_package = __esm(() => {
35
35
  package_default = {
36
36
  name: "opencode-swarm",
37
- version: "7.8.1",
37
+ version: "7.10.0",
38
38
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
39
39
  main: "dist/index.js",
40
40
  types: "dist/index.d.ts",
@@ -19738,7 +19738,13 @@ async function handleArchiveCommand(directory, args) {
19738
19738
  const wouldArchiveAge = [];
19739
19739
  const remainingBundles = [];
19740
19740
  for (const taskId of beforeTaskIds) {
19741
- const result = await loadEvidence(directory, taskId);
19741
+ let result;
19742
+ try {
19743
+ result = await loadEvidence(directory, taskId);
19744
+ } catch (_evidenceErr) {
19745
+ warn("archive: skipping corrupt or unreadable evidence for task", taskId);
19746
+ continue;
19747
+ }
19742
19748
  if (result.status !== "found") {
19743
19749
  continue;
19744
19750
  }
@@ -19793,6 +19799,7 @@ async function handleArchiveCommand(directory, args) {
19793
19799
  var init_archive = __esm(() => {
19794
19800
  init_loader();
19795
19801
  init_manager2();
19802
+ init_utils();
19796
19803
  });
19797
19804
 
19798
19805
  // src/db/project-db.ts
@@ -20799,7 +20806,13 @@ async function handleBenchmarkCommand(directory, args) {
20799
20806
  let totalTestToCodeRatio = 0;
20800
20807
  let qualityEvidenceCount = 0;
20801
20808
  for (const tid of await listEvidenceTaskIds(directory)) {
20802
- const result = await loadEvidence(directory, tid);
20809
+ let result;
20810
+ try {
20811
+ result = await loadEvidence(directory, tid);
20812
+ } catch (_evidenceErr) {
20813
+ warn("benchmark: skipping corrupt or unreadable evidence for task", tid);
20814
+ continue;
20815
+ }
20803
20816
  if (result.status !== "found")
20804
20817
  continue;
20805
20818
  for (const e of result.bundle.entries) {
@@ -34477,6 +34490,205 @@ function resetToRemoteBranch(cwd, options) {
34477
34490
  };
34478
34491
  }
34479
34492
  }
34493
+ function resetToMainAfterMerge(cwd, options) {
34494
+ const warnings = [];
34495
+ try {
34496
+ const defaultBranch = _internals6.detectDefaultRemoteBranch(cwd);
34497
+ if (!defaultBranch) {
34498
+ return {
34499
+ success: false,
34500
+ targetBranch: "",
34501
+ previousBranch: "",
34502
+ message: "Could not detect default remote branch",
34503
+ branchDeleted: false,
34504
+ changesDiscarded: false,
34505
+ warnings
34506
+ };
34507
+ }
34508
+ const currentBranch = getCurrentBranch(cwd);
34509
+ const targetBranch = `origin/${defaultBranch}`;
34510
+ if (currentBranch === "HEAD") {
34511
+ return {
34512
+ success: false,
34513
+ targetBranch,
34514
+ previousBranch: "HEAD",
34515
+ message: "Cannot reset: detached HEAD state",
34516
+ branchDeleted: false,
34517
+ changesDiscarded: false,
34518
+ warnings
34519
+ };
34520
+ }
34521
+ if (currentBranch === defaultBranch) {
34522
+ try {
34523
+ const logOutput = _internals6.gitExec(["log", `${targetBranch}..HEAD`, "--oneline"], cwd);
34524
+ if (logOutput.trim().length > 0) {
34525
+ return {
34526
+ success: false,
34527
+ targetBranch,
34528
+ previousBranch: currentBranch,
34529
+ message: `Cannot reset: ${defaultBranch} has unpushed commits. Push them first.`,
34530
+ branchDeleted: false,
34531
+ changesDiscarded: false,
34532
+ warnings
34533
+ };
34534
+ }
34535
+ } catch {}
34536
+ } else {
34537
+ try {
34538
+ _internals6.gitExec(["rev-parse", "--abbrev-ref", `${currentBranch}@{upstream}`], cwd);
34539
+ } catch {
34540
+ try {
34541
+ const localSha = _internals6.gitExec(["rev-parse", "HEAD"], cwd).trim();
34542
+ const remoteSha = _internals6.gitExec(["rev-parse", targetBranch], cwd).trim();
34543
+ if (localSha !== remoteSha) {
34544
+ return {
34545
+ success: false,
34546
+ targetBranch,
34547
+ previousBranch: currentBranch,
34548
+ message: `Cannot reset: branch ${currentBranch} is local-only and diverges from ${defaultBranch}. Push or check manually.`,
34549
+ branchDeleted: false,
34550
+ changesDiscarded: false,
34551
+ warnings
34552
+ };
34553
+ }
34554
+ } catch {
34555
+ return {
34556
+ success: false,
34557
+ targetBranch,
34558
+ previousBranch: currentBranch,
34559
+ message: `Cannot reset: unable to compare ${currentBranch} with ${defaultBranch}`,
34560
+ branchDeleted: false,
34561
+ changesDiscarded: false,
34562
+ warnings
34563
+ };
34564
+ }
34565
+ }
34566
+ }
34567
+ try {
34568
+ _internals6.gitExec(["fetch", "--prune", "origin"], cwd);
34569
+ } catch (err) {
34570
+ return {
34571
+ success: false,
34572
+ targetBranch,
34573
+ previousBranch: currentBranch,
34574
+ message: `Cannot reset: fetch failed \u2014 ${err instanceof Error ? err.message : String(err)}`,
34575
+ branchDeleted: false,
34576
+ changesDiscarded: false,
34577
+ warnings
34578
+ };
34579
+ }
34580
+ const previousBranch = currentBranch;
34581
+ let switchedBranch = false;
34582
+ if (currentBranch !== defaultBranch) {
34583
+ try {
34584
+ _internals6.gitExec(["checkout", defaultBranch], cwd);
34585
+ switchedBranch = true;
34586
+ } catch (err) {
34587
+ return {
34588
+ success: false,
34589
+ targetBranch,
34590
+ previousBranch,
34591
+ message: `Checkout to ${defaultBranch} failed: ${err instanceof Error ? err.message : String(err)}`,
34592
+ branchDeleted: false,
34593
+ changesDiscarded: false,
34594
+ warnings
34595
+ };
34596
+ }
34597
+ }
34598
+ try {
34599
+ _internals6.gitExec(["reset", "--hard", targetBranch], cwd);
34600
+ } catch (err) {
34601
+ return {
34602
+ success: false,
34603
+ targetBranch,
34604
+ previousBranch,
34605
+ message: `Reset to ${targetBranch} failed: ${err instanceof Error ? err.message : String(err)}`,
34606
+ branchDeleted: false,
34607
+ changesDiscarded: false,
34608
+ warnings
34609
+ };
34610
+ }
34611
+ let changesDiscarded = false;
34612
+ if (hasUncommittedChanges(cwd)) {
34613
+ let discardSucceeded = false;
34614
+ for (let retry = 0;retry < 4; retry++) {
34615
+ if (retry > 0 && process.platform === "win32") {
34616
+ const endTime = Date.now() + 500;
34617
+ while (Date.now() < endTime) {}
34618
+ }
34619
+ try {
34620
+ _internals6.gitExec(["checkout", "--", "."], cwd);
34621
+ discardSucceeded = true;
34622
+ break;
34623
+ } catch {}
34624
+ }
34625
+ if (!discardSucceeded) {
34626
+ warnings.push("Could not discard all uncommitted changes after reset");
34627
+ }
34628
+ changesDiscarded = discardSucceeded;
34629
+ }
34630
+ try {
34631
+ _internals6.gitExec(["clean", "-fd"], cwd);
34632
+ } catch {
34633
+ warnings.push("Could not clean untracked files");
34634
+ }
34635
+ let branchDeleted = false;
34636
+ if (switchedBranch && previousBranch !== defaultBranch) {
34637
+ try {
34638
+ const mergedOutput = _internals6.gitExec(["branch", "--merged", defaultBranch], cwd);
34639
+ const isMerged = mergedOutput.split(`
34640
+ `).some((line) => line.trim() === previousBranch || line.trim() === `* ${previousBranch}`);
34641
+ if (isMerged) {
34642
+ _internals6.gitExec(["branch", "-d", previousBranch], cwd);
34643
+ branchDeleted = true;
34644
+ } else {
34645
+ warnings.push(`Branch ${previousBranch} is not merged into ${defaultBranch} \u2014 keeping it`);
34646
+ }
34647
+ } catch {
34648
+ warnings.push(`Could not delete branch ${previousBranch}`);
34649
+ }
34650
+ }
34651
+ if (options?.pruneBranches) {
34652
+ try {
34653
+ const mergedOutput = _internals6.gitExec(["branch", "--merged", defaultBranch], cwd);
34654
+ const mergedLines = mergedOutput.split(`
34655
+ `);
34656
+ for (const line of mergedLines) {
34657
+ const trimmedLine = line.trim();
34658
+ if (!trimmedLine || trimmedLine.startsWith("*") || trimmedLine === defaultBranch) {
34659
+ continue;
34660
+ }
34661
+ try {
34662
+ _internals6.gitExec(["branch", "-d", trimmedLine], cwd);
34663
+ } catch {
34664
+ warnings.push(`Could not prune branch: ${trimmedLine}`);
34665
+ }
34666
+ }
34667
+ } catch (err) {
34668
+ warnings.push(`Prune failed: ${err instanceof Error ? err.message : String(err)}`);
34669
+ }
34670
+ }
34671
+ return {
34672
+ success: true,
34673
+ targetBranch,
34674
+ previousBranch,
34675
+ message: branchDeleted ? `Reset to ${defaultBranch} and deleted branch ${previousBranch}` : `Reset to ${defaultBranch}`,
34676
+ branchDeleted,
34677
+ changesDiscarded,
34678
+ warnings
34679
+ };
34680
+ } catch (err) {
34681
+ return {
34682
+ success: false,
34683
+ targetBranch: "",
34684
+ previousBranch: "",
34685
+ message: `Unexpected error: ${err instanceof Error ? err.message : String(err)}`,
34686
+ branchDeleted: false,
34687
+ changesDiscarded: false,
34688
+ warnings
34689
+ };
34690
+ }
34691
+ }
34480
34692
  var GIT_TIMEOUT_MS2 = 30000, _internals6;
34481
34693
  var init_branch = __esm(() => {
34482
34694
  init_logger();
@@ -34484,10 +34696,81 @@ var init_branch = __esm(() => {
34484
34696
  gitExec: gitExec2,
34485
34697
  detectDefaultRemoteBranch,
34486
34698
  getDefaultBaseBranch,
34487
- resetToRemoteBranch
34699
+ resetToRemoteBranch,
34700
+ resetToMainAfterMerge
34488
34701
  };
34489
34702
  });
34490
34703
 
34704
+ // src/background/event-bus.ts
34705
+ class AutomationEventBus {
34706
+ listeners = new Map;
34707
+ eventHistory = [];
34708
+ maxHistorySize;
34709
+ constructor(options) {
34710
+ this.maxHistorySize = options?.maxHistorySize ?? 100;
34711
+ }
34712
+ subscribe(type, listener) {
34713
+ if (!this.listeners.has(type)) {
34714
+ this.listeners.set(type, new Set);
34715
+ }
34716
+ this.listeners.get(type).add(listener);
34717
+ return () => {
34718
+ this.listeners.get(type)?.delete(listener);
34719
+ };
34720
+ }
34721
+ async publish(type, payload, source) {
34722
+ const event = {
34723
+ type,
34724
+ timestamp: Date.now(),
34725
+ payload,
34726
+ source
34727
+ };
34728
+ this.eventHistory.push(event);
34729
+ if (this.eventHistory.length > this.maxHistorySize) {
34730
+ this.eventHistory.shift();
34731
+ }
34732
+ log(`[EventBus] ${type}`, {
34733
+ source,
34734
+ payload: typeof payload === "object" ? "..." : payload
34735
+ });
34736
+ const listeners = this.listeners.get(type);
34737
+ if (listeners) {
34738
+ await Promise.all(Array.from(listeners).map(async (listener) => {
34739
+ try {
34740
+ await listener(event);
34741
+ } catch (error93) {
34742
+ log(`[EventBus] Listener error for ${type}`, { error: error93 });
34743
+ }
34744
+ }));
34745
+ }
34746
+ }
34747
+ getHistory(types) {
34748
+ if (!types || types.length === 0) {
34749
+ return [...this.eventHistory];
34750
+ }
34751
+ return this.eventHistory.filter((e) => types.includes(e.type));
34752
+ }
34753
+ clearHistory() {
34754
+ this.eventHistory = [];
34755
+ }
34756
+ getListenerCount(type) {
34757
+ return this.listeners.get(type)?.size ?? 0;
34758
+ }
34759
+ hasListeners(type) {
34760
+ return this.getListenerCount(type) > 0;
34761
+ }
34762
+ }
34763
+ function getGlobalEventBus() {
34764
+ if (!globalEventBus) {
34765
+ globalEventBus = new AutomationEventBus;
34766
+ }
34767
+ return globalEventBus;
34768
+ }
34769
+ var globalEventBus = null;
34770
+ var init_event_bus = __esm(() => {
34771
+ init_utils();
34772
+ });
34773
+
34491
34774
  // src/hooks/knowledge-store.ts
34492
34775
  import { existsSync as existsSync7 } from "fs";
34493
34776
  import { appendFile as appendFile2, mkdir as mkdir2, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
@@ -34655,78 +34938,9 @@ var init_knowledge_store = __esm(() => {
34655
34938
  import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
34656
34939
  });
34657
34940
 
34658
- // src/hooks/knowledge-reader.ts
34659
- import { existsSync as existsSync8 } from "fs";
34660
- import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
34661
- import * as path11 from "path";
34662
- async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
34663
- const shownFile = path11.join(directory, ".swarm", ".knowledge-shown.json");
34664
- try {
34665
- if (!existsSync8(shownFile)) {
34666
- return;
34667
- }
34668
- const content = await readFile4(shownFile, "utf-8");
34669
- const shownData = JSON.parse(content);
34670
- const shownIds = shownData[phaseInfo];
34671
- if (!shownIds || shownIds.length === 0) {
34672
- return;
34673
- }
34674
- const swarmPath = resolveSwarmKnowledgePath(directory);
34675
- const entries = await readKnowledge(swarmPath);
34676
- let updated = false;
34677
- const foundInSwarm = new Set;
34678
- for (const entry of entries) {
34679
- if (shownIds.includes(entry.id)) {
34680
- entry.retrieval_outcomes.applied_count++;
34681
- if (phaseSucceeded) {
34682
- entry.retrieval_outcomes.succeeded_after_count++;
34683
- } else {
34684
- entry.retrieval_outcomes.failed_after_count++;
34685
- }
34686
- updated = true;
34687
- foundInSwarm.add(entry.id);
34688
- }
34689
- }
34690
- if (updated) {
34691
- await rewriteKnowledge(swarmPath, entries);
34692
- }
34693
- const remainingIds = shownIds.filter((id) => !foundInSwarm.has(id));
34694
- if (remainingIds.length === 0) {
34695
- delete shownData[phaseInfo];
34696
- await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
34697
- return;
34698
- }
34699
- const hivePath = resolveHiveKnowledgePath();
34700
- const hiveEntries = await readKnowledge(hivePath);
34701
- let hiveUpdated = false;
34702
- for (const entry of hiveEntries) {
34703
- if (remainingIds.includes(entry.id)) {
34704
- entry.retrieval_outcomes.applied_count++;
34705
- if (phaseSucceeded) {
34706
- entry.retrieval_outcomes.succeeded_after_count++;
34707
- } else {
34708
- entry.retrieval_outcomes.failed_after_count++;
34709
- }
34710
- hiveUpdated = true;
34711
- }
34712
- }
34713
- if (hiveUpdated) {
34714
- await rewriteKnowledge(hivePath, hiveEntries);
34715
- }
34716
- delete shownData[phaseInfo];
34717
- await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
34718
- } catch {
34719
- warn("[swarm] Knowledge: failed to update retrieval outcomes");
34720
- }
34721
- }
34722
- var init_knowledge_reader = __esm(() => {
34723
- init_logger();
34724
- init_knowledge_store();
34725
- });
34726
-
34727
34941
  // src/hooks/knowledge-validator.ts
34728
- import { appendFile as appendFile3, mkdir as mkdir4, writeFile as writeFile5 } from "fs/promises";
34729
- import * as path12 from "path";
34942
+ import { appendFile as appendFile3, mkdir as mkdir3, writeFile as writeFile4 } from "fs/promises";
34943
+ import * as path11 from "path";
34730
34944
  function normalizeText(text) {
34731
34945
  return text.normalize("NFKC").toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
34732
34946
  }
@@ -34880,11 +35094,11 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
34880
35094
  return;
34881
35095
  }
34882
35096
  const sanitizedReason = reason.slice(0, 500).replace(/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f\x0d]/g, "");
34883
- const knowledgePath = path12.join(directory, ".swarm", "knowledge.jsonl");
34884
- const quarantinePath = path12.join(directory, ".swarm", "knowledge-quarantined.jsonl");
34885
- const rejectedPath = path12.join(directory, ".swarm", "knowledge-rejected.jsonl");
34886
- const swarmDir = path12.join(directory, ".swarm");
34887
- await mkdir4(swarmDir, { recursive: true });
35097
+ const knowledgePath = path11.join(directory, ".swarm", "knowledge.jsonl");
35098
+ const quarantinePath = path11.join(directory, ".swarm", "knowledge-quarantined.jsonl");
35099
+ const rejectedPath = path11.join(directory, ".swarm", "knowledge-rejected.jsonl");
35100
+ const swarmDir = path11.join(directory, ".swarm");
35101
+ await mkdir3(swarmDir, { recursive: true });
34888
35102
  let release;
34889
35103
  try {
34890
35104
  release = await import_proper_lockfile4.default.lock(swarmDir, {
@@ -34905,7 +35119,7 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
34905
35119
  const jsonlContent = remaining.length > 0 ? `${remaining.map((e) => JSON.stringify(e)).join(`
34906
35120
  `)}
34907
35121
  ` : "";
34908
- await writeFile5(knowledgePath, jsonlContent, "utf-8");
35122
+ await writeFile4(knowledgePath, jsonlContent, "utf-8");
34909
35123
  await appendFile3(quarantinePath, `${JSON.stringify(quarantined)}
34910
35124
  `, "utf-8");
34911
35125
  const quarantinedEntries = await readKnowledge(quarantinePath);
@@ -34914,7 +35128,7 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
34914
35128
  const capContent = trimmed.length > 0 ? `${trimmed.map((e) => JSON.stringify(e)).join(`
34915
35129
  `)}
34916
35130
  ` : "";
34917
- await writeFile5(quarantinePath, capContent, "utf-8");
35131
+ await writeFile4(quarantinePath, capContent, "utf-8");
34918
35132
  }
34919
35133
  const rejectedRecord = {
34920
35134
  id: entryId,
@@ -34940,11 +35154,11 @@ async function restoreEntry(directory, entryId) {
34940
35154
  warn("[knowledge-validator] restoreEntry: invalid entryId rejected");
34941
35155
  return;
34942
35156
  }
34943
- const knowledgePath = path12.join(directory, ".swarm", "knowledge.jsonl");
34944
- const quarantinePath = path12.join(directory, ".swarm", "knowledge-quarantined.jsonl");
34945
- const rejectedPath = path12.join(directory, ".swarm", "knowledge-rejected.jsonl");
34946
- const swarmDir = path12.join(directory, ".swarm");
34947
- await mkdir4(swarmDir, { recursive: true });
35157
+ const knowledgePath = path11.join(directory, ".swarm", "knowledge.jsonl");
35158
+ const quarantinePath = path11.join(directory, ".swarm", "knowledge-quarantined.jsonl");
35159
+ const rejectedPath = path11.join(directory, ".swarm", "knowledge-rejected.jsonl");
35160
+ const swarmDir = path11.join(directory, ".swarm");
35161
+ await mkdir3(swarmDir, { recursive: true });
34948
35162
  let release;
34949
35163
  try {
34950
35164
  release = await import_proper_lockfile4.default.lock(swarmDir, {
@@ -34960,7 +35174,7 @@ async function restoreEntry(directory, entryId) {
34960
35174
  const jsonlContent = remaining.length > 0 ? `${remaining.map((e) => JSON.stringify(e)).join(`
34961
35175
  `)}
34962
35176
  ` : "";
34963
- await writeFile5(quarantinePath, jsonlContent, "utf-8");
35177
+ await writeFile4(quarantinePath, jsonlContent, "utf-8");
34964
35178
  await appendFile3(knowledgePath, `${JSON.stringify(original)}
34965
35179
  `, "utf-8");
34966
35180
  const rejectedEntries = await readKnowledge(rejectedPath);
@@ -34968,7 +35182,7 @@ async function restoreEntry(directory, entryId) {
34968
35182
  const rejectedContent = filtered.length > 0 ? `${filtered.map((e) => JSON.stringify(e)).join(`
34969
35183
  `)}
34970
35184
  ` : "";
34971
- await writeFile5(rejectedPath, rejectedContent, "utf-8");
35185
+ await writeFile4(rejectedPath, rejectedContent, "utf-8");
34972
35186
  } finally {
34973
35187
  if (release) {
34974
35188
  await release();
@@ -35083,6 +35297,321 @@ var init_knowledge_validator = __esm(() => {
35083
35297
  ];
35084
35298
  });
35085
35299
 
35300
+ // src/hooks/curator.ts
35301
+ var init_curator = __esm(() => {
35302
+ init_event_bus();
35303
+ init_manager();
35304
+ init_bun_compat();
35305
+ init_logger();
35306
+ init_knowledge_store();
35307
+ init_knowledge_validator();
35308
+ init_utils2();
35309
+ });
35310
+
35311
+ // src/hooks/hive-promoter.ts
35312
+ import path12 from "path";
35313
+ function isAlreadyInHive(entry, hiveEntries, threshold) {
35314
+ return findNearDuplicate(entry.lesson, hiveEntries, threshold) !== undefined;
35315
+ }
35316
+ function countDistinctPhases(confirmedBy) {
35317
+ const phaseNumbers = new Set;
35318
+ for (const record3 of confirmedBy) {
35319
+ phaseNumbers.add(record3.phase_number);
35320
+ }
35321
+ return phaseNumbers.size;
35322
+ }
35323
+ function countDistinctProjects(confirmedBy) {
35324
+ const projectNames = new Set;
35325
+ for (const record3 of confirmedBy) {
35326
+ projectNames.add(record3.project_name);
35327
+ }
35328
+ return projectNames.size;
35329
+ }
35330
+ function hasProjectConfirmation(hiveEntry, projectName) {
35331
+ return hiveEntry.confirmed_by.some((record3) => record3.project_name === projectName);
35332
+ }
35333
+ function calculateEncounterScore(currentScore, isSameProject, config3) {
35334
+ const weight = isSameProject ? config3.same_project_weight : config3.cross_project_weight;
35335
+ const increment = config3.encounter_increment * weight;
35336
+ const newScore = currentScore + increment;
35337
+ return Math.min(Math.max(newScore, config3.min_encounter_score), config3.max_encounter_score);
35338
+ }
35339
+ function getEntryAgeMs(createdAt) {
35340
+ const createdTime = new Date(createdAt).getTime();
35341
+ if (Number.isNaN(createdTime))
35342
+ return 0;
35343
+ return Date.now() - createdTime;
35344
+ }
35345
+ async function checkHivePromotions(swarmEntries, config3) {
35346
+ let newPromotions = 0;
35347
+ let encountersIncremented = 0;
35348
+ let advancements = 0;
35349
+ if (config3.hive_enabled === false) {
35350
+ return {
35351
+ timestamp: new Date().toISOString(),
35352
+ new_promotions: 0,
35353
+ encounters_incremented: 0,
35354
+ advancements: 0,
35355
+ total_hive_entries: 0
35356
+ };
35357
+ }
35358
+ const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
35359
+ for (const swarmEntry of swarmEntries) {
35360
+ if (isAlreadyInHive(swarmEntry, hiveEntries, config3.dedup_threshold)) {
35361
+ continue;
35362
+ }
35363
+ let shouldPromote = false;
35364
+ if (swarmEntry.hive_eligible === true && countDistinctPhases(swarmEntry.confirmed_by) >= 3) {
35365
+ shouldPromote = true;
35366
+ }
35367
+ if (swarmEntry.tags.includes("hive-fast-track")) {
35368
+ shouldPromote = true;
35369
+ }
35370
+ const ageMs = getEntryAgeMs(swarmEntry.created_at);
35371
+ const ageThresholdMs = config3.auto_promote_days * 86400000;
35372
+ if (ageMs >= ageThresholdMs) {
35373
+ shouldPromote = true;
35374
+ }
35375
+ if (!shouldPromote) {
35376
+ continue;
35377
+ }
35378
+ const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
35379
+ category: swarmEntry.category,
35380
+ scope: swarmEntry.scope,
35381
+ confidence: swarmEntry.confidence
35382
+ });
35383
+ if (validationResult.severity === "error") {
35384
+ const rejectedLesson = {
35385
+ id: crypto.randomUUID(),
35386
+ lesson: swarmEntry.lesson,
35387
+ rejection_reason: validationResult.reason || "validation failed for hive promotion",
35388
+ rejected_at: new Date().toISOString(),
35389
+ rejection_layer: validationResult.layer || 2
35390
+ };
35391
+ const hiveRejectedPath = resolveHiveRejectedPath();
35392
+ await appendKnowledge(hiveRejectedPath, rejectedLesson);
35393
+ continue;
35394
+ }
35395
+ const newHiveEntry = {
35396
+ id: crypto.randomUUID(),
35397
+ tier: "hive",
35398
+ lesson: swarmEntry.lesson,
35399
+ category: swarmEntry.category,
35400
+ tags: swarmEntry.tags,
35401
+ scope: swarmEntry.scope,
35402
+ confidence: 0.5,
35403
+ status: "candidate",
35404
+ confirmed_by: [],
35405
+ retrieval_outcomes: {
35406
+ applied_count: 0,
35407
+ succeeded_after_count: 0,
35408
+ failed_after_count: 0
35409
+ },
35410
+ schema_version: config3.schema_version,
35411
+ created_at: new Date().toISOString(),
35412
+ updated_at: new Date().toISOString(),
35413
+ source_project: swarmEntry.project_name,
35414
+ encounter_score: config3.initial_encounter_score
35415
+ };
35416
+ await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
35417
+ newPromotions++;
35418
+ hiveEntries.push(newHiveEntry);
35419
+ }
35420
+ let hiveModified = false;
35421
+ for (const hiveEntry of hiveEntries) {
35422
+ const nearDuplicate = findNearDuplicate(hiveEntry.lesson, swarmEntries, config3.dedup_threshold);
35423
+ if (!nearDuplicate) {
35424
+ continue;
35425
+ }
35426
+ const isSameProject = nearDuplicate.project_name === hiveEntry.source_project;
35427
+ if (hasProjectConfirmation(hiveEntry, nearDuplicate.project_name)) {
35428
+ continue;
35429
+ }
35430
+ const newConfirmation = {
35431
+ project_name: nearDuplicate.project_name,
35432
+ confirmed_at: new Date().toISOString()
35433
+ };
35434
+ hiveEntry.confirmed_by.push(newConfirmation);
35435
+ const currentScore = hiveEntry.encounter_score ?? 1;
35436
+ hiveEntry.encounter_score = calculateEncounterScore(currentScore, isSameProject, config3);
35437
+ encountersIncremented++;
35438
+ hiveEntry.updated_at = new Date().toISOString();
35439
+ if (hiveEntry.status === "candidate" && countDistinctProjects(hiveEntry.confirmed_by) >= 3) {
35440
+ hiveEntry.status = "established";
35441
+ advancements++;
35442
+ }
35443
+ hiveModified = true;
35444
+ }
35445
+ if (hiveModified) {
35446
+ await rewriteKnowledge(resolveHiveKnowledgePath(), hiveEntries);
35447
+ }
35448
+ if (newPromotions > 0 || hiveModified) {
35449
+ await enforceKnowledgeCap(resolveHiveKnowledgePath(), config3.hive_max_entries);
35450
+ }
35451
+ return {
35452
+ timestamp: new Date().toISOString(),
35453
+ new_promotions: newPromotions,
35454
+ encounters_incremented: encountersIncremented,
35455
+ advancements,
35456
+ total_hive_entries: hiveEntries.length
35457
+ };
35458
+ }
35459
+ async function promoteToHive(directory, lesson, category) {
35460
+ const trimmedLesson = lesson.trim();
35461
+ const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
35462
+ const validationResult = validateLesson(trimmedLesson, hiveEntries.map((e) => e.lesson), {
35463
+ category: category || "process",
35464
+ scope: "global",
35465
+ confidence: 1
35466
+ });
35467
+ if (validationResult.severity === "error") {
35468
+ throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
35469
+ }
35470
+ if (findNearDuplicate(trimmedLesson, hiveEntries, 0.6)) {
35471
+ return `Lesson already exists in hive (near-duplicate).`;
35472
+ }
35473
+ const newHiveEntry = {
35474
+ id: crypto.randomUUID(),
35475
+ tier: "hive",
35476
+ lesson: trimmedLesson,
35477
+ category: category || "process",
35478
+ tags: [],
35479
+ scope: "global",
35480
+ confidence: 1,
35481
+ status: "promoted",
35482
+ confirmed_by: [],
35483
+ retrieval_outcomes: {
35484
+ applied_count: 0,
35485
+ succeeded_after_count: 0,
35486
+ failed_after_count: 0
35487
+ },
35488
+ schema_version: 1,
35489
+ created_at: new Date().toISOString(),
35490
+ updated_at: new Date().toISOString(),
35491
+ source_project: path12.basename(directory) || "unknown",
35492
+ encounter_score: 1
35493
+ };
35494
+ await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
35495
+ return `Promoted to hive: "${trimmedLesson.slice(0, 50)}${trimmedLesson.length > 50 ? "..." : ""}" (confidence: 1.0, source: manual)`;
35496
+ }
35497
+ async function promoteFromSwarm(directory, lessonId) {
35498
+ const swarmEntries = await readKnowledge(resolveSwarmKnowledgePath(directory));
35499
+ const swarmEntry = swarmEntries.find((e) => e.id === lessonId);
35500
+ if (!swarmEntry) {
35501
+ throw new Error(`Lesson ${lessonId} not found in .swarm/knowledge.jsonl`);
35502
+ }
35503
+ const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
35504
+ const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
35505
+ category: swarmEntry.category,
35506
+ scope: swarmEntry.scope,
35507
+ confidence: swarmEntry.confidence
35508
+ });
35509
+ if (validationResult.severity === "error") {
35510
+ throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
35511
+ }
35512
+ if (findNearDuplicate(swarmEntry.lesson, hiveEntries, 0.6)) {
35513
+ return `Lesson already exists in hive (near-duplicate).`;
35514
+ }
35515
+ const newHiveEntry = {
35516
+ id: crypto.randomUUID(),
35517
+ tier: "hive",
35518
+ lesson: swarmEntry.lesson,
35519
+ category: swarmEntry.category,
35520
+ tags: swarmEntry.tags,
35521
+ scope: swarmEntry.scope,
35522
+ confidence: 1,
35523
+ status: "promoted",
35524
+ confirmed_by: [],
35525
+ retrieval_outcomes: {
35526
+ applied_count: 0,
35527
+ succeeded_after_count: 0,
35528
+ failed_after_count: 0
35529
+ },
35530
+ schema_version: 1,
35531
+ created_at: new Date().toISOString(),
35532
+ updated_at: new Date().toISOString(),
35533
+ source_project: swarmEntry.project_name,
35534
+ encounter_score: 1
35535
+ };
35536
+ await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
35537
+ return `Promoted lesson ${lessonId} from swarm to hive: "${swarmEntry.lesson.slice(0, 50)}${swarmEntry.lesson.length > 50 ? "..." : ""}"`;
35538
+ }
35539
+ var init_hive_promoter = __esm(() => {
35540
+ init_curator();
35541
+ init_knowledge_store();
35542
+ init_knowledge_validator();
35543
+ init_utils2();
35544
+ });
35545
+
35546
+ // src/hooks/knowledge-reader.ts
35547
+ import { existsSync as existsSync8 } from "fs";
35548
+ import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
35549
+ import * as path13 from "path";
35550
+ async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
35551
+ const shownFile = path13.join(directory, ".swarm", ".knowledge-shown.json");
35552
+ try {
35553
+ if (!existsSync8(shownFile)) {
35554
+ return;
35555
+ }
35556
+ const content = await readFile4(shownFile, "utf-8");
35557
+ const shownData = JSON.parse(content);
35558
+ const shownIds = shownData[phaseInfo];
35559
+ if (!shownIds || shownIds.length === 0) {
35560
+ return;
35561
+ }
35562
+ const swarmPath = resolveSwarmKnowledgePath(directory);
35563
+ const entries = await readKnowledge(swarmPath);
35564
+ let updated = false;
35565
+ const foundInSwarm = new Set;
35566
+ for (const entry of entries) {
35567
+ if (shownIds.includes(entry.id)) {
35568
+ entry.retrieval_outcomes.applied_count++;
35569
+ if (phaseSucceeded) {
35570
+ entry.retrieval_outcomes.succeeded_after_count++;
35571
+ } else {
35572
+ entry.retrieval_outcomes.failed_after_count++;
35573
+ }
35574
+ updated = true;
35575
+ foundInSwarm.add(entry.id);
35576
+ }
35577
+ }
35578
+ if (updated) {
35579
+ await rewriteKnowledge(swarmPath, entries);
35580
+ }
35581
+ const remainingIds = shownIds.filter((id) => !foundInSwarm.has(id));
35582
+ if (remainingIds.length === 0) {
35583
+ delete shownData[phaseInfo];
35584
+ await writeFile5(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
35585
+ return;
35586
+ }
35587
+ const hivePath = resolveHiveKnowledgePath();
35588
+ const hiveEntries = await readKnowledge(hivePath);
35589
+ let hiveUpdated = false;
35590
+ for (const entry of hiveEntries) {
35591
+ if (remainingIds.includes(entry.id)) {
35592
+ entry.retrieval_outcomes.applied_count++;
35593
+ if (phaseSucceeded) {
35594
+ entry.retrieval_outcomes.succeeded_after_count++;
35595
+ } else {
35596
+ entry.retrieval_outcomes.failed_after_count++;
35597
+ }
35598
+ hiveUpdated = true;
35599
+ }
35600
+ }
35601
+ if (hiveUpdated) {
35602
+ await rewriteKnowledge(hivePath, hiveEntries);
35603
+ }
35604
+ delete shownData[phaseInfo];
35605
+ await writeFile5(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
35606
+ } catch {
35607
+ warn("[swarm] Knowledge: failed to update retrieval outcomes");
35608
+ }
35609
+ }
35610
+ var init_knowledge_reader = __esm(() => {
35611
+ init_logger();
35612
+ init_knowledge_store();
35613
+ });
35614
+
35086
35615
  // src/hooks/knowledge-curator.ts
35087
35616
  function pruneSeenRetroSections() {
35088
35617
  const cutoff = Date.now() - 86400000;
@@ -35418,133 +35947,6 @@ var init_knowledge_curator = __esm(() => {
35418
35947
  };
35419
35948
  });
35420
35949
 
35421
- // src/session/snapshot-writer.ts
35422
- import { mkdirSync as mkdirSync7, renameSync as renameSync5 } from "fs";
35423
- import * as path13 from "path";
35424
- function serializeAgentSession(s) {
35425
- const gateLog = {};
35426
- const rawGateLog = s.gateLog ?? new Map;
35427
- for (const [taskId, gates] of rawGateLog) {
35428
- gateLog[taskId] = Array.from(gates ?? []);
35429
- }
35430
- const reviewerCallCount = {};
35431
- const rawReviewerCallCount = s.reviewerCallCount ?? new Map;
35432
- for (const [phase, count] of rawReviewerCallCount) {
35433
- reviewerCallCount[String(phase)] = count;
35434
- }
35435
- const partialGateWarningsIssuedForTask = Array.from(s.partialGateWarningsIssuedForTask ?? new Set);
35436
- const catastrophicPhaseWarnings = Array.from(s.catastrophicPhaseWarnings ?? new Set);
35437
- const phaseAgentsDispatched = Array.from(s.phaseAgentsDispatched ?? new Set);
35438
- const lastCompletedPhaseAgentsDispatched = Array.from(s.lastCompletedPhaseAgentsDispatched ?? new Set);
35439
- const windows = {};
35440
- const rawWindows = s.windows ?? {};
35441
- for (const [key, win] of Object.entries(rawWindows)) {
35442
- windows[key] = {
35443
- id: win.id,
35444
- agentName: win.agentName,
35445
- startedAtMs: win.startedAtMs,
35446
- toolCalls: win.toolCalls,
35447
- consecutiveErrors: win.consecutiveErrors,
35448
- hardLimitHit: win.hardLimitHit,
35449
- lastSuccessTimeMs: win.lastSuccessTimeMs,
35450
- recentToolCalls: win.recentToolCalls,
35451
- warningIssued: win.warningIssued,
35452
- warningReason: win.warningReason,
35453
- transientRetryCount: win.transientRetryCount ?? 0
35454
- };
35455
- }
35456
- return {
35457
- agentName: s.agentName,
35458
- lastToolCallTime: s.lastToolCallTime,
35459
- lastAgentEventTime: s.lastAgentEventTime,
35460
- delegationActive: s.delegationActive,
35461
- activeInvocationId: s.activeInvocationId,
35462
- lastInvocationIdByAgent: s.lastInvocationIdByAgent ?? {},
35463
- windows,
35464
- lastCompactionHint: s.lastCompactionHint ?? 0,
35465
- architectWriteCount: s.architectWriteCount ?? 0,
35466
- lastCoderDelegationTaskId: s.lastCoderDelegationTaskId ?? null,
35467
- currentTaskId: s.currentTaskId ?? null,
35468
- turboMode: s.turboMode ?? false,
35469
- gateLog,
35470
- reviewerCallCount,
35471
- lastGateFailure: s.lastGateFailure ?? null,
35472
- partialGateWarningsIssuedForTask,
35473
- selfFixAttempted: s.selfFixAttempted ?? false,
35474
- selfCodingWarnedAtCount: s.selfCodingWarnedAtCount ?? 0,
35475
- catastrophicPhaseWarnings,
35476
- lastPhaseCompleteTimestamp: s.lastPhaseCompleteTimestamp ?? 0,
35477
- lastPhaseCompletePhase: s.lastPhaseCompletePhase ?? 0,
35478
- phaseAgentsDispatched,
35479
- lastCompletedPhaseAgentsDispatched,
35480
- qaSkipCount: s.qaSkipCount ?? 0,
35481
- qaSkipTaskIds: s.qaSkipTaskIds ?? [],
35482
- pendingAdvisoryMessages: s.pendingAdvisoryMessages ?? [],
35483
- taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map),
35484
- ...s.scopeViolationDetected !== undefined && {
35485
- scopeViolationDetected: s.scopeViolationDetected
35486
- },
35487
- model_fallback_index: s.model_fallback_index ?? 0,
35488
- modelFallbackExhausted: s.modelFallbackExhausted ?? false,
35489
- coderRevisions: s.coderRevisions ?? 0,
35490
- revisionLimitHit: s.revisionLimitHit ?? false,
35491
- fullAutoMode: s.fullAutoMode ?? false,
35492
- fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
35493
- fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
35494
- fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
35495
- sessionRehydratedAt: s.sessionRehydratedAt ?? 0
35496
- };
35497
- }
35498
- async function writeSnapshot(directory, state) {
35499
- try {
35500
- const snapshot = {
35501
- version: 2,
35502
- writtenAt: Date.now(),
35503
- toolAggregates: Object.fromEntries(state.toolAggregates),
35504
- activeAgent: Object.fromEntries(state.activeAgent),
35505
- delegationChains: Object.fromEntries(state.delegationChains),
35506
- agentSessions: {}
35507
- };
35508
- for (const [sessionId, sessionState] of state.agentSessions) {
35509
- snapshot.agentSessions[sessionId] = serializeAgentSession(sessionState);
35510
- }
35511
- const content = JSON.stringify(snapshot, null, 2);
35512
- const resolvedPath = validateSwarmPath(directory, "session/state.json");
35513
- const dir = path13.dirname(resolvedPath);
35514
- mkdirSync7(dir, { recursive: true });
35515
- const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
35516
- await bunWrite(tempPath, content);
35517
- renameSync5(tempPath, resolvedPath);
35518
- } catch (error93) {
35519
- log("[snapshot-writer] write failed", {
35520
- error: error93 instanceof Error ? error93.message : String(error93)
35521
- });
35522
- }
35523
- }
35524
- function createSnapshotWriterHook(directory) {
35525
- return (_input, _output) => {
35526
- _writeInFlight = _writeInFlight.then(() => _internals8.writeSnapshot(directory, swarmState), () => _internals8.writeSnapshot(directory, swarmState));
35527
- return _writeInFlight;
35528
- };
35529
- }
35530
- async function flushPendingSnapshot(directory) {
35531
- _writeInFlight = _writeInFlight.then(() => _internals8.writeSnapshot(directory, swarmState), () => _internals8.writeSnapshot(directory, swarmState));
35532
- await _writeInFlight;
35533
- }
35534
- var _writeInFlight, _internals8;
35535
- var init_snapshot_writer = __esm(() => {
35536
- init_utils2();
35537
- init_state();
35538
- init_utils();
35539
- init_bun_compat();
35540
- _writeInFlight = Promise.resolve();
35541
- _internals8 = {
35542
- writeSnapshot,
35543
- createSnapshotWriterHook,
35544
- flushPendingSnapshot
35545
- };
35546
- });
35547
-
35548
35950
  // src/tools/write-retro.ts
35549
35951
  async function executeWriteRetro(args, directory) {
35550
35952
  if (/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])(:|$)/i.test(directory)) {
@@ -35846,7 +36248,7 @@ async function executeWriteRetro(args, directory) {
35846
36248
  }, null, 2);
35847
36249
  }
35848
36250
  }
35849
- var write_retro, _internals9;
36251
+ var write_retro, _internals8;
35850
36252
  var init_write_retro = __esm(() => {
35851
36253
  init_zod();
35852
36254
  init_evidence_schema();
@@ -35893,13 +36295,13 @@ var init_write_retro = __esm(() => {
35893
36295
  task_id: args.task_id !== undefined ? String(args.task_id) : undefined,
35894
36296
  metadata: args.metadata
35895
36297
  };
35896
- return await _internals9.executeWriteRetro(writeRetroArgs, directory);
36298
+ return await _internals8.executeWriteRetro(writeRetroArgs, directory);
35897
36299
  } catch {
35898
36300
  return JSON.stringify({ success: false, phase: rawPhase, message: "Invalid arguments" }, null, 2);
35899
36301
  }
35900
36302
  }
35901
36303
  });
35902
- _internals9 = {
36304
+ _internals8 = {
35903
36305
  executeWriteRetro,
35904
36306
  write_retro
35905
36307
  };
@@ -35961,6 +36363,7 @@ async function handleCloseCommand(directory, args) {
35961
36363
  const closedPhases = [];
35962
36364
  const closedTasks = [];
35963
36365
  const warnings = [];
36366
+ let hivePromoted = 0;
35964
36367
  if (!planAlreadyDone) {
35965
36368
  for (const phase of inProgressPhases) {
35966
36369
  closedPhases.push(phase.id);
@@ -36081,6 +36484,26 @@ async function handleCloseCommand(directory, args) {
36081
36484
  if (curationSucceeded && allLessons.length > 0) {
36082
36485
  await fs7.unlink(lessonsFilePath).catch(() => {});
36083
36486
  }
36487
+ if (curationSucceeded) {
36488
+ try {
36489
+ const knowledgePath = resolveSwarmKnowledgePath(directory);
36490
+ const entries = await readKnowledge(knowledgePath);
36491
+ if (entries.length > 0) {
36492
+ for (const entry of entries) {
36493
+ try {
36494
+ await promoteToHive(directory, entry.lesson, entry.category);
36495
+ hivePromoted++;
36496
+ } catch (promotionErr) {
36497
+ const msg = promotionErr instanceof Error ? promotionErr.message : String(promotionErr);
36498
+ warnings.push(`Hive promotion skipped for lesson: ${msg}`);
36499
+ }
36500
+ }
36501
+ }
36502
+ } catch (hiveErr) {
36503
+ const msg = hiveErr instanceof Error ? hiveErr.message : String(hiveErr);
36504
+ warnings.push(`Hive promotion failed: ${msg}`);
36505
+ }
36506
+ }
36084
36507
  if (planExists) {
36085
36508
  const guaranteeResult = guaranteeAllPlansComplete(planData);
36086
36509
  for (const phaseId of guaranteeResult.closedPhaseIds) {
@@ -36109,6 +36532,7 @@ async function handleCloseCommand(directory, args) {
36109
36532
  let archiveResult = "";
36110
36533
  let archivedFileCount = 0;
36111
36534
  const archivedActiveStateFiles = new Set;
36535
+ const archivedActiveStateDirs = new Set;
36112
36536
  try {
36113
36537
  await fs7.mkdir(archiveDir, { recursive: true });
36114
36538
  for (const artifact of ARCHIVE_ARTIFACTS) {
@@ -36122,38 +36546,34 @@ async function handleCloseCommand(directory, args) {
36122
36546
  }
36123
36547
  } catch {}
36124
36548
  }
36125
- const evidenceDir = path14.join(swarmDir, "evidence");
36126
- const archiveEvidenceDir = path14.join(archiveDir, "evidence");
36127
- try {
36128
- const evidenceEntries = await fs7.readdir(evidenceDir);
36129
- if (evidenceEntries.length > 0) {
36130
- await fs7.mkdir(archiveEvidenceDir, { recursive: true });
36131
- for (const entry of evidenceEntries) {
36132
- const srcEntry = path14.join(evidenceDir, entry);
36133
- const destEntry = path14.join(archiveEvidenceDir, entry);
36134
- try {
36135
- const stat2 = await fs7.stat(srcEntry);
36136
- if (stat2.isDirectory()) {
36137
- await fs7.mkdir(destEntry, { recursive: true });
36138
- const subEntries = await fs7.readdir(srcEntry);
36139
- for (const sub of subEntries) {
36140
- await fs7.copyFile(path14.join(srcEntry, sub), path14.join(destEntry, sub)).catch(() => {});
36549
+ for (const dirName of ACTIVE_STATE_DIRS_TO_CLEAN) {
36550
+ const srcDir = path14.join(swarmDir, dirName);
36551
+ const destDir = path14.join(archiveDir, dirName);
36552
+ try {
36553
+ const entries = await fs7.readdir(srcDir);
36554
+ if (entries.length > 0) {
36555
+ await fs7.mkdir(destDir, { recursive: true });
36556
+ for (const entry of entries) {
36557
+ const srcEntry = path14.join(srcDir, entry);
36558
+ const destEntry = path14.join(destDir, entry);
36559
+ try {
36560
+ const stat2 = await fs7.stat(srcEntry);
36561
+ if (stat2.isDirectory()) {
36562
+ await fs7.mkdir(destEntry, { recursive: true });
36563
+ const subEntries = await fs7.readdir(srcEntry);
36564
+ for (const sub of subEntries) {
36565
+ await fs7.copyFile(path14.join(srcEntry, sub), path14.join(destEntry, sub)).catch(() => {});
36566
+ }
36567
+ } else {
36568
+ await fs7.copyFile(srcEntry, destEntry);
36141
36569
  }
36142
- } else {
36143
- await fs7.copyFile(srcEntry, destEntry);
36144
- }
36145
- archivedFileCount++;
36146
- } catch {}
36570
+ archivedFileCount++;
36571
+ } catch {}
36572
+ }
36147
36573
  }
36148
- }
36149
- } catch {}
36150
- const sessionStatePath = path14.join(swarmDir, "session", "state.json");
36151
- try {
36152
- const archiveSessionDir = path14.join(archiveDir, "session");
36153
- await fs7.mkdir(archiveSessionDir, { recursive: true });
36154
- await fs7.copyFile(sessionStatePath, path14.join(archiveSessionDir, "state.json"));
36155
- archivedFileCount++;
36156
- } catch {}
36574
+ archivedActiveStateDirs.add(dirName);
36575
+ } catch {}
36576
+ }
36157
36577
  archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
36158
36578
  } catch (archiveError) {
36159
36579
  warnings.push(`Archive creation failed: ${archiveError instanceof Error ? archiveError.message : String(archiveError)}`);
@@ -36183,6 +36603,16 @@ async function handleCloseCommand(directory, args) {
36183
36603
  } else {
36184
36604
  warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");
36185
36605
  }
36606
+ for (const dirName of ACTIVE_STATE_DIRS_TO_CLEAN) {
36607
+ if (!archivedActiveStateDirs.has(dirName)) {
36608
+ continue;
36609
+ }
36610
+ const dirPath = path14.join(swarmDir, dirName);
36611
+ try {
36612
+ await fs7.rm(dirPath, { recursive: true, force: true });
36613
+ cleanedFiles.push(`${dirName}/`);
36614
+ } catch {}
36615
+ }
36186
36616
  try {
36187
36617
  const swarmFiles = await fs7.readdir(swarmDir);
36188
36618
  const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
@@ -36241,17 +36671,30 @@ async function handleCloseCommand(directory, args) {
36241
36671
  const prunedBranches = [];
36242
36672
  const isGit = isGitRepo2(directory);
36243
36673
  if (isGit) {
36244
- const alignResult = resetToRemoteBranch(directory, { pruneBranches });
36245
- gitAlignResult = alignResult.message;
36246
- prunedBranches.push(...alignResult.prunedBranches);
36247
- if (!alignResult.success) {
36248
- warnings.push(`Git alignment: ${alignResult.message}`);
36249
- }
36250
- if (alignResult.alreadyAligned) {
36251
- gitAlignResult = `Already aligned with ${alignResult.targetBranch}`;
36252
- }
36253
- for (const w of alignResult.warnings) {
36254
- warnings.push(w);
36674
+ const aggressiveResult = resetToMainAfterMerge(directory, {
36675
+ pruneBranches
36676
+ });
36677
+ if (aggressiveResult.success) {
36678
+ gitAlignResult = aggressiveResult.message;
36679
+ for (const w of aggressiveResult.warnings) {
36680
+ warnings.push(w);
36681
+ }
36682
+ if (aggressiveResult.changesDiscarded) {
36683
+ warnings.push("Uncommitted changes were discarded during git alignment");
36684
+ }
36685
+ } else {
36686
+ const alignResult = resetToRemoteBranch(directory, { pruneBranches });
36687
+ gitAlignResult = alignResult.message;
36688
+ prunedBranches.push(...alignResult.prunedBranches);
36689
+ if (!alignResult.success) {
36690
+ warnings.push(`Git alignment: ${alignResult.message}`);
36691
+ }
36692
+ if (alignResult.alreadyAligned) {
36693
+ gitAlignResult = `Already aligned with ${alignResult.targetBranch}`;
36694
+ }
36695
+ for (const w of alignResult.warnings) {
36696
+ warnings.push(w);
36697
+ }
36255
36698
  }
36256
36699
  } else {
36257
36700
  gitAlignResult = "Not a git repository \u2014 skipped git alignment";
@@ -36291,6 +36734,7 @@ async function handleCloseCommand(directory, args) {
36291
36734
  ...swarmPlanFilesRemoved > 0 ? [`- Removed ${swarmPlanFilesRemoved} SWARM_PLAN checkpoint artifact(s)`] : [],
36292
36735
  ...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : [],
36293
36736
  ...curationSucceeded && allLessons.length > 0 ? [`- Committed ${allLessons.length} lesson(s) to knowledge store`] : [],
36737
+ ...hivePromoted > 0 ? [`- Promoted ${hivePromoted} lesson(s) to hive knowledge`] : [],
36294
36738
  "",
36295
36739
  ...warnings.length > 0 ? ["## Warnings", ...warnings.map((w) => `- ${w}`), ""] : []
36296
36740
  ].join(`
@@ -36302,13 +36746,6 @@ async function handleCloseCommand(directory, args) {
36302
36746
  warnings.push(`Failed to write close-summary.md: ${msg}`);
36303
36747
  console.warn("[close-command] Failed to write close-summary.md:", error93);
36304
36748
  }
36305
- try {
36306
- await flushPendingSnapshot(directory);
36307
- } catch (error93) {
36308
- const msg = error93 instanceof Error ? error93.message : String(error93);
36309
- warnings.push(`flushPendingSnapshot failed: ${msg}`);
36310
- console.warn("[close-command] flushPendingSnapshot error:", error93);
36311
- }
36312
36749
  const preservedClient = swarmState.opencodeClient;
36313
36750
  const preservedFullAutoFlag = swarmState.fullAutoEnabledInConfig;
36314
36751
  const preservedCuratorInitNames = swarmState.curatorInitAgentNames;
@@ -36349,15 +36786,16 @@ ${otherWarnings.map((w) => `- ${w}`).join(`
36349
36786
  **Archive:** ${archiveResult}
36350
36787
  **Git:** ${gitAlignResult}${lessonSummary}${warningMsg}`;
36351
36788
  }
36352
- var ARCHIVE_ARTIFACTS, ACTIVE_STATE_TO_CLEAN;
36789
+ var ARCHIVE_ARTIFACTS, ACTIVE_STATE_TO_CLEAN, ACTIVE_STATE_DIRS_TO_CLEAN;
36353
36790
  var init_close = __esm(() => {
36354
36791
  init_schema();
36355
36792
  init_manager2();
36356
36793
  init_branch();
36794
+ init_hive_promoter();
36357
36795
  init_knowledge_curator();
36796
+ init_knowledge_store();
36358
36797
  init_utils2();
36359
36798
  init_scope_persistence();
36360
- init_snapshot_writer();
36361
36799
  init_state();
36362
36800
  init_write_retro();
36363
36801
  ARCHIVE_ARTIFACTS = [
@@ -36370,7 +36808,18 @@ var init_close = __esm(() => {
36370
36808
  "handoff-prompt.md",
36371
36809
  "handoff-consumed.md",
36372
36810
  "escalation-report.md",
36373
- "close-lessons.md"
36811
+ "close-lessons.md",
36812
+ "knowledge.jsonl",
36813
+ "knowledge-rejected.jsonl",
36814
+ "repo-graph.json",
36815
+ "doc-manifest.json",
36816
+ "dark-matter.md",
36817
+ "telemetry.jsonl",
36818
+ "swarm.db",
36819
+ "swarm.db-shm",
36820
+ "swarm.db-wal",
36821
+ "close-summary.md",
36822
+ "spec.md"
36374
36823
  ];
36375
36824
  ACTIVE_STATE_TO_CLEAN = [
36376
36825
  "plan.json",
@@ -36380,7 +36829,23 @@ var init_close = __esm(() => {
36380
36829
  "handoff.md",
36381
36830
  "handoff-prompt.md",
36382
36831
  "handoff-consumed.md",
36383
- "escalation-report.md"
36832
+ "escalation-report.md",
36833
+ "knowledge.jsonl",
36834
+ "knowledge-rejected.jsonl",
36835
+ "repo-graph.json",
36836
+ "doc-manifest.json",
36837
+ "dark-matter.md",
36838
+ "telemetry.jsonl",
36839
+ "swarm.db",
36840
+ "swarm.db-shm",
36841
+ "swarm.db-wal"
36842
+ ];
36843
+ ACTIVE_STATE_DIRS_TO_CLEAN = [
36844
+ "evidence",
36845
+ "session",
36846
+ "scopes",
36847
+ "locks",
36848
+ "spec-archive"
36384
36849
  ];
36385
36850
  });
36386
36851
 
@@ -36483,322 +36948,6 @@ var init_council = __esm(() => {
36483
36948
  `);
36484
36949
  });
36485
36950
 
36486
- // src/background/event-bus.ts
36487
- class AutomationEventBus {
36488
- listeners = new Map;
36489
- eventHistory = [];
36490
- maxHistorySize;
36491
- constructor(options) {
36492
- this.maxHistorySize = options?.maxHistorySize ?? 100;
36493
- }
36494
- subscribe(type, listener) {
36495
- if (!this.listeners.has(type)) {
36496
- this.listeners.set(type, new Set);
36497
- }
36498
- this.listeners.get(type).add(listener);
36499
- return () => {
36500
- this.listeners.get(type)?.delete(listener);
36501
- };
36502
- }
36503
- async publish(type, payload, source) {
36504
- const event = {
36505
- type,
36506
- timestamp: Date.now(),
36507
- payload,
36508
- source
36509
- };
36510
- this.eventHistory.push(event);
36511
- if (this.eventHistory.length > this.maxHistorySize) {
36512
- this.eventHistory.shift();
36513
- }
36514
- log(`[EventBus] ${type}`, {
36515
- source,
36516
- payload: typeof payload === "object" ? "..." : payload
36517
- });
36518
- const listeners = this.listeners.get(type);
36519
- if (listeners) {
36520
- await Promise.all(Array.from(listeners).map(async (listener) => {
36521
- try {
36522
- await listener(event);
36523
- } catch (error93) {
36524
- log(`[EventBus] Listener error for ${type}`, { error: error93 });
36525
- }
36526
- }));
36527
- }
36528
- }
36529
- getHistory(types) {
36530
- if (!types || types.length === 0) {
36531
- return [...this.eventHistory];
36532
- }
36533
- return this.eventHistory.filter((e) => types.includes(e.type));
36534
- }
36535
- clearHistory() {
36536
- this.eventHistory = [];
36537
- }
36538
- getListenerCount(type) {
36539
- return this.listeners.get(type)?.size ?? 0;
36540
- }
36541
- hasListeners(type) {
36542
- return this.getListenerCount(type) > 0;
36543
- }
36544
- }
36545
- function getGlobalEventBus() {
36546
- if (!globalEventBus) {
36547
- globalEventBus = new AutomationEventBus;
36548
- }
36549
- return globalEventBus;
36550
- }
36551
- var globalEventBus = null;
36552
- var init_event_bus = __esm(() => {
36553
- init_utils();
36554
- });
36555
-
36556
- // src/hooks/curator.ts
36557
- var init_curator = __esm(() => {
36558
- init_event_bus();
36559
- init_manager();
36560
- init_bun_compat();
36561
- init_logger();
36562
- init_knowledge_store();
36563
- init_knowledge_validator();
36564
- init_utils2();
36565
- });
36566
-
36567
- // src/hooks/hive-promoter.ts
36568
- import path16 from "path";
36569
- function isAlreadyInHive(entry, hiveEntries, threshold) {
36570
- return findNearDuplicate(entry.lesson, hiveEntries, threshold) !== undefined;
36571
- }
36572
- function countDistinctPhases(confirmedBy) {
36573
- const phaseNumbers = new Set;
36574
- for (const record3 of confirmedBy) {
36575
- phaseNumbers.add(record3.phase_number);
36576
- }
36577
- return phaseNumbers.size;
36578
- }
36579
- function countDistinctProjects(confirmedBy) {
36580
- const projectNames = new Set;
36581
- for (const record3 of confirmedBy) {
36582
- projectNames.add(record3.project_name);
36583
- }
36584
- return projectNames.size;
36585
- }
36586
- function hasProjectConfirmation(hiveEntry, projectName) {
36587
- return hiveEntry.confirmed_by.some((record3) => record3.project_name === projectName);
36588
- }
36589
- function calculateEncounterScore(currentScore, isSameProject, config3) {
36590
- const weight = isSameProject ? config3.same_project_weight : config3.cross_project_weight;
36591
- const increment = config3.encounter_increment * weight;
36592
- const newScore = currentScore + increment;
36593
- return Math.min(Math.max(newScore, config3.min_encounter_score), config3.max_encounter_score);
36594
- }
36595
- function getEntryAgeMs(createdAt) {
36596
- const createdTime = new Date(createdAt).getTime();
36597
- if (Number.isNaN(createdTime))
36598
- return 0;
36599
- return Date.now() - createdTime;
36600
- }
36601
- async function checkHivePromotions(swarmEntries, config3) {
36602
- let newPromotions = 0;
36603
- let encountersIncremented = 0;
36604
- let advancements = 0;
36605
- if (config3.hive_enabled === false) {
36606
- return {
36607
- timestamp: new Date().toISOString(),
36608
- new_promotions: 0,
36609
- encounters_incremented: 0,
36610
- advancements: 0,
36611
- total_hive_entries: 0
36612
- };
36613
- }
36614
- const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
36615
- for (const swarmEntry of swarmEntries) {
36616
- if (isAlreadyInHive(swarmEntry, hiveEntries, config3.dedup_threshold)) {
36617
- continue;
36618
- }
36619
- let shouldPromote = false;
36620
- if (swarmEntry.hive_eligible === true && countDistinctPhases(swarmEntry.confirmed_by) >= 3) {
36621
- shouldPromote = true;
36622
- }
36623
- if (swarmEntry.tags.includes("hive-fast-track")) {
36624
- shouldPromote = true;
36625
- }
36626
- const ageMs = getEntryAgeMs(swarmEntry.created_at);
36627
- const ageThresholdMs = config3.auto_promote_days * 86400000;
36628
- if (ageMs >= ageThresholdMs) {
36629
- shouldPromote = true;
36630
- }
36631
- if (!shouldPromote) {
36632
- continue;
36633
- }
36634
- const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
36635
- category: swarmEntry.category,
36636
- scope: swarmEntry.scope,
36637
- confidence: swarmEntry.confidence
36638
- });
36639
- if (validationResult.severity === "error") {
36640
- const rejectedLesson = {
36641
- id: crypto.randomUUID(),
36642
- lesson: swarmEntry.lesson,
36643
- rejection_reason: validationResult.reason || "validation failed for hive promotion",
36644
- rejected_at: new Date().toISOString(),
36645
- rejection_layer: validationResult.layer || 2
36646
- };
36647
- const hiveRejectedPath = resolveHiveRejectedPath();
36648
- await appendKnowledge(hiveRejectedPath, rejectedLesson);
36649
- continue;
36650
- }
36651
- const newHiveEntry = {
36652
- id: crypto.randomUUID(),
36653
- tier: "hive",
36654
- lesson: swarmEntry.lesson,
36655
- category: swarmEntry.category,
36656
- tags: swarmEntry.tags,
36657
- scope: swarmEntry.scope,
36658
- confidence: 0.5,
36659
- status: "candidate",
36660
- confirmed_by: [],
36661
- retrieval_outcomes: {
36662
- applied_count: 0,
36663
- succeeded_after_count: 0,
36664
- failed_after_count: 0
36665
- },
36666
- schema_version: config3.schema_version,
36667
- created_at: new Date().toISOString(),
36668
- updated_at: new Date().toISOString(),
36669
- source_project: swarmEntry.project_name,
36670
- encounter_score: config3.initial_encounter_score
36671
- };
36672
- await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
36673
- newPromotions++;
36674
- hiveEntries.push(newHiveEntry);
36675
- }
36676
- let hiveModified = false;
36677
- for (const hiveEntry of hiveEntries) {
36678
- const nearDuplicate = findNearDuplicate(hiveEntry.lesson, swarmEntries, config3.dedup_threshold);
36679
- if (!nearDuplicate) {
36680
- continue;
36681
- }
36682
- const isSameProject = nearDuplicate.project_name === hiveEntry.source_project;
36683
- if (hasProjectConfirmation(hiveEntry, nearDuplicate.project_name)) {
36684
- continue;
36685
- }
36686
- const newConfirmation = {
36687
- project_name: nearDuplicate.project_name,
36688
- confirmed_at: new Date().toISOString()
36689
- };
36690
- hiveEntry.confirmed_by.push(newConfirmation);
36691
- const currentScore = hiveEntry.encounter_score ?? 1;
36692
- hiveEntry.encounter_score = calculateEncounterScore(currentScore, isSameProject, config3);
36693
- encountersIncremented++;
36694
- hiveEntry.updated_at = new Date().toISOString();
36695
- if (hiveEntry.status === "candidate" && countDistinctProjects(hiveEntry.confirmed_by) >= 3) {
36696
- hiveEntry.status = "established";
36697
- advancements++;
36698
- }
36699
- hiveModified = true;
36700
- }
36701
- if (hiveModified) {
36702
- await rewriteKnowledge(resolveHiveKnowledgePath(), hiveEntries);
36703
- }
36704
- if (newPromotions > 0 || hiveModified) {
36705
- await enforceKnowledgeCap(resolveHiveKnowledgePath(), config3.hive_max_entries);
36706
- }
36707
- return {
36708
- timestamp: new Date().toISOString(),
36709
- new_promotions: newPromotions,
36710
- encounters_incremented: encountersIncremented,
36711
- advancements,
36712
- total_hive_entries: hiveEntries.length
36713
- };
36714
- }
36715
- async function promoteToHive(directory, lesson, category) {
36716
- const trimmedLesson = lesson.trim();
36717
- const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
36718
- const validationResult = validateLesson(trimmedLesson, hiveEntries.map((e) => e.lesson), {
36719
- category: category || "process",
36720
- scope: "global",
36721
- confidence: 1
36722
- });
36723
- if (validationResult.severity === "error") {
36724
- throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
36725
- }
36726
- if (findNearDuplicate(trimmedLesson, hiveEntries, 0.6)) {
36727
- return `Lesson already exists in hive (near-duplicate).`;
36728
- }
36729
- const newHiveEntry = {
36730
- id: crypto.randomUUID(),
36731
- tier: "hive",
36732
- lesson: trimmedLesson,
36733
- category: category || "process",
36734
- tags: [],
36735
- scope: "global",
36736
- confidence: 1,
36737
- status: "promoted",
36738
- confirmed_by: [],
36739
- retrieval_outcomes: {
36740
- applied_count: 0,
36741
- succeeded_after_count: 0,
36742
- failed_after_count: 0
36743
- },
36744
- schema_version: 1,
36745
- created_at: new Date().toISOString(),
36746
- updated_at: new Date().toISOString(),
36747
- source_project: path16.basename(directory) || "unknown",
36748
- encounter_score: 1
36749
- };
36750
- await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
36751
- return `Promoted to hive: "${trimmedLesson.slice(0, 50)}${trimmedLesson.length > 50 ? "..." : ""}" (confidence: 1.0, source: manual)`;
36752
- }
36753
- async function promoteFromSwarm(directory, lessonId) {
36754
- const swarmEntries = await readKnowledge(resolveSwarmKnowledgePath(directory));
36755
- const swarmEntry = swarmEntries.find((e) => e.id === lessonId);
36756
- if (!swarmEntry) {
36757
- throw new Error(`Lesson ${lessonId} not found in .swarm/knowledge.jsonl`);
36758
- }
36759
- const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
36760
- const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
36761
- category: swarmEntry.category,
36762
- scope: swarmEntry.scope,
36763
- confidence: swarmEntry.confidence
36764
- });
36765
- if (validationResult.severity === "error") {
36766
- throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
36767
- }
36768
- if (findNearDuplicate(swarmEntry.lesson, hiveEntries, 0.6)) {
36769
- return `Lesson already exists in hive (near-duplicate).`;
36770
- }
36771
- const newHiveEntry = {
36772
- id: crypto.randomUUID(),
36773
- tier: "hive",
36774
- lesson: swarmEntry.lesson,
36775
- category: swarmEntry.category,
36776
- tags: swarmEntry.tags,
36777
- scope: swarmEntry.scope,
36778
- confidence: 1,
36779
- status: "promoted",
36780
- confirmed_by: [],
36781
- retrieval_outcomes: {
36782
- applied_count: 0,
36783
- succeeded_after_count: 0,
36784
- failed_after_count: 0
36785
- },
36786
- schema_version: 1,
36787
- created_at: new Date().toISOString(),
36788
- updated_at: new Date().toISOString(),
36789
- source_project: swarmEntry.project_name,
36790
- encounter_score: 1
36791
- };
36792
- await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
36793
- return `Promoted lesson ${lessonId} from swarm to hive: "${swarmEntry.lesson.slice(0, 50)}${swarmEntry.lesson.length > 50 ? "..." : ""}"`;
36794
- }
36795
- var init_hive_promoter = __esm(() => {
36796
- init_curator();
36797
- init_knowledge_store();
36798
- init_knowledge_validator();
36799
- init_utils2();
36800
- });
36801
-
36802
36951
  // src/commands/curate.ts
36803
36952
  async function handleCurateCommand(directory, _args) {
36804
36953
  try {
@@ -36836,7 +36985,7 @@ var init_curate = __esm(() => {
36836
36985
  import * as child_process3 from "child_process";
36837
36986
  import { randomUUID } from "crypto";
36838
36987
  import { readdir, readFile as readFile5, stat as stat2 } from "fs/promises";
36839
- import * as path17 from "path";
36988
+ import * as path16 from "path";
36840
36989
  import { promisify } from "util";
36841
36990
  function getExecFileAsync() {
36842
36991
  return promisify(child_process3.execFile);
@@ -36938,7 +37087,7 @@ async function scanSourceFiles(dir) {
36938
37087
  try {
36939
37088
  const entries = await readdir(dir, { withFileTypes: true });
36940
37089
  for (const entry of entries) {
36941
- const fullPath = path17.join(dir, entry.name);
37090
+ const fullPath = path16.join(dir, entry.name);
36942
37091
  if (entry.isDirectory()) {
36943
37092
  if (skipDirs.has(entry.name)) {
36944
37093
  continue;
@@ -36946,7 +37095,7 @@ async function scanSourceFiles(dir) {
36946
37095
  const subFiles = await scanSourceFiles(fullPath);
36947
37096
  results.push(...subFiles);
36948
37097
  } else if (entry.isFile()) {
36949
- const ext = path17.extname(entry.name);
37098
+ const ext = path16.extname(entry.name);
36950
37099
  if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
36951
37100
  results.push(fullPath);
36952
37101
  }
@@ -36968,8 +37117,8 @@ async function getStaticEdges(directory) {
36968
37117
  continue;
36969
37118
  }
36970
37119
  try {
36971
- const sourceDir = path17.dirname(sourceFile);
36972
- const resolvedPath = path17.resolve(sourceDir, importPath);
37120
+ const sourceDir = path16.dirname(sourceFile);
37121
+ const resolvedPath = path16.resolve(sourceDir, importPath);
36973
37122
  const extensions = [
36974
37123
  "",
36975
37124
  ".ts",
@@ -36994,8 +37143,8 @@ async function getStaticEdges(directory) {
36994
37143
  if (!targetFile) {
36995
37144
  continue;
36996
37145
  }
36997
- const relSource = path17.relative(directory, sourceFile).replace(/\\/g, "/");
36998
- const relTarget = path17.relative(directory, targetFile).replace(/\\/g, "/");
37146
+ const relSource = path16.relative(directory, sourceFile).replace(/\\/g, "/");
37147
+ const relTarget = path16.relative(directory, targetFile).replace(/\\/g, "/");
36999
37148
  const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
37000
37149
  edges.add(key);
37001
37150
  } catch {}
@@ -37007,7 +37156,7 @@ async function getStaticEdges(directory) {
37007
37156
  function isTestImplementationPair(fileA, fileB) {
37008
37157
  const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
37009
37158
  const getBaseName = (filePath) => {
37010
- const base = path17.basename(filePath);
37159
+ const base = path16.basename(filePath);
37011
37160
  for (const pattern of testPatterns) {
37012
37161
  if (base.endsWith(pattern)) {
37013
37162
  return base.slice(0, -pattern.length);
@@ -37017,16 +37166,16 @@ function isTestImplementationPair(fileA, fileB) {
37017
37166
  };
37018
37167
  const baseA = getBaseName(fileA);
37019
37168
  const baseB = getBaseName(fileB);
37020
- return baseA === baseB && baseA !== path17.basename(fileA) && baseA !== path17.basename(fileB);
37169
+ return baseA === baseB && baseA !== path16.basename(fileA) && baseA !== path16.basename(fileB);
37021
37170
  }
37022
37171
  function hasSharedPrefix(fileA, fileB) {
37023
- const dirA = path17.dirname(fileA);
37024
- const dirB = path17.dirname(fileB);
37172
+ const dirA = path16.dirname(fileA);
37173
+ const dirB = path16.dirname(fileB);
37025
37174
  if (dirA !== dirB) {
37026
37175
  return false;
37027
37176
  }
37028
- const baseA = path17.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
37029
- const baseB = path17.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
37177
+ const baseA = path16.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
37178
+ const baseB = path16.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
37030
37179
  if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
37031
37180
  return true;
37032
37181
  }
@@ -37054,9 +37203,9 @@ async function detectDarkMatter(directory, options) {
37054
37203
  } catch {
37055
37204
  return [];
37056
37205
  }
37057
- const commitMap = await _internals10.parseGitLog(directory, maxCommitsToAnalyze);
37058
- const matrix = _internals10.buildCoChangeMatrix(commitMap);
37059
- const staticEdges = await _internals10.getStaticEdges(directory);
37206
+ const commitMap = await _internals9.parseGitLog(directory, maxCommitsToAnalyze);
37207
+ const matrix = _internals9.buildCoChangeMatrix(commitMap);
37208
+ const staticEdges = await _internals9.getStaticEdges(directory);
37060
37209
  const results = [];
37061
37210
  for (const entry of matrix.values()) {
37062
37211
  const key = `${entry.fileA}::${entry.fileB}`;
@@ -37080,8 +37229,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
37080
37229
  const entries = [];
37081
37230
  const now = new Date().toISOString();
37082
37231
  for (const pair of pairs.slice(0, 10)) {
37083
- const baseA = path17.basename(pair.fileA);
37084
- const baseB = path17.basename(pair.fileB);
37232
+ const baseA = path16.basename(pair.fileA);
37233
+ const baseB = path16.basename(pair.fileB);
37085
37234
  let lesson = `Files ${pair.fileA} and ${pair.fileB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
37086
37235
  if (lesson.length > 280) {
37087
37236
  lesson = `Files ${baseA} and ${baseB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
@@ -37136,7 +37285,7 @@ ${rows}
37136
37285
  These pairs likely share an architectural concern invisible to static analysis.
37137
37286
  Consider adding explicit documentation or extracting the shared concern.`;
37138
37287
  }
37139
- var co_change_analyzer, _internals10;
37288
+ var co_change_analyzer, _internals9;
37140
37289
  var init_co_change_analyzer = __esm(() => {
37141
37290
  init_zod();
37142
37291
  init_create_tool();
@@ -37168,11 +37317,11 @@ var init_co_change_analyzer = __esm(() => {
37168
37317
  npmiThreshold,
37169
37318
  maxCommitsToAnalyze
37170
37319
  };
37171
- const pairs = await _internals10.detectDarkMatter(directory, options);
37172
- return _internals10.formatDarkMatterOutput(pairs);
37320
+ const pairs = await _internals9.detectDarkMatter(directory, options);
37321
+ return _internals9.formatDarkMatterOutput(pairs);
37173
37322
  }
37174
37323
  });
37175
- _internals10 = {
37324
+ _internals9 = {
37176
37325
  parseGitLog,
37177
37326
  buildCoChangeMatrix,
37178
37327
  getStaticEdges,
@@ -37183,7 +37332,7 @@ var init_co_change_analyzer = __esm(() => {
37183
37332
  });
37184
37333
 
37185
37334
  // src/commands/dark-matter.ts
37186
- import path18 from "path";
37335
+ import path17 from "path";
37187
37336
  async function handleDarkMatterCommand(directory, args) {
37188
37337
  const options = {};
37189
37338
  for (let i = 0;i < args.length; i++) {
@@ -37201,11 +37350,21 @@ async function handleDarkMatterCommand(directory, args) {
37201
37350
  i++;
37202
37351
  }
37203
37352
  }
37204
- const pairs = await detectDarkMatter(directory, options);
37353
+ let pairs;
37354
+ try {
37355
+ pairs = await _internals9.detectDarkMatter(directory, options);
37356
+ } catch (err) {
37357
+ const errMsg = err instanceof Error ? err.message : String(err);
37358
+ return `## Dark Matter Analysis Failed
37359
+
37360
+ Error analyzing git history: ${errMsg}
37361
+
37362
+ Ensure this is a git repository with commit history.`;
37363
+ }
37205
37364
  const output = formatDarkMatterOutput(pairs);
37206
37365
  if (pairs.length > 0) {
37207
37366
  try {
37208
- const projectName = path18.basename(path18.resolve(directory));
37367
+ const projectName = path17.basename(path17.resolve(directory));
37209
37368
  const entries = darkMatterToKnowledgeEntries(pairs, projectName);
37210
37369
  if (entries.length > 0) {
37211
37370
  const knowledgePath = resolveSwarmKnowledgePath(directory);
@@ -37230,51 +37389,51 @@ var init_dark_matter = __esm(() => {
37230
37389
 
37231
37390
  // src/config/cache-paths.ts
37232
37391
  import * as os5 from "os";
37233
- import * as path19 from "path";
37392
+ import * as path18 from "path";
37234
37393
  function getPluginConfigDir() {
37235
- return path19.join(process.env.XDG_CONFIG_HOME || path19.join(os5.homedir(), ".config"), "opencode");
37394
+ return path18.join(process.env.XDG_CONFIG_HOME || path18.join(os5.homedir(), ".config"), "opencode");
37236
37395
  }
37237
37396
  function getPluginCachePaths() {
37238
- const cacheBase = process.env.XDG_CACHE_HOME || path19.join(os5.homedir(), ".cache");
37397
+ const cacheBase = process.env.XDG_CACHE_HOME || path18.join(os5.homedir(), ".cache");
37239
37398
  const configDir = getPluginConfigDir();
37240
37399
  const paths = [
37241
- path19.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
37242
- path19.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
37243
- path19.join(configDir, "node_modules", "opencode-swarm")
37400
+ path18.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
37401
+ path18.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
37402
+ path18.join(configDir, "node_modules", "opencode-swarm")
37244
37403
  ];
37245
37404
  if (process.platform === "darwin") {
37246
- const libCaches = path19.join(os5.homedir(), "Library", "Caches");
37247
- paths.push(path19.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path19.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
37405
+ const libCaches = path18.join(os5.homedir(), "Library", "Caches");
37406
+ paths.push(path18.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path18.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
37248
37407
  }
37249
37408
  if (process.platform === "win32") {
37250
- const localAppData = process.env.LOCALAPPDATA || path19.join(os5.homedir(), "AppData", "Local");
37251
- const appData = process.env.APPDATA || path19.join(os5.homedir(), "AppData", "Roaming");
37252
- paths.push(path19.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path19.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path19.join(appData, "opencode", "node_modules", "opencode-swarm"));
37409
+ const localAppData = process.env.LOCALAPPDATA || path18.join(os5.homedir(), "AppData", "Local");
37410
+ const appData = process.env.APPDATA || path18.join(os5.homedir(), "AppData", "Roaming");
37411
+ paths.push(path18.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path18.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path18.join(appData, "opencode", "node_modules", "opencode-swarm"));
37253
37412
  }
37254
37413
  return paths;
37255
37414
  }
37256
37415
  function getPluginLockFilePaths() {
37257
- const cacheBase = process.env.XDG_CACHE_HOME || path19.join(os5.homedir(), ".cache");
37416
+ const cacheBase = process.env.XDG_CACHE_HOME || path18.join(os5.homedir(), ".cache");
37258
37417
  const configDir = getPluginConfigDir();
37259
37418
  const paths = [
37260
- path19.join(cacheBase, "opencode", "bun.lock"),
37261
- path19.join(cacheBase, "opencode", "bun.lockb"),
37262
- path19.join(configDir, "package-lock.json")
37419
+ path18.join(cacheBase, "opencode", "bun.lock"),
37420
+ path18.join(cacheBase, "opencode", "bun.lockb"),
37421
+ path18.join(configDir, "package-lock.json")
37263
37422
  ];
37264
37423
  if (process.platform === "darwin") {
37265
- const libCaches = path19.join(os5.homedir(), "Library", "Caches");
37266
- paths.push(path19.join(libCaches, "opencode", "bun.lock"), path19.join(libCaches, "opencode", "bun.lockb"));
37424
+ const libCaches = path18.join(os5.homedir(), "Library", "Caches");
37425
+ paths.push(path18.join(libCaches, "opencode", "bun.lock"), path18.join(libCaches, "opencode", "bun.lockb"));
37267
37426
  }
37268
37427
  if (process.platform === "win32") {
37269
- const localAppData = process.env.LOCALAPPDATA || path19.join(os5.homedir(), "AppData", "Local");
37270
- paths.push(path19.join(localAppData, "opencode", "bun.lock"), path19.join(localAppData, "opencode", "bun.lockb"));
37428
+ const localAppData = process.env.LOCALAPPDATA || path18.join(os5.homedir(), "AppData", "Local");
37429
+ paths.push(path18.join(localAppData, "opencode", "bun.lock"), path18.join(localAppData, "opencode", "bun.lockb"));
37271
37430
  }
37272
37431
  return paths;
37273
37432
  }
37274
37433
  var init_cache_paths = () => {};
37275
37434
 
37276
37435
  // src/services/version-check.ts
37277
- import { existsSync as existsSync9, mkdirSync as mkdirSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
37436
+ import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
37278
37437
  import { homedir as homedir5 } from "os";
37279
37438
  import { join as join17 } from "path";
37280
37439
  function cacheDir() {
@@ -37287,10 +37446,10 @@ function cacheFile() {
37287
37446
  }
37288
37447
  function readVersionCache() {
37289
37448
  try {
37290
- const path20 = cacheFile();
37291
- if (!existsSync9(path20))
37449
+ const path19 = cacheFile();
37450
+ if (!existsSync9(path19))
37292
37451
  return null;
37293
- const raw = readFileSync5(path20, "utf-8");
37452
+ const raw = readFileSync5(path19, "utf-8");
37294
37453
  const parsed = JSON.parse(raw);
37295
37454
  if (typeof parsed?.checkedAt !== "number")
37296
37455
  return null;
@@ -37330,7 +37489,7 @@ var init_version_check = __esm(() => {
37330
37489
  // src/services/diagnose-service.ts
37331
37490
  import * as child_process4 from "child_process";
37332
37491
  import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync6 } from "fs";
37333
- import path20 from "path";
37492
+ import path19 from "path";
37334
37493
  import { fileURLToPath } from "url";
37335
37494
  function validateTaskDag(plan) {
37336
37495
  const allTaskIds = new Set;
@@ -37627,7 +37786,7 @@ async function checkSpecStaleness(directory, plan) {
37627
37786
  };
37628
37787
  }
37629
37788
  async function checkConfigParseability(directory) {
37630
- const configPath = path20.join(directory, ".opencode/opencode-swarm.json");
37789
+ const configPath = path19.join(directory, ".opencode/opencode-swarm.json");
37631
37790
  if (!existsSync10(configPath)) {
37632
37791
  return {
37633
37792
  name: "Config Parseability",
@@ -37656,7 +37815,7 @@ function resolveGrammarDir(thisDir) {
37656
37815
  const normalized = thisDir.replace(/\\/g, "/");
37657
37816
  const isSource = normalized.endsWith("/src/services");
37658
37817
  const isCliBundle = normalized.endsWith("/cli");
37659
- return isSource || isCliBundle ? path20.join(thisDir, "..", "lang", "grammars") : path20.join(thisDir, "lang", "grammars");
37818
+ return isSource || isCliBundle ? path19.join(thisDir, "..", "lang", "grammars") : path19.join(thisDir, "lang", "grammars");
37660
37819
  }
37661
37820
  async function checkGrammarWasmFiles() {
37662
37821
  const grammarFiles = [
@@ -37680,14 +37839,14 @@ async function checkGrammarWasmFiles() {
37680
37839
  "tree-sitter-ini.wasm",
37681
37840
  "tree-sitter-regex.wasm"
37682
37841
  ];
37683
- const thisDir = path20.dirname(fileURLToPath(import.meta.url));
37842
+ const thisDir = path19.dirname(fileURLToPath(import.meta.url));
37684
37843
  const grammarDir = resolveGrammarDir(thisDir);
37685
37844
  const missing = [];
37686
- if (!existsSync10(path20.join(grammarDir, "tree-sitter.wasm"))) {
37845
+ if (!existsSync10(path19.join(grammarDir, "tree-sitter.wasm"))) {
37687
37846
  missing.push("tree-sitter.wasm (core runtime)");
37688
37847
  }
37689
37848
  for (const file3 of grammarFiles) {
37690
- if (!existsSync10(path20.join(grammarDir, file3))) {
37849
+ if (!existsSync10(path19.join(grammarDir, file3))) {
37691
37850
  missing.push(file3);
37692
37851
  }
37693
37852
  }
@@ -37705,7 +37864,7 @@ async function checkGrammarWasmFiles() {
37705
37864
  };
37706
37865
  }
37707
37866
  async function checkCheckpointManifest(directory) {
37708
- const manifestPath = path20.join(directory, ".swarm/checkpoints.json");
37867
+ const manifestPath = path19.join(directory, ".swarm/checkpoints.json");
37709
37868
  if (!existsSync10(manifestPath)) {
37710
37869
  return {
37711
37870
  name: "Checkpoint Manifest",
@@ -37757,7 +37916,7 @@ async function checkCheckpointManifest(directory) {
37757
37916
  }
37758
37917
  }
37759
37918
  async function checkEventStreamIntegrity(directory) {
37760
- const eventsPath = path20.join(directory, ".swarm/events.jsonl");
37919
+ const eventsPath = path19.join(directory, ".swarm/events.jsonl");
37761
37920
  if (!existsSync10(eventsPath)) {
37762
37921
  return {
37763
37922
  name: "Event Stream",
@@ -37798,7 +37957,7 @@ async function checkEventStreamIntegrity(directory) {
37798
37957
  }
37799
37958
  }
37800
37959
  async function checkSteeringDirectives(directory) {
37801
- const eventsPath = path20.join(directory, ".swarm/events.jsonl");
37960
+ const eventsPath = path19.join(directory, ".swarm/events.jsonl");
37802
37961
  if (!existsSync10(eventsPath)) {
37803
37962
  return {
37804
37963
  name: "Steering Directives",
@@ -37854,7 +38013,7 @@ async function checkCurator(directory) {
37854
38013
  detail: "Disabled (enable via curator.enabled)"
37855
38014
  };
37856
38015
  }
37857
- const summaryPath = path20.join(directory, ".swarm/curator-summary.json");
38016
+ const summaryPath = path19.join(directory, ".swarm/curator-summary.json");
37858
38017
  if (!existsSync10(summaryPath)) {
37859
38018
  return {
37860
38019
  name: "Curator",
@@ -38020,7 +38179,7 @@ async function getDiagnoseData(directory) {
38020
38179
  checks5.push(await checkSteeringDirectives(directory));
38021
38180
  checks5.push(await checkCurator(directory));
38022
38181
  try {
38023
- const evidenceDir = path20.join(directory, ".swarm", "evidence");
38182
+ const evidenceDir = path19.join(directory, ".swarm", "evidence");
38024
38183
  const snapshotFiles = existsSync10(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
38025
38184
  if (snapshotFiles.length > 0) {
38026
38185
  const latest = snapshotFiles.sort().pop();
@@ -38058,7 +38217,7 @@ async function getDiagnoseData(directory) {
38058
38217
  cacheRows.push(`\u2B1C ${cachePath} \u2014 absent`);
38059
38218
  continue;
38060
38219
  }
38061
- const pkgJsonPath = path20.join(cachePath, "package.json");
38220
+ const pkgJsonPath = path19.join(cachePath, "package.json");
38062
38221
  try {
38063
38222
  const raw = readFileSync6(pkgJsonPath, "utf-8");
38064
38223
  const parsed = JSON.parse(raw);
@@ -38146,13 +38305,13 @@ __export(exports_config_doctor, {
38146
38305
  import * as crypto3 from "crypto";
38147
38306
  import * as fs8 from "fs";
38148
38307
  import * as os6 from "os";
38149
- import * as path21 from "path";
38308
+ import * as path20 from "path";
38150
38309
  function getUserConfigDir3() {
38151
- return process.env.XDG_CONFIG_HOME || path21.join(os6.homedir(), ".config");
38310
+ return process.env.XDG_CONFIG_HOME || path20.join(os6.homedir(), ".config");
38152
38311
  }
38153
38312
  function getConfigPaths(directory) {
38154
- const userConfigPath = path21.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
38155
- const projectConfigPath = path21.join(directory, ".opencode", "opencode-swarm.json");
38313
+ const userConfigPath = path20.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
38314
+ const projectConfigPath = path20.join(directory, ".opencode", "opencode-swarm.json");
38156
38315
  return { userConfigPath, projectConfigPath };
38157
38316
  }
38158
38317
  function computeHash(content) {
@@ -38177,9 +38336,9 @@ function isValidConfigPath(configPath, directory) {
38177
38336
  const normalizedUser = userConfigPath.replace(/\\/g, "/");
38178
38337
  const normalizedProject = projectConfigPath.replace(/\\/g, "/");
38179
38338
  try {
38180
- const resolvedConfig = path21.resolve(configPath);
38181
- const resolvedUser = path21.resolve(normalizedUser);
38182
- const resolvedProject = path21.resolve(normalizedProject);
38339
+ const resolvedConfig = path20.resolve(configPath);
38340
+ const resolvedUser = path20.resolve(normalizedUser);
38341
+ const resolvedProject = path20.resolve(normalizedProject);
38183
38342
  return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
38184
38343
  } catch {
38185
38344
  return false;
@@ -38219,12 +38378,12 @@ function createConfigBackup(directory) {
38219
38378
  };
38220
38379
  }
38221
38380
  function writeBackupArtifact(directory, backup) {
38222
- const swarmDir = path21.join(directory, ".swarm");
38381
+ const swarmDir = path20.join(directory, ".swarm");
38223
38382
  if (!fs8.existsSync(swarmDir)) {
38224
38383
  fs8.mkdirSync(swarmDir, { recursive: true });
38225
38384
  }
38226
38385
  const backupFilename = `config-backup-${backup.createdAt}.json`;
38227
- const backupPath = path21.join(swarmDir, backupFilename);
38386
+ const backupPath = path20.join(swarmDir, backupFilename);
38228
38387
  const artifact = {
38229
38388
  createdAt: backup.createdAt,
38230
38389
  configPath: backup.configPath,
@@ -38254,7 +38413,7 @@ function restoreFromBackup(backupPath, directory) {
38254
38413
  return null;
38255
38414
  }
38256
38415
  const targetPath = artifact.configPath;
38257
- const targetDir = path21.dirname(targetPath);
38416
+ const targetDir = path20.dirname(targetPath);
38258
38417
  if (!fs8.existsSync(targetDir)) {
38259
38418
  fs8.mkdirSync(targetDir, { recursive: true });
38260
38419
  }
@@ -38285,9 +38444,9 @@ function readConfigFromFile(directory) {
38285
38444
  return null;
38286
38445
  }
38287
38446
  }
38288
- function validateConfigKey(path22, value, _config) {
38447
+ function validateConfigKey(path21, value, _config) {
38289
38448
  const findings = [];
38290
- switch (path22) {
38449
+ switch (path21) {
38291
38450
  case "agents": {
38292
38451
  if (value !== undefined) {
38293
38452
  findings.push({
@@ -38534,27 +38693,27 @@ function validateConfigKey(path22, value, _config) {
38534
38693
  }
38535
38694
  return findings;
38536
38695
  }
38537
- function walkConfigAndValidate(obj, path22, config3, findings) {
38696
+ function walkConfigAndValidate(obj, path21, config3, findings) {
38538
38697
  if (obj === null || obj === undefined) {
38539
38698
  return;
38540
38699
  }
38541
- if (path22 && typeof obj === "object" && !Array.isArray(obj)) {
38542
- const keyFindings = validateConfigKey(path22, obj, config3);
38700
+ if (path21 && typeof obj === "object" && !Array.isArray(obj)) {
38701
+ const keyFindings = validateConfigKey(path21, obj, config3);
38543
38702
  findings.push(...keyFindings);
38544
38703
  }
38545
38704
  if (typeof obj !== "object") {
38546
- const keyFindings = validateConfigKey(path22, obj, config3);
38705
+ const keyFindings = validateConfigKey(path21, obj, config3);
38547
38706
  findings.push(...keyFindings);
38548
38707
  return;
38549
38708
  }
38550
38709
  if (Array.isArray(obj)) {
38551
38710
  obj.forEach((item, index) => {
38552
- walkConfigAndValidate(item, `${path22}[${index}]`, config3, findings);
38711
+ walkConfigAndValidate(item, `${path21}[${index}]`, config3, findings);
38553
38712
  });
38554
38713
  return;
38555
38714
  }
38556
38715
  for (const [key, value] of Object.entries(obj)) {
38557
- const newPath = path22 ? `${path22}.${key}` : key;
38716
+ const newPath = path21 ? `${path21}.${key}` : key;
38558
38717
  walkConfigAndValidate(value, newPath, config3, findings);
38559
38718
  }
38560
38719
  }
@@ -38674,7 +38833,7 @@ function applySafeAutoFixes(directory, result) {
38674
38833
  }
38675
38834
  }
38676
38835
  if (appliedFixes.length > 0) {
38677
- const configDir = path21.dirname(configPath);
38836
+ const configDir = path20.dirname(configPath);
38678
38837
  if (!fs8.existsSync(configDir)) {
38679
38838
  fs8.mkdirSync(configDir, { recursive: true });
38680
38839
  }
@@ -38684,12 +38843,12 @@ function applySafeAutoFixes(directory, result) {
38684
38843
  return { appliedFixes, updatedConfigPath };
38685
38844
  }
38686
38845
  function writeDoctorArtifact(directory, result) {
38687
- const swarmDir = path21.join(directory, ".swarm");
38846
+ const swarmDir = path20.join(directory, ".swarm");
38688
38847
  if (!fs8.existsSync(swarmDir)) {
38689
38848
  fs8.mkdirSync(swarmDir, { recursive: true });
38690
38849
  }
38691
38850
  const artifactFilename = "config-doctor.json";
38692
- const artifactPath = path21.join(swarmDir, artifactFilename);
38851
+ const artifactPath = path20.join(swarmDir, artifactFilename);
38693
38852
  const guiOutput = {
38694
38853
  timestamp: result.timestamp,
38695
38854
  summary: result.summary,
@@ -39792,7 +39951,7 @@ var init_detector = __esm(() => {
39792
39951
 
39793
39952
  // src/build/discovery.ts
39794
39953
  import * as fs9 from "fs";
39795
- import * as path22 from "path";
39954
+ import * as path21 from "path";
39796
39955
  function isCommandAvailable(command) {
39797
39956
  if (toolchainCache.has(command)) {
39798
39957
  return toolchainCache.get(command);
@@ -39824,11 +39983,11 @@ function findBuildFiles(workingDir, patterns) {
39824
39983
  const regex = simpleGlobToRegex(pattern);
39825
39984
  const matches = files.filter((f) => regex.test(f));
39826
39985
  if (matches.length > 0) {
39827
- return path22.join(dir, matches[0]);
39986
+ return path21.join(dir, matches[0]);
39828
39987
  }
39829
39988
  } catch {}
39830
39989
  } else {
39831
- const filePath = path22.join(workingDir, pattern);
39990
+ const filePath = path21.join(workingDir, pattern);
39832
39991
  if (fs9.existsSync(filePath)) {
39833
39992
  return filePath;
39834
39993
  }
@@ -39837,7 +39996,7 @@ function findBuildFiles(workingDir, patterns) {
39837
39996
  return null;
39838
39997
  }
39839
39998
  function getRepoDefinedScripts(workingDir, scripts) {
39840
- const packageJsonPath = path22.join(workingDir, "package.json");
39999
+ const packageJsonPath = path21.join(workingDir, "package.json");
39841
40000
  if (!fs9.existsSync(packageJsonPath)) {
39842
40001
  return [];
39843
40002
  }
@@ -39878,7 +40037,7 @@ function findAllBuildFiles(workingDir) {
39878
40037
  const regex = simpleGlobToRegex(pattern);
39879
40038
  findFilesRecursive(workingDir, regex, allBuildFiles);
39880
40039
  } else {
39881
- const filePath = path22.join(workingDir, pattern);
40040
+ const filePath = path21.join(workingDir, pattern);
39882
40041
  if (fs9.existsSync(filePath)) {
39883
40042
  allBuildFiles.add(filePath);
39884
40043
  }
@@ -39891,7 +40050,7 @@ function findFilesRecursive(dir, regex, results) {
39891
40050
  try {
39892
40051
  const entries = fs9.readdirSync(dir, { withFileTypes: true });
39893
40052
  for (const entry of entries) {
39894
- const fullPath = path22.join(dir, entry.name);
40053
+ const fullPath = path21.join(dir, entry.name);
39895
40054
  if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
39896
40055
  findFilesRecursive(fullPath, regex, results);
39897
40056
  } else if (entry.isFile() && regex.test(entry.name)) {
@@ -39914,7 +40073,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
39914
40073
  let foundCommand = false;
39915
40074
  for (const cmd of sortedCommands) {
39916
40075
  if (cmd.detectFile) {
39917
- const detectFilePath = path22.join(workingDir, cmd.detectFile);
40076
+ const detectFilePath = path21.join(workingDir, cmd.detectFile);
39918
40077
  if (!fs9.existsSync(detectFilePath)) {
39919
40078
  continue;
39920
40079
  }
@@ -39947,7 +40106,7 @@ async function discoverBuildCommands(workingDir, options) {
39947
40106
  const scope = options?.scope ?? "all";
39948
40107
  const changedFiles = options?.changedFiles ?? [];
39949
40108
  const _filesToCheck = filterByScope(workingDir, scope, changedFiles);
39950
- const profileResult = await _internals11.discoverBuildCommandsFromProfiles(workingDir);
40109
+ const profileResult = await _internals10.discoverBuildCommandsFromProfiles(workingDir);
39951
40110
  const profileCommands = profileResult.commands;
39952
40111
  const profileSkipped = profileResult.skipped;
39953
40112
  const coveredEcosystems = new Set;
@@ -40010,7 +40169,7 @@ function clearToolchainCache() {
40010
40169
  function getEcosystems() {
40011
40170
  return ECOSYSTEMS.map((e) => e.ecosystem);
40012
40171
  }
40013
- var ECOSYSTEMS, PROFILE_TO_ECOSYSTEM_NAMES, toolchainCache, _internals11, build_discovery;
40172
+ var ECOSYSTEMS, PROFILE_TO_ECOSYSTEM_NAMES, toolchainCache, _internals10, build_discovery;
40014
40173
  var init_discovery = __esm(() => {
40015
40174
  init_dist();
40016
40175
  init_detector();
@@ -40128,7 +40287,7 @@ var init_discovery = __esm(() => {
40128
40287
  php: ["php-composer"]
40129
40288
  };
40130
40289
  toolchainCache = new Map;
40131
- _internals11 = {
40290
+ _internals10 = {
40132
40291
  isCommandAvailable,
40133
40292
  discoverBuildCommandsFromProfiles,
40134
40293
  discoverBuildCommands,
@@ -40154,7 +40313,7 @@ var init_discovery = __esm(() => {
40154
40313
 
40155
40314
  // src/services/tool-doctor.ts
40156
40315
  import * as fs10 from "fs";
40157
- import * as path23 from "path";
40316
+ import * as path22 from "path";
40158
40317
  function extractRegisteredToolKeys(indexPath) {
40159
40318
  const registeredKeys = new Set;
40160
40319
  try {
@@ -40209,8 +40368,8 @@ function checkBinaryReadiness() {
40209
40368
  }
40210
40369
  function runToolDoctor(_directory, pluginRoot) {
40211
40370
  const findings = [];
40212
- const resolvedPluginRoot = pluginRoot ?? path23.resolve(import.meta.dir, "..", "..");
40213
- const indexPath = path23.join(resolvedPluginRoot, "src", "index.ts");
40371
+ const resolvedPluginRoot = pluginRoot ?? path22.resolve(import.meta.dir, "..", "..");
40372
+ const indexPath = path22.join(resolvedPluginRoot, "src", "index.ts");
40214
40373
  if (!fs10.existsSync(indexPath)) {
40215
40374
  return {
40216
40375
  findings: [
@@ -40380,7 +40539,7 @@ var exports_evidence_summary_service = {};
40380
40539
  __export(exports_evidence_summary_service, {
40381
40540
  isAutoSummaryEnabled: () => isAutoSummaryEnabled,
40382
40541
  buildEvidenceSummary: () => buildEvidenceSummary,
40383
- _internals: () => _internals12,
40542
+ _internals: () => _internals11,
40384
40543
  REQUIRED_EVIDENCE_TYPES: () => REQUIRED_EVIDENCE_TYPES,
40385
40544
  EVIDENCE_SUMMARY_VERSION: () => EVIDENCE_SUMMARY_VERSION
40386
40545
  });
@@ -40418,14 +40577,14 @@ function getTaskStatus(task, bundle) {
40418
40577
  if (task?.status) {
40419
40578
  return task.status;
40420
40579
  }
40421
- const entries = _internals12.normalizeBundleEntries(bundle);
40580
+ const entries = _internals11.normalizeBundleEntries(bundle);
40422
40581
  if (entries.length > 0) {
40423
40582
  return "completed";
40424
40583
  }
40425
40584
  return "pending";
40426
40585
  }
40427
40586
  function isEvidenceComplete(bundle) {
40428
- const entries = _internals12.normalizeBundleEntries(bundle);
40587
+ const entries = _internals11.normalizeBundleEntries(bundle);
40429
40588
  if (entries.length === 0) {
40430
40589
  return {
40431
40590
  isComplete: false,
@@ -40461,10 +40620,10 @@ async function buildTaskSummary(directory, task, taskId) {
40461
40620
  const result = await loadEvidence(directory, taskId);
40462
40621
  const bundle = result.status === "found" ? result.bundle : null;
40463
40622
  const phase = task?.phase ?? 0;
40464
- const status = _internals12.getTaskStatus(task, bundle);
40465
- const evidenceCheck = _internals12.isEvidenceComplete(bundle);
40466
- const blockers = _internals12.getTaskBlockers(task, evidenceCheck, status);
40467
- const entries = _internals12.normalizeBundleEntries(bundle);
40623
+ const status = _internals11.getTaskStatus(task, bundle);
40624
+ const evidenceCheck = _internals11.isEvidenceComplete(bundle);
40625
+ const blockers = _internals11.getTaskBlockers(task, evidenceCheck, status);
40626
+ const entries = _internals11.normalizeBundleEntries(bundle);
40468
40627
  const hasReview = entries.some((e) => e.type === "review");
40469
40628
  const hasTest = entries.some((e) => e.type === "test");
40470
40629
  const hasApproval = entries.some((e) => e.type === "approval");
@@ -40493,12 +40652,12 @@ async function buildPhaseSummary(directory, phase) {
40493
40652
  const taskSummaries = [];
40494
40653
  const _taskMap = new Map(phase.tasks.map((t) => [t.id, t]));
40495
40654
  for (const task of phase.tasks) {
40496
- const summary = await _internals12.buildTaskSummary(directory, task, task.id);
40655
+ const summary = await _internals11.buildTaskSummary(directory, task, task.id);
40497
40656
  taskSummaries.push(summary);
40498
40657
  }
40499
40658
  const extraTaskIds = taskIds.filter((id) => !phaseTaskIds.has(id));
40500
40659
  for (const taskId of extraTaskIds) {
40501
- const summary = await _internals12.buildTaskSummary(directory, undefined, taskId);
40660
+ const summary = await _internals11.buildTaskSummary(directory, undefined, taskId);
40502
40661
  if (summary.phase === phase.id) {
40503
40662
  taskSummaries.push(summary);
40504
40663
  }
@@ -40599,7 +40758,7 @@ async function buildEvidenceSummary(directory, currentPhase) {
40599
40758
  let totalTasks = 0;
40600
40759
  let completedTasks = 0;
40601
40760
  for (const phase of phasesToProcess) {
40602
- const summary = await _internals12.buildPhaseSummary(directory, phase);
40761
+ const summary = await _internals11.buildPhaseSummary(directory, phase);
40603
40762
  phaseSummaries.push(summary);
40604
40763
  totalTasks += summary.totalTasks;
40605
40764
  completedTasks += summary.completedTasks;
@@ -40621,7 +40780,7 @@ async function buildEvidenceSummary(directory, currentPhase) {
40621
40780
  overallBlockers,
40622
40781
  summaryText: ""
40623
40782
  };
40624
- artifact.summaryText = _internals12.generateSummaryText(artifact);
40783
+ artifact.summaryText = _internals11.generateSummaryText(artifact);
40625
40784
  log("[EvidenceSummary] Summary built", {
40626
40785
  phases: phaseSummaries.length,
40627
40786
  totalTasks,
@@ -40640,7 +40799,7 @@ function isAutoSummaryEnabled(automationConfig) {
40640
40799
  }
40641
40800
  return automationConfig.capabilities?.evidence_auto_summaries === true;
40642
40801
  }
40643
- var VALID_EVIDENCE_TYPES2, REQUIRED_EVIDENCE_TYPES, EVIDENCE_SUMMARY_VERSION = "1.0.0", _internals12;
40802
+ var VALID_EVIDENCE_TYPES2, REQUIRED_EVIDENCE_TYPES, EVIDENCE_SUMMARY_VERSION = "1.0.0", _internals11;
40644
40803
  var init_evidence_summary_service = __esm(() => {
40645
40804
  init_manager2();
40646
40805
  init_manager();
@@ -40654,7 +40813,7 @@ var init_evidence_summary_service = __esm(() => {
40654
40813
  "retrospective"
40655
40814
  ]);
40656
40815
  REQUIRED_EVIDENCE_TYPES = ["review", "test"];
40657
- _internals12 = {
40816
+ _internals11 = {
40658
40817
  buildEvidenceSummary,
40659
40818
  isAutoSummaryEnabled,
40660
40819
  normalizeBundleEntries,
@@ -40901,12 +41060,12 @@ var init_export = __esm(() => {
40901
41060
 
40902
41061
  // src/full-auto/state.ts
40903
41062
  import * as fs11 from "fs";
40904
- import * as path24 from "path";
41063
+ import * as path23 from "path";
40905
41064
  function nowISO() {
40906
41065
  return new Date().toISOString();
40907
41066
  }
40908
41067
  function ensureSwarmDir(directory) {
40909
- const swarmDir = path24.resolve(directory, ".swarm");
41068
+ const swarmDir = path23.resolve(directory, ".swarm");
40910
41069
  if (!fs11.existsSync(swarmDir)) {
40911
41070
  fs11.mkdirSync(swarmDir, { recursive: true });
40912
41071
  }
@@ -41257,7 +41416,7 @@ function extractCurrentPhaseFromPlan2(plan) {
41257
41416
  if (!plan) {
41258
41417
  return { currentPhase: null, currentTask: null, incompleteTasks: [] };
41259
41418
  }
41260
- if (!_internals13.validatePlanPhases(plan)) {
41419
+ if (!_internals12.validatePlanPhases(plan)) {
41261
41420
  return { currentPhase: null, currentTask: null, incompleteTasks: [] };
41262
41421
  }
41263
41422
  let currentPhase = null;
@@ -41399,9 +41558,9 @@ function extractPhaseMetrics(content) {
41399
41558
  async function getHandoffData(directory) {
41400
41559
  const now = new Date().toISOString();
41401
41560
  const sessionContent = await readSwarmFileAsync(directory, "session/state.json");
41402
- const sessionState = _internals13.parseSessionState(sessionContent);
41561
+ const sessionState = _internals12.parseSessionState(sessionContent);
41403
41562
  const plan = await loadPlanJsonOnly(directory);
41404
- const planInfo = _internals13.extractCurrentPhaseFromPlan(plan);
41563
+ const planInfo = _internals12.extractCurrentPhaseFromPlan(plan);
41405
41564
  if (!plan) {
41406
41565
  const planMdContent = await readSwarmFileAsync(directory, "plan.md");
41407
41566
  if (planMdContent) {
@@ -41420,8 +41579,8 @@ async function getHandoffData(directory) {
41420
41579
  }
41421
41580
  }
41422
41581
  const contextContent = await readSwarmFileAsync(directory, "context.md");
41423
- const recentDecisions = _internals13.extractDecisions(contextContent);
41424
- const rawPhaseMetrics = _internals13.extractPhaseMetrics(contextContent);
41582
+ const recentDecisions = _internals12.extractDecisions(contextContent);
41583
+ const rawPhaseMetrics = _internals12.extractPhaseMetrics(contextContent);
41425
41584
  const phaseMetrics = sanitizeString(rawPhaseMetrics, 1000);
41426
41585
  let delegationState = null;
41427
41586
  if (sessionState?.delegationState) {
@@ -41585,13 +41744,13 @@ ${lines.join(`
41585
41744
  `)}
41586
41745
  \`\`\``;
41587
41746
  }
41588
- var RTL_OVERRIDE_PATTERN, MAX_TASK_ID_LENGTH = 100, MAX_DECISION_LENGTH = 500, MAX_INCOMPLETE_TASKS = 20, _internals13;
41747
+ var RTL_OVERRIDE_PATTERN, MAX_TASK_ID_LENGTH = 100, MAX_DECISION_LENGTH = 500, MAX_INCOMPLETE_TASKS = 20, _internals12;
41589
41748
  var init_handoff_service = __esm(() => {
41590
41749
  init_utils2();
41591
41750
  init_manager();
41592
41751
  init_utils();
41593
41752
  RTL_OVERRIDE_PATTERN = /[\u202e\u202d\u202c\u200f]/g;
41594
- _internals13 = {
41753
+ _internals12 = {
41595
41754
  getHandoffData,
41596
41755
  formatHandoffMarkdown,
41597
41756
  formatContinuationPrompt,
@@ -41605,24 +41764,166 @@ var init_handoff_service = __esm(() => {
41605
41764
  };
41606
41765
  });
41607
41766
 
41767
+ // src/session/snapshot-writer.ts
41768
+ import { mkdirSync as mkdirSync10, renameSync as renameSync6 } from "fs";
41769
+ import * as path24 from "path";
41770
+ function serializeAgentSession(s) {
41771
+ const gateLog = {};
41772
+ const rawGateLog = s.gateLog ?? new Map;
41773
+ for (const [taskId, gates] of rawGateLog) {
41774
+ gateLog[taskId] = Array.from(gates ?? []);
41775
+ }
41776
+ const reviewerCallCount = {};
41777
+ const rawReviewerCallCount = s.reviewerCallCount ?? new Map;
41778
+ for (const [phase, count] of rawReviewerCallCount) {
41779
+ reviewerCallCount[String(phase)] = count;
41780
+ }
41781
+ const partialGateWarningsIssuedForTask = Array.from(s.partialGateWarningsIssuedForTask ?? new Set);
41782
+ const catastrophicPhaseWarnings = Array.from(s.catastrophicPhaseWarnings ?? new Set);
41783
+ const phaseAgentsDispatched = Array.from(s.phaseAgentsDispatched ?? new Set);
41784
+ const lastCompletedPhaseAgentsDispatched = Array.from(s.lastCompletedPhaseAgentsDispatched ?? new Set);
41785
+ const windows = {};
41786
+ const rawWindows = s.windows ?? {};
41787
+ for (const [key, win] of Object.entries(rawWindows)) {
41788
+ windows[key] = {
41789
+ id: win.id,
41790
+ agentName: win.agentName,
41791
+ startedAtMs: win.startedAtMs,
41792
+ toolCalls: win.toolCalls,
41793
+ consecutiveErrors: win.consecutiveErrors,
41794
+ hardLimitHit: win.hardLimitHit,
41795
+ lastSuccessTimeMs: win.lastSuccessTimeMs,
41796
+ recentToolCalls: win.recentToolCalls,
41797
+ warningIssued: win.warningIssued,
41798
+ warningReason: win.warningReason,
41799
+ transientRetryCount: win.transientRetryCount ?? 0
41800
+ };
41801
+ }
41802
+ return {
41803
+ agentName: s.agentName,
41804
+ lastToolCallTime: s.lastToolCallTime,
41805
+ lastAgentEventTime: s.lastAgentEventTime,
41806
+ delegationActive: s.delegationActive,
41807
+ activeInvocationId: s.activeInvocationId,
41808
+ lastInvocationIdByAgent: s.lastInvocationIdByAgent ?? {},
41809
+ windows,
41810
+ lastCompactionHint: s.lastCompactionHint ?? 0,
41811
+ architectWriteCount: s.architectWriteCount ?? 0,
41812
+ lastCoderDelegationTaskId: s.lastCoderDelegationTaskId ?? null,
41813
+ currentTaskId: s.currentTaskId ?? null,
41814
+ turboMode: s.turboMode ?? false,
41815
+ gateLog,
41816
+ reviewerCallCount,
41817
+ lastGateFailure: s.lastGateFailure ?? null,
41818
+ partialGateWarningsIssuedForTask,
41819
+ selfFixAttempted: s.selfFixAttempted ?? false,
41820
+ selfCodingWarnedAtCount: s.selfCodingWarnedAtCount ?? 0,
41821
+ catastrophicPhaseWarnings,
41822
+ lastPhaseCompleteTimestamp: s.lastPhaseCompleteTimestamp ?? 0,
41823
+ lastPhaseCompletePhase: s.lastPhaseCompletePhase ?? 0,
41824
+ phaseAgentsDispatched,
41825
+ lastCompletedPhaseAgentsDispatched,
41826
+ qaSkipCount: s.qaSkipCount ?? 0,
41827
+ qaSkipTaskIds: s.qaSkipTaskIds ?? [],
41828
+ pendingAdvisoryMessages: s.pendingAdvisoryMessages ?? [],
41829
+ taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map),
41830
+ ...s.scopeViolationDetected !== undefined && {
41831
+ scopeViolationDetected: s.scopeViolationDetected
41832
+ },
41833
+ model_fallback_index: s.model_fallback_index ?? 0,
41834
+ modelFallbackExhausted: s.modelFallbackExhausted ?? false,
41835
+ coderRevisions: s.coderRevisions ?? 0,
41836
+ revisionLimitHit: s.revisionLimitHit ?? false,
41837
+ fullAutoMode: s.fullAutoMode ?? false,
41838
+ fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
41839
+ fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
41840
+ fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
41841
+ sessionRehydratedAt: s.sessionRehydratedAt ?? 0
41842
+ };
41843
+ }
41844
+ async function writeSnapshot(directory, state) {
41845
+ try {
41846
+ const snapshot = {
41847
+ version: 2,
41848
+ writtenAt: Date.now(),
41849
+ toolAggregates: Object.fromEntries(state.toolAggregates),
41850
+ activeAgent: Object.fromEntries(state.activeAgent),
41851
+ delegationChains: Object.fromEntries(state.delegationChains),
41852
+ agentSessions: {}
41853
+ };
41854
+ for (const [sessionId, sessionState] of state.agentSessions) {
41855
+ snapshot.agentSessions[sessionId] = serializeAgentSession(sessionState);
41856
+ }
41857
+ const content = JSON.stringify(snapshot, null, 2);
41858
+ const resolvedPath = validateSwarmPath(directory, "session/state.json");
41859
+ const dir = path24.dirname(resolvedPath);
41860
+ mkdirSync10(dir, { recursive: true });
41861
+ const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
41862
+ await bunWrite(tempPath, content);
41863
+ renameSync6(tempPath, resolvedPath);
41864
+ } catch (error93) {
41865
+ log("[snapshot-writer] write failed", {
41866
+ error: error93 instanceof Error ? error93.message : String(error93)
41867
+ });
41868
+ }
41869
+ }
41870
+ function createSnapshotWriterHook(directory) {
41871
+ return (_input, _output) => {
41872
+ _writeInFlight = _writeInFlight.then(() => _internals13.writeSnapshot(directory, swarmState), () => _internals13.writeSnapshot(directory, swarmState));
41873
+ return _writeInFlight;
41874
+ };
41875
+ }
41876
+ async function flushPendingSnapshot(directory) {
41877
+ _writeInFlight = _writeInFlight.then(() => _internals13.writeSnapshot(directory, swarmState), () => _internals13.writeSnapshot(directory, swarmState));
41878
+ await _writeInFlight;
41879
+ }
41880
+ var _writeInFlight, _internals13;
41881
+ var init_snapshot_writer = __esm(() => {
41882
+ init_utils2();
41883
+ init_state();
41884
+ init_utils();
41885
+ init_bun_compat();
41886
+ _writeInFlight = Promise.resolve();
41887
+ _internals13 = {
41888
+ writeSnapshot,
41889
+ createSnapshotWriterHook,
41890
+ flushPendingSnapshot
41891
+ };
41892
+ });
41893
+
41608
41894
  // src/commands/handoff.ts
41609
41895
  import crypto4 from "crypto";
41610
- import { renameSync as renameSync7 } from "fs";
41896
+ import { renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
41611
41897
  async function handleHandoffCommand(directory, _args) {
41612
41898
  const handoffData = await getHandoffData(directory);
41613
41899
  const markdown = formatHandoffMarkdown(handoffData);
41614
- const resolvedPath = validateSwarmPath(directory, "handoff.md");
41615
- const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
41616
- await bunWrite(tempPath, markdown);
41617
- renameSync7(tempPath, resolvedPath);
41618
- const continuationPrompt = formatContinuationPrompt(handoffData);
41619
- const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
41620
- const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
41621
- await bunWrite(promptTempPath, continuationPrompt);
41622
- renameSync7(promptTempPath, promptPath);
41623
- await writeSnapshot(directory, swarmState);
41624
- await flushPendingSnapshot(directory);
41625
- return `## Handoff Brief Written
41900
+ try {
41901
+ const resolvedPath = validateSwarmPath(directory, "handoff.md");
41902
+ const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
41903
+ await bunWrite(tempPath, markdown);
41904
+ try {
41905
+ renameSync7(tempPath, resolvedPath);
41906
+ } catch (renameErr) {
41907
+ try {
41908
+ unlinkSync4(tempPath);
41909
+ } catch {}
41910
+ throw renameErr;
41911
+ }
41912
+ const continuationPrompt = formatContinuationPrompt(handoffData);
41913
+ const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
41914
+ const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
41915
+ await bunWrite(promptTempPath, continuationPrompt);
41916
+ try {
41917
+ renameSync7(promptTempPath, promptPath);
41918
+ } catch (renameErr) {
41919
+ try {
41920
+ unlinkSync4(promptTempPath);
41921
+ } catch {}
41922
+ throw renameErr;
41923
+ }
41924
+ await writeSnapshot(directory, swarmState);
41925
+ await flushPendingSnapshot(directory);
41926
+ return `## Handoff Brief Written
41626
41927
 
41627
41928
  Brief written to \`.swarm/handoff.md\`.
41628
41929
  Continuation prompt written to \`.swarm/handoff-prompt.md\`.
@@ -41636,6 +41937,16 @@ ${markdown}
41636
41937
  Copy and paste the block below into your next session to resume cleanly:
41637
41938
 
41638
41939
  ${continuationPrompt}`;
41940
+ } catch (err) {
41941
+ const errMsg = err instanceof Error ? err.message : String(err);
41942
+ return `## Handoff Generated (file write failed)
41943
+
41944
+ Handoff data was generated but could not be written to disk: ${errMsg}
41945
+
41946
+ The handoff content is included below for manual copy:
41947
+
41948
+ ${markdown}`;
41949
+ }
41639
41950
  }
41640
41951
  var init_handoff = __esm(() => {
41641
41952
  init_utils2();
@@ -47722,7 +48033,19 @@ async function handleSimulateCommand(directory, args) {
47722
48033
  options.minCommits = val;
47723
48034
  }
47724
48035
  }
47725
- const darkMatterPairs = await detectDarkMatter(directory, options);
48036
+ let darkMatterPairs;
48037
+ try {
48038
+ darkMatterPairs = await _internals9.detectDarkMatter(directory, options);
48039
+ } catch (err) {
48040
+ const errMsg = err instanceof Error ? err.message : String(err);
48041
+ return `## Simulate Report
48042
+
48043
+ ### Error
48044
+
48045
+ Error analyzing git history: ${errMsg}
48046
+
48047
+ Ensure this is a git repository with commit history.`;
48048
+ }
47726
48049
  const reportLines = [
47727
48050
  "# Simulate Report",
47728
48051
  "",
@@ -47740,15 +48063,21 @@ async function handleSimulateCommand(directory, args) {
47740
48063
  ];
47741
48064
  const report = reportLines.filter(Boolean).join(`
47742
48065
  `);
47743
- const fs22 = await import("fs/promises");
47744
- const path37 = await import("path");
47745
- const reportPath = path37.join(directory, ".swarm", "simulate-report.md");
47746
- await fs22.mkdir(path37.dirname(reportPath), { recursive: true });
47747
- await fs22.writeFile(reportPath, report, "utf-8");
48066
+ try {
48067
+ const fs22 = await import("fs/promises");
48068
+ const path37 = await import("path");
48069
+ const reportPath = path37.join(directory, ".swarm", "simulate-report.md");
48070
+ await fs22.mkdir(path37.dirname(reportPath), { recursive: true });
48071
+ await fs22.writeFile(reportPath, report, "utf-8");
48072
+ } catch (err) {
48073
+ const writeErr = err instanceof Error ? err.message : String(err);
48074
+ warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
48075
+ }
47748
48076
  return `${darkMatterPairs.length} hidden coupling pairs detected`;
47749
48077
  }
47750
48078
  var init_simulate = __esm(() => {
47751
48079
  init_co_change_analyzer();
48080
+ init_utils();
47752
48081
  });
47753
48082
 
47754
48083
  // src/commands/specify.ts
@@ -48195,12 +48524,6 @@ function buildHelpText() {
48195
48524
  return lines.join(`
48196
48525
  `);
48197
48526
  }
48198
- function getHelpText() {
48199
- if (!_helpText) {
48200
- _helpText = buildHelpText();
48201
- }
48202
- return _helpText;
48203
- }
48204
48527
  function createSwarmCommandHandler(directory, agents) {
48205
48528
  return async (input, output) => {
48206
48529
  if (input.command !== "swarm" && !input.command.startsWith("swarm-")) {
@@ -48226,7 +48549,22 @@ function createSwarmCommandHandler(directory, agents) {
48226
48549
  let text;
48227
48550
  const resolved = resolveCommand(tokens);
48228
48551
  if (!resolved) {
48229
- text = getHelpText();
48552
+ if (tokens.length === 0) {
48553
+ text = buildHelpText();
48554
+ } else {
48555
+ const attemptedCommand = tokens[0] || "";
48556
+ const MAX_DISPLAY = 100;
48557
+ const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
48558
+ const similar = _internals19.findSimilarCommands(attemptedCommand);
48559
+ const header = `Command \`/swarm ${displayCommand}\` not found.`;
48560
+ const suggestions = similar.length > 0 ? `Did you mean:
48561
+ ${similar.map((cmd) => ` \u2022 /swarm ${cmd}`).join(`
48562
+ `)}` : "";
48563
+ const footer = "Run `/swarm help` for all commands.";
48564
+ text = [header, suggestions, footer].filter(Boolean).join(`
48565
+
48566
+ `);
48567
+ }
48230
48568
  } else {
48231
48569
  try {
48232
48570
  text = await resolved.entry.handler({
@@ -48258,7 +48596,6 @@ ${text}`;
48258
48596
  ];
48259
48597
  };
48260
48598
  }
48261
- var _helpText;
48262
48599
  var init_commands = __esm(() => {
48263
48600
  init_registry();
48264
48601
  init_acknowledge_spec_drift();
@@ -48318,14 +48655,38 @@ function levenshteinDistance(a, b) {
48318
48655
  }
48319
48656
  function findSimilarCommands(query) {
48320
48657
  const q = query.toLowerCase();
48321
- const scored = VALID_COMMANDS.filter((cmd) => {
48322
- if (cmd.includes(" ") || cmd.includes("-"))
48323
- return false;
48324
- return cmd.toLowerCase().includes(q) || q.includes(cmd.toLowerCase());
48325
- }).map((cmd) => ({
48326
- cmd,
48327
- score: cmd.length < q.length ? q.length - cmd.length : _internals19.levenshteinDistance(q, cmd)
48328
- }));
48658
+ if (q.length > 500) {
48659
+ return [];
48660
+ }
48661
+ const scored = VALID_COMMANDS.map((cmd) => {
48662
+ const cmdLower = cmd.toLowerCase();
48663
+ const fullScore = _internals19.levenshteinDistance(q, cmdLower);
48664
+ let tokenScore = Infinity;
48665
+ if (cmd.includes(" ") || cmd.includes("-")) {
48666
+ const qTokens = q.split(/[\s-]+/);
48667
+ const cmdTokens = cmdLower.split(/[\s-]+/);
48668
+ let totalTokenDist = 0;
48669
+ for (const qt of qTokens) {
48670
+ if (qt.length === 0)
48671
+ continue;
48672
+ let minDist = Infinity;
48673
+ for (const ct of cmdTokens) {
48674
+ if (ct.length === 0)
48675
+ continue;
48676
+ const dist = _internals19.levenshteinDistance(qt, ct);
48677
+ if (dist < minDist)
48678
+ minDist = dist;
48679
+ }
48680
+ totalTokenDist += minDist;
48681
+ }
48682
+ tokenScore = totalTokenDist;
48683
+ }
48684
+ const dashStrippedQ = q.replace(/-/g, "");
48685
+ const dashStrippedCmd = cmdLower.replace(/-/g, "");
48686
+ const dashScore = _internals19.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
48687
+ const score = Math.min(fullScore, tokenScore, dashScore);
48688
+ return { cmd, score };
48689
+ });
48329
48690
  scored.sort((a, b) => a.score - b.score);
48330
48691
  return scored.slice(0, 3).map((s) => s.cmd);
48331
48692
  }