opencode-swarm 7.9.0 → 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.9.0",
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",
@@ -34490,6 +34490,205 @@ function resetToRemoteBranch(cwd, options) {
34490
34490
  };
34491
34491
  }
34492
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
+ }
34493
34692
  var GIT_TIMEOUT_MS2 = 30000, _internals6;
34494
34693
  var init_branch = __esm(() => {
34495
34694
  init_logger();
@@ -34497,10 +34696,81 @@ var init_branch = __esm(() => {
34497
34696
  gitExec: gitExec2,
34498
34697
  detectDefaultRemoteBranch,
34499
34698
  getDefaultBaseBranch,
34500
- resetToRemoteBranch
34699
+ resetToRemoteBranch,
34700
+ resetToMainAfterMerge
34501
34701
  };
34502
34702
  });
34503
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
+
34504
34774
  // src/hooks/knowledge-store.ts
34505
34775
  import { existsSync as existsSync7 } from "fs";
34506
34776
  import { appendFile as appendFile2, mkdir as mkdir2, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
@@ -34668,78 +34938,9 @@ var init_knowledge_store = __esm(() => {
34668
34938
  import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
34669
34939
  });
34670
34940
 
34671
- // src/hooks/knowledge-reader.ts
34672
- import { existsSync as existsSync8 } from "fs";
34673
- import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
34674
- import * as path11 from "path";
34675
- async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
34676
- const shownFile = path11.join(directory, ".swarm", ".knowledge-shown.json");
34677
- try {
34678
- if (!existsSync8(shownFile)) {
34679
- return;
34680
- }
34681
- const content = await readFile4(shownFile, "utf-8");
34682
- const shownData = JSON.parse(content);
34683
- const shownIds = shownData[phaseInfo];
34684
- if (!shownIds || shownIds.length === 0) {
34685
- return;
34686
- }
34687
- const swarmPath = resolveSwarmKnowledgePath(directory);
34688
- const entries = await readKnowledge(swarmPath);
34689
- let updated = false;
34690
- const foundInSwarm = new Set;
34691
- for (const entry of entries) {
34692
- if (shownIds.includes(entry.id)) {
34693
- entry.retrieval_outcomes.applied_count++;
34694
- if (phaseSucceeded) {
34695
- entry.retrieval_outcomes.succeeded_after_count++;
34696
- } else {
34697
- entry.retrieval_outcomes.failed_after_count++;
34698
- }
34699
- updated = true;
34700
- foundInSwarm.add(entry.id);
34701
- }
34702
- }
34703
- if (updated) {
34704
- await rewriteKnowledge(swarmPath, entries);
34705
- }
34706
- const remainingIds = shownIds.filter((id) => !foundInSwarm.has(id));
34707
- if (remainingIds.length === 0) {
34708
- delete shownData[phaseInfo];
34709
- await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
34710
- return;
34711
- }
34712
- const hivePath = resolveHiveKnowledgePath();
34713
- const hiveEntries = await readKnowledge(hivePath);
34714
- let hiveUpdated = false;
34715
- for (const entry of hiveEntries) {
34716
- if (remainingIds.includes(entry.id)) {
34717
- entry.retrieval_outcomes.applied_count++;
34718
- if (phaseSucceeded) {
34719
- entry.retrieval_outcomes.succeeded_after_count++;
34720
- } else {
34721
- entry.retrieval_outcomes.failed_after_count++;
34722
- }
34723
- hiveUpdated = true;
34724
- }
34725
- }
34726
- if (hiveUpdated) {
34727
- await rewriteKnowledge(hivePath, hiveEntries);
34728
- }
34729
- delete shownData[phaseInfo];
34730
- await writeFile4(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
34731
- } catch {
34732
- warn("[swarm] Knowledge: failed to update retrieval outcomes");
34733
- }
34734
- }
34735
- var init_knowledge_reader = __esm(() => {
34736
- init_logger();
34737
- init_knowledge_store();
34738
- });
34739
-
34740
34941
  // src/hooks/knowledge-validator.ts
34741
- import { appendFile as appendFile3, mkdir as mkdir4, writeFile as writeFile5 } from "fs/promises";
34742
- 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";
34743
34944
  function normalizeText(text) {
34744
34945
  return text.normalize("NFKC").toLowerCase().replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
34745
34946
  }
@@ -34893,11 +35094,11 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
34893
35094
  return;
34894
35095
  }
34895
35096
  const sanitizedReason = reason.slice(0, 500).replace(/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f\x0d]/g, "");
34896
- const knowledgePath = path12.join(directory, ".swarm", "knowledge.jsonl");
34897
- const quarantinePath = path12.join(directory, ".swarm", "knowledge-quarantined.jsonl");
34898
- const rejectedPath = path12.join(directory, ".swarm", "knowledge-rejected.jsonl");
34899
- const swarmDir = path12.join(directory, ".swarm");
34900
- 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 });
34901
35102
  let release;
34902
35103
  try {
34903
35104
  release = await import_proper_lockfile4.default.lock(swarmDir, {
@@ -34918,7 +35119,7 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
34918
35119
  const jsonlContent = remaining.length > 0 ? `${remaining.map((e) => JSON.stringify(e)).join(`
34919
35120
  `)}
34920
35121
  ` : "";
34921
- await writeFile5(knowledgePath, jsonlContent, "utf-8");
35122
+ await writeFile4(knowledgePath, jsonlContent, "utf-8");
34922
35123
  await appendFile3(quarantinePath, `${JSON.stringify(quarantined)}
34923
35124
  `, "utf-8");
34924
35125
  const quarantinedEntries = await readKnowledge(quarantinePath);
@@ -34927,7 +35128,7 @@ async function quarantineEntry(directory, entryId, reason, reportedBy) {
34927
35128
  const capContent = trimmed.length > 0 ? `${trimmed.map((e) => JSON.stringify(e)).join(`
34928
35129
  `)}
34929
35130
  ` : "";
34930
- await writeFile5(quarantinePath, capContent, "utf-8");
35131
+ await writeFile4(quarantinePath, capContent, "utf-8");
34931
35132
  }
34932
35133
  const rejectedRecord = {
34933
35134
  id: entryId,
@@ -34953,11 +35154,11 @@ async function restoreEntry(directory, entryId) {
34953
35154
  warn("[knowledge-validator] restoreEntry: invalid entryId rejected");
34954
35155
  return;
34955
35156
  }
34956
- const knowledgePath = path12.join(directory, ".swarm", "knowledge.jsonl");
34957
- const quarantinePath = path12.join(directory, ".swarm", "knowledge-quarantined.jsonl");
34958
- const rejectedPath = path12.join(directory, ".swarm", "knowledge-rejected.jsonl");
34959
- const swarmDir = path12.join(directory, ".swarm");
34960
- 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 });
34961
35162
  let release;
34962
35163
  try {
34963
35164
  release = await import_proper_lockfile4.default.lock(swarmDir, {
@@ -34973,7 +35174,7 @@ async function restoreEntry(directory, entryId) {
34973
35174
  const jsonlContent = remaining.length > 0 ? `${remaining.map((e) => JSON.stringify(e)).join(`
34974
35175
  `)}
34975
35176
  ` : "";
34976
- await writeFile5(quarantinePath, jsonlContent, "utf-8");
35177
+ await writeFile4(quarantinePath, jsonlContent, "utf-8");
34977
35178
  await appendFile3(knowledgePath, `${JSON.stringify(original)}
34978
35179
  `, "utf-8");
34979
35180
  const rejectedEntries = await readKnowledge(rejectedPath);
@@ -34981,7 +35182,7 @@ async function restoreEntry(directory, entryId) {
34981
35182
  const rejectedContent = filtered.length > 0 ? `${filtered.map((e) => JSON.stringify(e)).join(`
34982
35183
  `)}
34983
35184
  ` : "";
34984
- await writeFile5(rejectedPath, rejectedContent, "utf-8");
35185
+ await writeFile4(rejectedPath, rejectedContent, "utf-8");
34985
35186
  } finally {
34986
35187
  if (release) {
34987
35188
  await release();
@@ -35096,6 +35297,321 @@ var init_knowledge_validator = __esm(() => {
35096
35297
  ];
35097
35298
  });
35098
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
+
35099
35615
  // src/hooks/knowledge-curator.ts
35100
35616
  function pruneSeenRetroSections() {
35101
35617
  const cutoff = Date.now() - 86400000;
@@ -35431,133 +35947,6 @@ var init_knowledge_curator = __esm(() => {
35431
35947
  };
35432
35948
  });
35433
35949
 
35434
- // src/session/snapshot-writer.ts
35435
- import { mkdirSync as mkdirSync7, renameSync as renameSync5 } from "fs";
35436
- import * as path13 from "path";
35437
- function serializeAgentSession(s) {
35438
- const gateLog = {};
35439
- const rawGateLog = s.gateLog ?? new Map;
35440
- for (const [taskId, gates] of rawGateLog) {
35441
- gateLog[taskId] = Array.from(gates ?? []);
35442
- }
35443
- const reviewerCallCount = {};
35444
- const rawReviewerCallCount = s.reviewerCallCount ?? new Map;
35445
- for (const [phase, count] of rawReviewerCallCount) {
35446
- reviewerCallCount[String(phase)] = count;
35447
- }
35448
- const partialGateWarningsIssuedForTask = Array.from(s.partialGateWarningsIssuedForTask ?? new Set);
35449
- const catastrophicPhaseWarnings = Array.from(s.catastrophicPhaseWarnings ?? new Set);
35450
- const phaseAgentsDispatched = Array.from(s.phaseAgentsDispatched ?? new Set);
35451
- const lastCompletedPhaseAgentsDispatched = Array.from(s.lastCompletedPhaseAgentsDispatched ?? new Set);
35452
- const windows = {};
35453
- const rawWindows = s.windows ?? {};
35454
- for (const [key, win] of Object.entries(rawWindows)) {
35455
- windows[key] = {
35456
- id: win.id,
35457
- agentName: win.agentName,
35458
- startedAtMs: win.startedAtMs,
35459
- toolCalls: win.toolCalls,
35460
- consecutiveErrors: win.consecutiveErrors,
35461
- hardLimitHit: win.hardLimitHit,
35462
- lastSuccessTimeMs: win.lastSuccessTimeMs,
35463
- recentToolCalls: win.recentToolCalls,
35464
- warningIssued: win.warningIssued,
35465
- warningReason: win.warningReason,
35466
- transientRetryCount: win.transientRetryCount ?? 0
35467
- };
35468
- }
35469
- return {
35470
- agentName: s.agentName,
35471
- lastToolCallTime: s.lastToolCallTime,
35472
- lastAgentEventTime: s.lastAgentEventTime,
35473
- delegationActive: s.delegationActive,
35474
- activeInvocationId: s.activeInvocationId,
35475
- lastInvocationIdByAgent: s.lastInvocationIdByAgent ?? {},
35476
- windows,
35477
- lastCompactionHint: s.lastCompactionHint ?? 0,
35478
- architectWriteCount: s.architectWriteCount ?? 0,
35479
- lastCoderDelegationTaskId: s.lastCoderDelegationTaskId ?? null,
35480
- currentTaskId: s.currentTaskId ?? null,
35481
- turboMode: s.turboMode ?? false,
35482
- gateLog,
35483
- reviewerCallCount,
35484
- lastGateFailure: s.lastGateFailure ?? null,
35485
- partialGateWarningsIssuedForTask,
35486
- selfFixAttempted: s.selfFixAttempted ?? false,
35487
- selfCodingWarnedAtCount: s.selfCodingWarnedAtCount ?? 0,
35488
- catastrophicPhaseWarnings,
35489
- lastPhaseCompleteTimestamp: s.lastPhaseCompleteTimestamp ?? 0,
35490
- lastPhaseCompletePhase: s.lastPhaseCompletePhase ?? 0,
35491
- phaseAgentsDispatched,
35492
- lastCompletedPhaseAgentsDispatched,
35493
- qaSkipCount: s.qaSkipCount ?? 0,
35494
- qaSkipTaskIds: s.qaSkipTaskIds ?? [],
35495
- pendingAdvisoryMessages: s.pendingAdvisoryMessages ?? [],
35496
- taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map),
35497
- ...s.scopeViolationDetected !== undefined && {
35498
- scopeViolationDetected: s.scopeViolationDetected
35499
- },
35500
- model_fallback_index: s.model_fallback_index ?? 0,
35501
- modelFallbackExhausted: s.modelFallbackExhausted ?? false,
35502
- coderRevisions: s.coderRevisions ?? 0,
35503
- revisionLimitHit: s.revisionLimitHit ?? false,
35504
- fullAutoMode: s.fullAutoMode ?? false,
35505
- fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
35506
- fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
35507
- fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
35508
- sessionRehydratedAt: s.sessionRehydratedAt ?? 0
35509
- };
35510
- }
35511
- async function writeSnapshot(directory, state) {
35512
- try {
35513
- const snapshot = {
35514
- version: 2,
35515
- writtenAt: Date.now(),
35516
- toolAggregates: Object.fromEntries(state.toolAggregates),
35517
- activeAgent: Object.fromEntries(state.activeAgent),
35518
- delegationChains: Object.fromEntries(state.delegationChains),
35519
- agentSessions: {}
35520
- };
35521
- for (const [sessionId, sessionState] of state.agentSessions) {
35522
- snapshot.agentSessions[sessionId] = serializeAgentSession(sessionState);
35523
- }
35524
- const content = JSON.stringify(snapshot, null, 2);
35525
- const resolvedPath = validateSwarmPath(directory, "session/state.json");
35526
- const dir = path13.dirname(resolvedPath);
35527
- mkdirSync7(dir, { recursive: true });
35528
- const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
35529
- await bunWrite(tempPath, content);
35530
- renameSync5(tempPath, resolvedPath);
35531
- } catch (error93) {
35532
- log("[snapshot-writer] write failed", {
35533
- error: error93 instanceof Error ? error93.message : String(error93)
35534
- });
35535
- }
35536
- }
35537
- function createSnapshotWriterHook(directory) {
35538
- return (_input, _output) => {
35539
- _writeInFlight = _writeInFlight.then(() => _internals8.writeSnapshot(directory, swarmState), () => _internals8.writeSnapshot(directory, swarmState));
35540
- return _writeInFlight;
35541
- };
35542
- }
35543
- async function flushPendingSnapshot(directory) {
35544
- _writeInFlight = _writeInFlight.then(() => _internals8.writeSnapshot(directory, swarmState), () => _internals8.writeSnapshot(directory, swarmState));
35545
- await _writeInFlight;
35546
- }
35547
- var _writeInFlight, _internals8;
35548
- var init_snapshot_writer = __esm(() => {
35549
- init_utils2();
35550
- init_state();
35551
- init_utils();
35552
- init_bun_compat();
35553
- _writeInFlight = Promise.resolve();
35554
- _internals8 = {
35555
- writeSnapshot,
35556
- createSnapshotWriterHook,
35557
- flushPendingSnapshot
35558
- };
35559
- });
35560
-
35561
35950
  // src/tools/write-retro.ts
35562
35951
  async function executeWriteRetro(args, directory) {
35563
35952
  if (/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])(:|$)/i.test(directory)) {
@@ -35859,7 +36248,7 @@ async function executeWriteRetro(args, directory) {
35859
36248
  }, null, 2);
35860
36249
  }
35861
36250
  }
35862
- var write_retro, _internals9;
36251
+ var write_retro, _internals8;
35863
36252
  var init_write_retro = __esm(() => {
35864
36253
  init_zod();
35865
36254
  init_evidence_schema();
@@ -35906,13 +36295,13 @@ var init_write_retro = __esm(() => {
35906
36295
  task_id: args.task_id !== undefined ? String(args.task_id) : undefined,
35907
36296
  metadata: args.metadata
35908
36297
  };
35909
- return await _internals9.executeWriteRetro(writeRetroArgs, directory);
36298
+ return await _internals8.executeWriteRetro(writeRetroArgs, directory);
35910
36299
  } catch {
35911
36300
  return JSON.stringify({ success: false, phase: rawPhase, message: "Invalid arguments" }, null, 2);
35912
36301
  }
35913
36302
  }
35914
36303
  });
35915
- _internals9 = {
36304
+ _internals8 = {
35916
36305
  executeWriteRetro,
35917
36306
  write_retro
35918
36307
  };
@@ -35974,6 +36363,7 @@ async function handleCloseCommand(directory, args) {
35974
36363
  const closedPhases = [];
35975
36364
  const closedTasks = [];
35976
36365
  const warnings = [];
36366
+ let hivePromoted = 0;
35977
36367
  if (!planAlreadyDone) {
35978
36368
  for (const phase of inProgressPhases) {
35979
36369
  closedPhases.push(phase.id);
@@ -36094,6 +36484,26 @@ async function handleCloseCommand(directory, args) {
36094
36484
  if (curationSucceeded && allLessons.length > 0) {
36095
36485
  await fs7.unlink(lessonsFilePath).catch(() => {});
36096
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
+ }
36097
36507
  if (planExists) {
36098
36508
  const guaranteeResult = guaranteeAllPlansComplete(planData);
36099
36509
  for (const phaseId of guaranteeResult.closedPhaseIds) {
@@ -36122,6 +36532,7 @@ async function handleCloseCommand(directory, args) {
36122
36532
  let archiveResult = "";
36123
36533
  let archivedFileCount = 0;
36124
36534
  const archivedActiveStateFiles = new Set;
36535
+ const archivedActiveStateDirs = new Set;
36125
36536
  try {
36126
36537
  await fs7.mkdir(archiveDir, { recursive: true });
36127
36538
  for (const artifact of ARCHIVE_ARTIFACTS) {
@@ -36135,38 +36546,34 @@ async function handleCloseCommand(directory, args) {
36135
36546
  }
36136
36547
  } catch {}
36137
36548
  }
36138
- const evidenceDir = path14.join(swarmDir, "evidence");
36139
- const archiveEvidenceDir = path14.join(archiveDir, "evidence");
36140
- try {
36141
- const evidenceEntries = await fs7.readdir(evidenceDir);
36142
- if (evidenceEntries.length > 0) {
36143
- await fs7.mkdir(archiveEvidenceDir, { recursive: true });
36144
- for (const entry of evidenceEntries) {
36145
- const srcEntry = path14.join(evidenceDir, entry);
36146
- const destEntry = path14.join(archiveEvidenceDir, entry);
36147
- try {
36148
- const stat2 = await fs7.stat(srcEntry);
36149
- if (stat2.isDirectory()) {
36150
- await fs7.mkdir(destEntry, { recursive: true });
36151
- const subEntries = await fs7.readdir(srcEntry);
36152
- for (const sub of subEntries) {
36153
- 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);
36154
36569
  }
36155
- } else {
36156
- await fs7.copyFile(srcEntry, destEntry);
36157
- }
36158
- archivedFileCount++;
36159
- } catch {}
36570
+ archivedFileCount++;
36571
+ } catch {}
36572
+ }
36160
36573
  }
36161
- }
36162
- } catch {}
36163
- const sessionStatePath = path14.join(swarmDir, "session", "state.json");
36164
- try {
36165
- const archiveSessionDir = path14.join(archiveDir, "session");
36166
- await fs7.mkdir(archiveSessionDir, { recursive: true });
36167
- await fs7.copyFile(sessionStatePath, path14.join(archiveSessionDir, "state.json"));
36168
- archivedFileCount++;
36169
- } catch {}
36574
+ archivedActiveStateDirs.add(dirName);
36575
+ } catch {}
36576
+ }
36170
36577
  archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
36171
36578
  } catch (archiveError) {
36172
36579
  warnings.push(`Archive creation failed: ${archiveError instanceof Error ? archiveError.message : String(archiveError)}`);
@@ -36196,6 +36603,16 @@ async function handleCloseCommand(directory, args) {
36196
36603
  } else {
36197
36604
  warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");
36198
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
+ }
36199
36616
  try {
36200
36617
  const swarmFiles = await fs7.readdir(swarmDir);
36201
36618
  const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
@@ -36254,17 +36671,30 @@ async function handleCloseCommand(directory, args) {
36254
36671
  const prunedBranches = [];
36255
36672
  const isGit = isGitRepo2(directory);
36256
36673
  if (isGit) {
36257
- const alignResult = resetToRemoteBranch(directory, { pruneBranches });
36258
- gitAlignResult = alignResult.message;
36259
- prunedBranches.push(...alignResult.prunedBranches);
36260
- if (!alignResult.success) {
36261
- warnings.push(`Git alignment: ${alignResult.message}`);
36262
- }
36263
- if (alignResult.alreadyAligned) {
36264
- gitAlignResult = `Already aligned with ${alignResult.targetBranch}`;
36265
- }
36266
- for (const w of alignResult.warnings) {
36267
- 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
+ }
36268
36698
  }
36269
36699
  } else {
36270
36700
  gitAlignResult = "Not a git repository \u2014 skipped git alignment";
@@ -36304,6 +36734,7 @@ async function handleCloseCommand(directory, args) {
36304
36734
  ...swarmPlanFilesRemoved > 0 ? [`- Removed ${swarmPlanFilesRemoved} SWARM_PLAN checkpoint artifact(s)`] : [],
36305
36735
  ...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : [],
36306
36736
  ...curationSucceeded && allLessons.length > 0 ? [`- Committed ${allLessons.length} lesson(s) to knowledge store`] : [],
36737
+ ...hivePromoted > 0 ? [`- Promoted ${hivePromoted} lesson(s) to hive knowledge`] : [],
36307
36738
  "",
36308
36739
  ...warnings.length > 0 ? ["## Warnings", ...warnings.map((w) => `- ${w}`), ""] : []
36309
36740
  ].join(`
@@ -36315,13 +36746,6 @@ async function handleCloseCommand(directory, args) {
36315
36746
  warnings.push(`Failed to write close-summary.md: ${msg}`);
36316
36747
  console.warn("[close-command] Failed to write close-summary.md:", error93);
36317
36748
  }
36318
- try {
36319
- await flushPendingSnapshot(directory);
36320
- } catch (error93) {
36321
- const msg = error93 instanceof Error ? error93.message : String(error93);
36322
- warnings.push(`flushPendingSnapshot failed: ${msg}`);
36323
- console.warn("[close-command] flushPendingSnapshot error:", error93);
36324
- }
36325
36749
  const preservedClient = swarmState.opencodeClient;
36326
36750
  const preservedFullAutoFlag = swarmState.fullAutoEnabledInConfig;
36327
36751
  const preservedCuratorInitNames = swarmState.curatorInitAgentNames;
@@ -36362,15 +36786,16 @@ ${otherWarnings.map((w) => `- ${w}`).join(`
36362
36786
  **Archive:** ${archiveResult}
36363
36787
  **Git:** ${gitAlignResult}${lessonSummary}${warningMsg}`;
36364
36788
  }
36365
- var ARCHIVE_ARTIFACTS, ACTIVE_STATE_TO_CLEAN;
36789
+ var ARCHIVE_ARTIFACTS, ACTIVE_STATE_TO_CLEAN, ACTIVE_STATE_DIRS_TO_CLEAN;
36366
36790
  var init_close = __esm(() => {
36367
36791
  init_schema();
36368
36792
  init_manager2();
36369
36793
  init_branch();
36794
+ init_hive_promoter();
36370
36795
  init_knowledge_curator();
36796
+ init_knowledge_store();
36371
36797
  init_utils2();
36372
36798
  init_scope_persistence();
36373
- init_snapshot_writer();
36374
36799
  init_state();
36375
36800
  init_write_retro();
36376
36801
  ARCHIVE_ARTIFACTS = [
@@ -36383,7 +36808,18 @@ var init_close = __esm(() => {
36383
36808
  "handoff-prompt.md",
36384
36809
  "handoff-consumed.md",
36385
36810
  "escalation-report.md",
36386
- "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"
36387
36823
  ];
36388
36824
  ACTIVE_STATE_TO_CLEAN = [
36389
36825
  "plan.json",
@@ -36393,7 +36829,23 @@ var init_close = __esm(() => {
36393
36829
  "handoff.md",
36394
36830
  "handoff-prompt.md",
36395
36831
  "handoff-consumed.md",
36396
- "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"
36397
36849
  ];
36398
36850
  });
36399
36851
 
@@ -36496,322 +36948,6 @@ var init_council = __esm(() => {
36496
36948
  `);
36497
36949
  });
36498
36950
 
36499
- // src/background/event-bus.ts
36500
- class AutomationEventBus {
36501
- listeners = new Map;
36502
- eventHistory = [];
36503
- maxHistorySize;
36504
- constructor(options) {
36505
- this.maxHistorySize = options?.maxHistorySize ?? 100;
36506
- }
36507
- subscribe(type, listener) {
36508
- if (!this.listeners.has(type)) {
36509
- this.listeners.set(type, new Set);
36510
- }
36511
- this.listeners.get(type).add(listener);
36512
- return () => {
36513
- this.listeners.get(type)?.delete(listener);
36514
- };
36515
- }
36516
- async publish(type, payload, source) {
36517
- const event = {
36518
- type,
36519
- timestamp: Date.now(),
36520
- payload,
36521
- source
36522
- };
36523
- this.eventHistory.push(event);
36524
- if (this.eventHistory.length > this.maxHistorySize) {
36525
- this.eventHistory.shift();
36526
- }
36527
- log(`[EventBus] ${type}`, {
36528
- source,
36529
- payload: typeof payload === "object" ? "..." : payload
36530
- });
36531
- const listeners = this.listeners.get(type);
36532
- if (listeners) {
36533
- await Promise.all(Array.from(listeners).map(async (listener) => {
36534
- try {
36535
- await listener(event);
36536
- } catch (error93) {
36537
- log(`[EventBus] Listener error for ${type}`, { error: error93 });
36538
- }
36539
- }));
36540
- }
36541
- }
36542
- getHistory(types) {
36543
- if (!types || types.length === 0) {
36544
- return [...this.eventHistory];
36545
- }
36546
- return this.eventHistory.filter((e) => types.includes(e.type));
36547
- }
36548
- clearHistory() {
36549
- this.eventHistory = [];
36550
- }
36551
- getListenerCount(type) {
36552
- return this.listeners.get(type)?.size ?? 0;
36553
- }
36554
- hasListeners(type) {
36555
- return this.getListenerCount(type) > 0;
36556
- }
36557
- }
36558
- function getGlobalEventBus() {
36559
- if (!globalEventBus) {
36560
- globalEventBus = new AutomationEventBus;
36561
- }
36562
- return globalEventBus;
36563
- }
36564
- var globalEventBus = null;
36565
- var init_event_bus = __esm(() => {
36566
- init_utils();
36567
- });
36568
-
36569
- // src/hooks/curator.ts
36570
- var init_curator = __esm(() => {
36571
- init_event_bus();
36572
- init_manager();
36573
- init_bun_compat();
36574
- init_logger();
36575
- init_knowledge_store();
36576
- init_knowledge_validator();
36577
- init_utils2();
36578
- });
36579
-
36580
- // src/hooks/hive-promoter.ts
36581
- import path16 from "path";
36582
- function isAlreadyInHive(entry, hiveEntries, threshold) {
36583
- return findNearDuplicate(entry.lesson, hiveEntries, threshold) !== undefined;
36584
- }
36585
- function countDistinctPhases(confirmedBy) {
36586
- const phaseNumbers = new Set;
36587
- for (const record3 of confirmedBy) {
36588
- phaseNumbers.add(record3.phase_number);
36589
- }
36590
- return phaseNumbers.size;
36591
- }
36592
- function countDistinctProjects(confirmedBy) {
36593
- const projectNames = new Set;
36594
- for (const record3 of confirmedBy) {
36595
- projectNames.add(record3.project_name);
36596
- }
36597
- return projectNames.size;
36598
- }
36599
- function hasProjectConfirmation(hiveEntry, projectName) {
36600
- return hiveEntry.confirmed_by.some((record3) => record3.project_name === projectName);
36601
- }
36602
- function calculateEncounterScore(currentScore, isSameProject, config3) {
36603
- const weight = isSameProject ? config3.same_project_weight : config3.cross_project_weight;
36604
- const increment = config3.encounter_increment * weight;
36605
- const newScore = currentScore + increment;
36606
- return Math.min(Math.max(newScore, config3.min_encounter_score), config3.max_encounter_score);
36607
- }
36608
- function getEntryAgeMs(createdAt) {
36609
- const createdTime = new Date(createdAt).getTime();
36610
- if (Number.isNaN(createdTime))
36611
- return 0;
36612
- return Date.now() - createdTime;
36613
- }
36614
- async function checkHivePromotions(swarmEntries, config3) {
36615
- let newPromotions = 0;
36616
- let encountersIncremented = 0;
36617
- let advancements = 0;
36618
- if (config3.hive_enabled === false) {
36619
- return {
36620
- timestamp: new Date().toISOString(),
36621
- new_promotions: 0,
36622
- encounters_incremented: 0,
36623
- advancements: 0,
36624
- total_hive_entries: 0
36625
- };
36626
- }
36627
- const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
36628
- for (const swarmEntry of swarmEntries) {
36629
- if (isAlreadyInHive(swarmEntry, hiveEntries, config3.dedup_threshold)) {
36630
- continue;
36631
- }
36632
- let shouldPromote = false;
36633
- if (swarmEntry.hive_eligible === true && countDistinctPhases(swarmEntry.confirmed_by) >= 3) {
36634
- shouldPromote = true;
36635
- }
36636
- if (swarmEntry.tags.includes("hive-fast-track")) {
36637
- shouldPromote = true;
36638
- }
36639
- const ageMs = getEntryAgeMs(swarmEntry.created_at);
36640
- const ageThresholdMs = config3.auto_promote_days * 86400000;
36641
- if (ageMs >= ageThresholdMs) {
36642
- shouldPromote = true;
36643
- }
36644
- if (!shouldPromote) {
36645
- continue;
36646
- }
36647
- const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
36648
- category: swarmEntry.category,
36649
- scope: swarmEntry.scope,
36650
- confidence: swarmEntry.confidence
36651
- });
36652
- if (validationResult.severity === "error") {
36653
- const rejectedLesson = {
36654
- id: crypto.randomUUID(),
36655
- lesson: swarmEntry.lesson,
36656
- rejection_reason: validationResult.reason || "validation failed for hive promotion",
36657
- rejected_at: new Date().toISOString(),
36658
- rejection_layer: validationResult.layer || 2
36659
- };
36660
- const hiveRejectedPath = resolveHiveRejectedPath();
36661
- await appendKnowledge(hiveRejectedPath, rejectedLesson);
36662
- continue;
36663
- }
36664
- const newHiveEntry = {
36665
- id: crypto.randomUUID(),
36666
- tier: "hive",
36667
- lesson: swarmEntry.lesson,
36668
- category: swarmEntry.category,
36669
- tags: swarmEntry.tags,
36670
- scope: swarmEntry.scope,
36671
- confidence: 0.5,
36672
- status: "candidate",
36673
- confirmed_by: [],
36674
- retrieval_outcomes: {
36675
- applied_count: 0,
36676
- succeeded_after_count: 0,
36677
- failed_after_count: 0
36678
- },
36679
- schema_version: config3.schema_version,
36680
- created_at: new Date().toISOString(),
36681
- updated_at: new Date().toISOString(),
36682
- source_project: swarmEntry.project_name,
36683
- encounter_score: config3.initial_encounter_score
36684
- };
36685
- await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
36686
- newPromotions++;
36687
- hiveEntries.push(newHiveEntry);
36688
- }
36689
- let hiveModified = false;
36690
- for (const hiveEntry of hiveEntries) {
36691
- const nearDuplicate = findNearDuplicate(hiveEntry.lesson, swarmEntries, config3.dedup_threshold);
36692
- if (!nearDuplicate) {
36693
- continue;
36694
- }
36695
- const isSameProject = nearDuplicate.project_name === hiveEntry.source_project;
36696
- if (hasProjectConfirmation(hiveEntry, nearDuplicate.project_name)) {
36697
- continue;
36698
- }
36699
- const newConfirmation = {
36700
- project_name: nearDuplicate.project_name,
36701
- confirmed_at: new Date().toISOString()
36702
- };
36703
- hiveEntry.confirmed_by.push(newConfirmation);
36704
- const currentScore = hiveEntry.encounter_score ?? 1;
36705
- hiveEntry.encounter_score = calculateEncounterScore(currentScore, isSameProject, config3);
36706
- encountersIncremented++;
36707
- hiveEntry.updated_at = new Date().toISOString();
36708
- if (hiveEntry.status === "candidate" && countDistinctProjects(hiveEntry.confirmed_by) >= 3) {
36709
- hiveEntry.status = "established";
36710
- advancements++;
36711
- }
36712
- hiveModified = true;
36713
- }
36714
- if (hiveModified) {
36715
- await rewriteKnowledge(resolveHiveKnowledgePath(), hiveEntries);
36716
- }
36717
- if (newPromotions > 0 || hiveModified) {
36718
- await enforceKnowledgeCap(resolveHiveKnowledgePath(), config3.hive_max_entries);
36719
- }
36720
- return {
36721
- timestamp: new Date().toISOString(),
36722
- new_promotions: newPromotions,
36723
- encounters_incremented: encountersIncremented,
36724
- advancements,
36725
- total_hive_entries: hiveEntries.length
36726
- };
36727
- }
36728
- async function promoteToHive(directory, lesson, category) {
36729
- const trimmedLesson = lesson.trim();
36730
- const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
36731
- const validationResult = validateLesson(trimmedLesson, hiveEntries.map((e) => e.lesson), {
36732
- category: category || "process",
36733
- scope: "global",
36734
- confidence: 1
36735
- });
36736
- if (validationResult.severity === "error") {
36737
- throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
36738
- }
36739
- if (findNearDuplicate(trimmedLesson, hiveEntries, 0.6)) {
36740
- return `Lesson already exists in hive (near-duplicate).`;
36741
- }
36742
- const newHiveEntry = {
36743
- id: crypto.randomUUID(),
36744
- tier: "hive",
36745
- lesson: trimmedLesson,
36746
- category: category || "process",
36747
- tags: [],
36748
- scope: "global",
36749
- confidence: 1,
36750
- status: "promoted",
36751
- confirmed_by: [],
36752
- retrieval_outcomes: {
36753
- applied_count: 0,
36754
- succeeded_after_count: 0,
36755
- failed_after_count: 0
36756
- },
36757
- schema_version: 1,
36758
- created_at: new Date().toISOString(),
36759
- updated_at: new Date().toISOString(),
36760
- source_project: path16.basename(directory) || "unknown",
36761
- encounter_score: 1
36762
- };
36763
- await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
36764
- return `Promoted to hive: "${trimmedLesson.slice(0, 50)}${trimmedLesson.length > 50 ? "..." : ""}" (confidence: 1.0, source: manual)`;
36765
- }
36766
- async function promoteFromSwarm(directory, lessonId) {
36767
- const swarmEntries = await readKnowledge(resolveSwarmKnowledgePath(directory));
36768
- const swarmEntry = swarmEntries.find((e) => e.id === lessonId);
36769
- if (!swarmEntry) {
36770
- throw new Error(`Lesson ${lessonId} not found in .swarm/knowledge.jsonl`);
36771
- }
36772
- const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
36773
- const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
36774
- category: swarmEntry.category,
36775
- scope: swarmEntry.scope,
36776
- confidence: swarmEntry.confidence
36777
- });
36778
- if (validationResult.severity === "error") {
36779
- throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
36780
- }
36781
- if (findNearDuplicate(swarmEntry.lesson, hiveEntries, 0.6)) {
36782
- return `Lesson already exists in hive (near-duplicate).`;
36783
- }
36784
- const newHiveEntry = {
36785
- id: crypto.randomUUID(),
36786
- tier: "hive",
36787
- lesson: swarmEntry.lesson,
36788
- category: swarmEntry.category,
36789
- tags: swarmEntry.tags,
36790
- scope: swarmEntry.scope,
36791
- confidence: 1,
36792
- status: "promoted",
36793
- confirmed_by: [],
36794
- retrieval_outcomes: {
36795
- applied_count: 0,
36796
- succeeded_after_count: 0,
36797
- failed_after_count: 0
36798
- },
36799
- schema_version: 1,
36800
- created_at: new Date().toISOString(),
36801
- updated_at: new Date().toISOString(),
36802
- source_project: swarmEntry.project_name,
36803
- encounter_score: 1
36804
- };
36805
- await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
36806
- return `Promoted lesson ${lessonId} from swarm to hive: "${swarmEntry.lesson.slice(0, 50)}${swarmEntry.lesson.length > 50 ? "..." : ""}"`;
36807
- }
36808
- var init_hive_promoter = __esm(() => {
36809
- init_curator();
36810
- init_knowledge_store();
36811
- init_knowledge_validator();
36812
- init_utils2();
36813
- });
36814
-
36815
36951
  // src/commands/curate.ts
36816
36952
  async function handleCurateCommand(directory, _args) {
36817
36953
  try {
@@ -36849,7 +36985,7 @@ var init_curate = __esm(() => {
36849
36985
  import * as child_process3 from "child_process";
36850
36986
  import { randomUUID } from "crypto";
36851
36987
  import { readdir, readFile as readFile5, stat as stat2 } from "fs/promises";
36852
- import * as path17 from "path";
36988
+ import * as path16 from "path";
36853
36989
  import { promisify } from "util";
36854
36990
  function getExecFileAsync() {
36855
36991
  return promisify(child_process3.execFile);
@@ -36951,7 +37087,7 @@ async function scanSourceFiles(dir) {
36951
37087
  try {
36952
37088
  const entries = await readdir(dir, { withFileTypes: true });
36953
37089
  for (const entry of entries) {
36954
- const fullPath = path17.join(dir, entry.name);
37090
+ const fullPath = path16.join(dir, entry.name);
36955
37091
  if (entry.isDirectory()) {
36956
37092
  if (skipDirs.has(entry.name)) {
36957
37093
  continue;
@@ -36959,7 +37095,7 @@ async function scanSourceFiles(dir) {
36959
37095
  const subFiles = await scanSourceFiles(fullPath);
36960
37096
  results.push(...subFiles);
36961
37097
  } else if (entry.isFile()) {
36962
- const ext = path17.extname(entry.name);
37098
+ const ext = path16.extname(entry.name);
36963
37099
  if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
36964
37100
  results.push(fullPath);
36965
37101
  }
@@ -36981,8 +37117,8 @@ async function getStaticEdges(directory) {
36981
37117
  continue;
36982
37118
  }
36983
37119
  try {
36984
- const sourceDir = path17.dirname(sourceFile);
36985
- const resolvedPath = path17.resolve(sourceDir, importPath);
37120
+ const sourceDir = path16.dirname(sourceFile);
37121
+ const resolvedPath = path16.resolve(sourceDir, importPath);
36986
37122
  const extensions = [
36987
37123
  "",
36988
37124
  ".ts",
@@ -37007,8 +37143,8 @@ async function getStaticEdges(directory) {
37007
37143
  if (!targetFile) {
37008
37144
  continue;
37009
37145
  }
37010
- const relSource = path17.relative(directory, sourceFile).replace(/\\/g, "/");
37011
- 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, "/");
37012
37148
  const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
37013
37149
  edges.add(key);
37014
37150
  } catch {}
@@ -37020,7 +37156,7 @@ async function getStaticEdges(directory) {
37020
37156
  function isTestImplementationPair(fileA, fileB) {
37021
37157
  const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
37022
37158
  const getBaseName = (filePath) => {
37023
- const base = path17.basename(filePath);
37159
+ const base = path16.basename(filePath);
37024
37160
  for (const pattern of testPatterns) {
37025
37161
  if (base.endsWith(pattern)) {
37026
37162
  return base.slice(0, -pattern.length);
@@ -37030,16 +37166,16 @@ function isTestImplementationPair(fileA, fileB) {
37030
37166
  };
37031
37167
  const baseA = getBaseName(fileA);
37032
37168
  const baseB = getBaseName(fileB);
37033
- return baseA === baseB && baseA !== path17.basename(fileA) && baseA !== path17.basename(fileB);
37169
+ return baseA === baseB && baseA !== path16.basename(fileA) && baseA !== path16.basename(fileB);
37034
37170
  }
37035
37171
  function hasSharedPrefix(fileA, fileB) {
37036
- const dirA = path17.dirname(fileA);
37037
- const dirB = path17.dirname(fileB);
37172
+ const dirA = path16.dirname(fileA);
37173
+ const dirB = path16.dirname(fileB);
37038
37174
  if (dirA !== dirB) {
37039
37175
  return false;
37040
37176
  }
37041
- const baseA = path17.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
37042
- 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)$/, "");
37043
37179
  if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
37044
37180
  return true;
37045
37181
  }
@@ -37067,9 +37203,9 @@ async function detectDarkMatter(directory, options) {
37067
37203
  } catch {
37068
37204
  return [];
37069
37205
  }
37070
- const commitMap = await _internals10.parseGitLog(directory, maxCommitsToAnalyze);
37071
- const matrix = _internals10.buildCoChangeMatrix(commitMap);
37072
- 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);
37073
37209
  const results = [];
37074
37210
  for (const entry of matrix.values()) {
37075
37211
  const key = `${entry.fileA}::${entry.fileB}`;
@@ -37093,8 +37229,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
37093
37229
  const entries = [];
37094
37230
  const now = new Date().toISOString();
37095
37231
  for (const pair of pairs.slice(0, 10)) {
37096
- const baseA = path17.basename(pair.fileA);
37097
- const baseB = path17.basename(pair.fileB);
37232
+ const baseA = path16.basename(pair.fileA);
37233
+ const baseB = path16.basename(pair.fileB);
37098
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.`;
37099
37235
  if (lesson.length > 280) {
37100
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.`;
@@ -37149,7 +37285,7 @@ ${rows}
37149
37285
  These pairs likely share an architectural concern invisible to static analysis.
37150
37286
  Consider adding explicit documentation or extracting the shared concern.`;
37151
37287
  }
37152
- var co_change_analyzer, _internals10;
37288
+ var co_change_analyzer, _internals9;
37153
37289
  var init_co_change_analyzer = __esm(() => {
37154
37290
  init_zod();
37155
37291
  init_create_tool();
@@ -37181,11 +37317,11 @@ var init_co_change_analyzer = __esm(() => {
37181
37317
  npmiThreshold,
37182
37318
  maxCommitsToAnalyze
37183
37319
  };
37184
- const pairs = await _internals10.detectDarkMatter(directory, options);
37185
- return _internals10.formatDarkMatterOutput(pairs);
37320
+ const pairs = await _internals9.detectDarkMatter(directory, options);
37321
+ return _internals9.formatDarkMatterOutput(pairs);
37186
37322
  }
37187
37323
  });
37188
- _internals10 = {
37324
+ _internals9 = {
37189
37325
  parseGitLog,
37190
37326
  buildCoChangeMatrix,
37191
37327
  getStaticEdges,
@@ -37196,7 +37332,7 @@ var init_co_change_analyzer = __esm(() => {
37196
37332
  });
37197
37333
 
37198
37334
  // src/commands/dark-matter.ts
37199
- import path18 from "path";
37335
+ import path17 from "path";
37200
37336
  async function handleDarkMatterCommand(directory, args) {
37201
37337
  const options = {};
37202
37338
  for (let i = 0;i < args.length; i++) {
@@ -37216,7 +37352,7 @@ async function handleDarkMatterCommand(directory, args) {
37216
37352
  }
37217
37353
  let pairs;
37218
37354
  try {
37219
- pairs = await _internals10.detectDarkMatter(directory, options);
37355
+ pairs = await _internals9.detectDarkMatter(directory, options);
37220
37356
  } catch (err) {
37221
37357
  const errMsg = err instanceof Error ? err.message : String(err);
37222
37358
  return `## Dark Matter Analysis Failed
@@ -37228,7 +37364,7 @@ Ensure this is a git repository with commit history.`;
37228
37364
  const output = formatDarkMatterOutput(pairs);
37229
37365
  if (pairs.length > 0) {
37230
37366
  try {
37231
- const projectName = path18.basename(path18.resolve(directory));
37367
+ const projectName = path17.basename(path17.resolve(directory));
37232
37368
  const entries = darkMatterToKnowledgeEntries(pairs, projectName);
37233
37369
  if (entries.length > 0) {
37234
37370
  const knowledgePath = resolveSwarmKnowledgePath(directory);
@@ -37253,51 +37389,51 @@ var init_dark_matter = __esm(() => {
37253
37389
 
37254
37390
  // src/config/cache-paths.ts
37255
37391
  import * as os5 from "os";
37256
- import * as path19 from "path";
37392
+ import * as path18 from "path";
37257
37393
  function getPluginConfigDir() {
37258
- 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");
37259
37395
  }
37260
37396
  function getPluginCachePaths() {
37261
- 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");
37262
37398
  const configDir = getPluginConfigDir();
37263
37399
  const paths = [
37264
- path19.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
37265
- path19.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
37266
- 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")
37267
37403
  ];
37268
37404
  if (process.platform === "darwin") {
37269
- const libCaches = path19.join(os5.homedir(), "Library", "Caches");
37270
- 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"));
37271
37407
  }
37272
37408
  if (process.platform === "win32") {
37273
- const localAppData = process.env.LOCALAPPDATA || path19.join(os5.homedir(), "AppData", "Local");
37274
- const appData = process.env.APPDATA || path19.join(os5.homedir(), "AppData", "Roaming");
37275
- 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"));
37276
37412
  }
37277
37413
  return paths;
37278
37414
  }
37279
37415
  function getPluginLockFilePaths() {
37280
- 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");
37281
37417
  const configDir = getPluginConfigDir();
37282
37418
  const paths = [
37283
- path19.join(cacheBase, "opencode", "bun.lock"),
37284
- path19.join(cacheBase, "opencode", "bun.lockb"),
37285
- 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")
37286
37422
  ];
37287
37423
  if (process.platform === "darwin") {
37288
- const libCaches = path19.join(os5.homedir(), "Library", "Caches");
37289
- 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"));
37290
37426
  }
37291
37427
  if (process.platform === "win32") {
37292
- const localAppData = process.env.LOCALAPPDATA || path19.join(os5.homedir(), "AppData", "Local");
37293
- 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"));
37294
37430
  }
37295
37431
  return paths;
37296
37432
  }
37297
37433
  var init_cache_paths = () => {};
37298
37434
 
37299
37435
  // src/services/version-check.ts
37300
- 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";
37301
37437
  import { homedir as homedir5 } from "os";
37302
37438
  import { join as join17 } from "path";
37303
37439
  function cacheDir() {
@@ -37310,10 +37446,10 @@ function cacheFile() {
37310
37446
  }
37311
37447
  function readVersionCache() {
37312
37448
  try {
37313
- const path20 = cacheFile();
37314
- if (!existsSync9(path20))
37449
+ const path19 = cacheFile();
37450
+ if (!existsSync9(path19))
37315
37451
  return null;
37316
- const raw = readFileSync5(path20, "utf-8");
37452
+ const raw = readFileSync5(path19, "utf-8");
37317
37453
  const parsed = JSON.parse(raw);
37318
37454
  if (typeof parsed?.checkedAt !== "number")
37319
37455
  return null;
@@ -37353,7 +37489,7 @@ var init_version_check = __esm(() => {
37353
37489
  // src/services/diagnose-service.ts
37354
37490
  import * as child_process4 from "child_process";
37355
37491
  import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync as statSync6 } from "fs";
37356
- import path20 from "path";
37492
+ import path19 from "path";
37357
37493
  import { fileURLToPath } from "url";
37358
37494
  function validateTaskDag(plan) {
37359
37495
  const allTaskIds = new Set;
@@ -37650,7 +37786,7 @@ async function checkSpecStaleness(directory, plan) {
37650
37786
  };
37651
37787
  }
37652
37788
  async function checkConfigParseability(directory) {
37653
- const configPath = path20.join(directory, ".opencode/opencode-swarm.json");
37789
+ const configPath = path19.join(directory, ".opencode/opencode-swarm.json");
37654
37790
  if (!existsSync10(configPath)) {
37655
37791
  return {
37656
37792
  name: "Config Parseability",
@@ -37679,7 +37815,7 @@ function resolveGrammarDir(thisDir) {
37679
37815
  const normalized = thisDir.replace(/\\/g, "/");
37680
37816
  const isSource = normalized.endsWith("/src/services");
37681
37817
  const isCliBundle = normalized.endsWith("/cli");
37682
- 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");
37683
37819
  }
37684
37820
  async function checkGrammarWasmFiles() {
37685
37821
  const grammarFiles = [
@@ -37703,14 +37839,14 @@ async function checkGrammarWasmFiles() {
37703
37839
  "tree-sitter-ini.wasm",
37704
37840
  "tree-sitter-regex.wasm"
37705
37841
  ];
37706
- const thisDir = path20.dirname(fileURLToPath(import.meta.url));
37842
+ const thisDir = path19.dirname(fileURLToPath(import.meta.url));
37707
37843
  const grammarDir = resolveGrammarDir(thisDir);
37708
37844
  const missing = [];
37709
- if (!existsSync10(path20.join(grammarDir, "tree-sitter.wasm"))) {
37845
+ if (!existsSync10(path19.join(grammarDir, "tree-sitter.wasm"))) {
37710
37846
  missing.push("tree-sitter.wasm (core runtime)");
37711
37847
  }
37712
37848
  for (const file3 of grammarFiles) {
37713
- if (!existsSync10(path20.join(grammarDir, file3))) {
37849
+ if (!existsSync10(path19.join(grammarDir, file3))) {
37714
37850
  missing.push(file3);
37715
37851
  }
37716
37852
  }
@@ -37728,7 +37864,7 @@ async function checkGrammarWasmFiles() {
37728
37864
  };
37729
37865
  }
37730
37866
  async function checkCheckpointManifest(directory) {
37731
- const manifestPath = path20.join(directory, ".swarm/checkpoints.json");
37867
+ const manifestPath = path19.join(directory, ".swarm/checkpoints.json");
37732
37868
  if (!existsSync10(manifestPath)) {
37733
37869
  return {
37734
37870
  name: "Checkpoint Manifest",
@@ -37780,7 +37916,7 @@ async function checkCheckpointManifest(directory) {
37780
37916
  }
37781
37917
  }
37782
37918
  async function checkEventStreamIntegrity(directory) {
37783
- const eventsPath = path20.join(directory, ".swarm/events.jsonl");
37919
+ const eventsPath = path19.join(directory, ".swarm/events.jsonl");
37784
37920
  if (!existsSync10(eventsPath)) {
37785
37921
  return {
37786
37922
  name: "Event Stream",
@@ -37821,7 +37957,7 @@ async function checkEventStreamIntegrity(directory) {
37821
37957
  }
37822
37958
  }
37823
37959
  async function checkSteeringDirectives(directory) {
37824
- const eventsPath = path20.join(directory, ".swarm/events.jsonl");
37960
+ const eventsPath = path19.join(directory, ".swarm/events.jsonl");
37825
37961
  if (!existsSync10(eventsPath)) {
37826
37962
  return {
37827
37963
  name: "Steering Directives",
@@ -37877,7 +38013,7 @@ async function checkCurator(directory) {
37877
38013
  detail: "Disabled (enable via curator.enabled)"
37878
38014
  };
37879
38015
  }
37880
- const summaryPath = path20.join(directory, ".swarm/curator-summary.json");
38016
+ const summaryPath = path19.join(directory, ".swarm/curator-summary.json");
37881
38017
  if (!existsSync10(summaryPath)) {
37882
38018
  return {
37883
38019
  name: "Curator",
@@ -38043,7 +38179,7 @@ async function getDiagnoseData(directory) {
38043
38179
  checks5.push(await checkSteeringDirectives(directory));
38044
38180
  checks5.push(await checkCurator(directory));
38045
38181
  try {
38046
- const evidenceDir = path20.join(directory, ".swarm", "evidence");
38182
+ const evidenceDir = path19.join(directory, ".swarm", "evidence");
38047
38183
  const snapshotFiles = existsSync10(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
38048
38184
  if (snapshotFiles.length > 0) {
38049
38185
  const latest = snapshotFiles.sort().pop();
@@ -38081,7 +38217,7 @@ async function getDiagnoseData(directory) {
38081
38217
  cacheRows.push(`\u2B1C ${cachePath} \u2014 absent`);
38082
38218
  continue;
38083
38219
  }
38084
- const pkgJsonPath = path20.join(cachePath, "package.json");
38220
+ const pkgJsonPath = path19.join(cachePath, "package.json");
38085
38221
  try {
38086
38222
  const raw = readFileSync6(pkgJsonPath, "utf-8");
38087
38223
  const parsed = JSON.parse(raw);
@@ -38169,13 +38305,13 @@ __export(exports_config_doctor, {
38169
38305
  import * as crypto3 from "crypto";
38170
38306
  import * as fs8 from "fs";
38171
38307
  import * as os6 from "os";
38172
- import * as path21 from "path";
38308
+ import * as path20 from "path";
38173
38309
  function getUserConfigDir3() {
38174
- return process.env.XDG_CONFIG_HOME || path21.join(os6.homedir(), ".config");
38310
+ return process.env.XDG_CONFIG_HOME || path20.join(os6.homedir(), ".config");
38175
38311
  }
38176
38312
  function getConfigPaths(directory) {
38177
- const userConfigPath = path21.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
38178
- 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");
38179
38315
  return { userConfigPath, projectConfigPath };
38180
38316
  }
38181
38317
  function computeHash(content) {
@@ -38200,9 +38336,9 @@ function isValidConfigPath(configPath, directory) {
38200
38336
  const normalizedUser = userConfigPath.replace(/\\/g, "/");
38201
38337
  const normalizedProject = projectConfigPath.replace(/\\/g, "/");
38202
38338
  try {
38203
- const resolvedConfig = path21.resolve(configPath);
38204
- const resolvedUser = path21.resolve(normalizedUser);
38205
- const resolvedProject = path21.resolve(normalizedProject);
38339
+ const resolvedConfig = path20.resolve(configPath);
38340
+ const resolvedUser = path20.resolve(normalizedUser);
38341
+ const resolvedProject = path20.resolve(normalizedProject);
38206
38342
  return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
38207
38343
  } catch {
38208
38344
  return false;
@@ -38242,12 +38378,12 @@ function createConfigBackup(directory) {
38242
38378
  };
38243
38379
  }
38244
38380
  function writeBackupArtifact(directory, backup) {
38245
- const swarmDir = path21.join(directory, ".swarm");
38381
+ const swarmDir = path20.join(directory, ".swarm");
38246
38382
  if (!fs8.existsSync(swarmDir)) {
38247
38383
  fs8.mkdirSync(swarmDir, { recursive: true });
38248
38384
  }
38249
38385
  const backupFilename = `config-backup-${backup.createdAt}.json`;
38250
- const backupPath = path21.join(swarmDir, backupFilename);
38386
+ const backupPath = path20.join(swarmDir, backupFilename);
38251
38387
  const artifact = {
38252
38388
  createdAt: backup.createdAt,
38253
38389
  configPath: backup.configPath,
@@ -38277,7 +38413,7 @@ function restoreFromBackup(backupPath, directory) {
38277
38413
  return null;
38278
38414
  }
38279
38415
  const targetPath = artifact.configPath;
38280
- const targetDir = path21.dirname(targetPath);
38416
+ const targetDir = path20.dirname(targetPath);
38281
38417
  if (!fs8.existsSync(targetDir)) {
38282
38418
  fs8.mkdirSync(targetDir, { recursive: true });
38283
38419
  }
@@ -38308,9 +38444,9 @@ function readConfigFromFile(directory) {
38308
38444
  return null;
38309
38445
  }
38310
38446
  }
38311
- function validateConfigKey(path22, value, _config) {
38447
+ function validateConfigKey(path21, value, _config) {
38312
38448
  const findings = [];
38313
- switch (path22) {
38449
+ switch (path21) {
38314
38450
  case "agents": {
38315
38451
  if (value !== undefined) {
38316
38452
  findings.push({
@@ -38557,27 +38693,27 @@ function validateConfigKey(path22, value, _config) {
38557
38693
  }
38558
38694
  return findings;
38559
38695
  }
38560
- function walkConfigAndValidate(obj, path22, config3, findings) {
38696
+ function walkConfigAndValidate(obj, path21, config3, findings) {
38561
38697
  if (obj === null || obj === undefined) {
38562
38698
  return;
38563
38699
  }
38564
- if (path22 && typeof obj === "object" && !Array.isArray(obj)) {
38565
- const keyFindings = validateConfigKey(path22, obj, config3);
38700
+ if (path21 && typeof obj === "object" && !Array.isArray(obj)) {
38701
+ const keyFindings = validateConfigKey(path21, obj, config3);
38566
38702
  findings.push(...keyFindings);
38567
38703
  }
38568
38704
  if (typeof obj !== "object") {
38569
- const keyFindings = validateConfigKey(path22, obj, config3);
38705
+ const keyFindings = validateConfigKey(path21, obj, config3);
38570
38706
  findings.push(...keyFindings);
38571
38707
  return;
38572
38708
  }
38573
38709
  if (Array.isArray(obj)) {
38574
38710
  obj.forEach((item, index) => {
38575
- walkConfigAndValidate(item, `${path22}[${index}]`, config3, findings);
38711
+ walkConfigAndValidate(item, `${path21}[${index}]`, config3, findings);
38576
38712
  });
38577
38713
  return;
38578
38714
  }
38579
38715
  for (const [key, value] of Object.entries(obj)) {
38580
- const newPath = path22 ? `${path22}.${key}` : key;
38716
+ const newPath = path21 ? `${path21}.${key}` : key;
38581
38717
  walkConfigAndValidate(value, newPath, config3, findings);
38582
38718
  }
38583
38719
  }
@@ -38697,7 +38833,7 @@ function applySafeAutoFixes(directory, result) {
38697
38833
  }
38698
38834
  }
38699
38835
  if (appliedFixes.length > 0) {
38700
- const configDir = path21.dirname(configPath);
38836
+ const configDir = path20.dirname(configPath);
38701
38837
  if (!fs8.existsSync(configDir)) {
38702
38838
  fs8.mkdirSync(configDir, { recursive: true });
38703
38839
  }
@@ -38707,12 +38843,12 @@ function applySafeAutoFixes(directory, result) {
38707
38843
  return { appliedFixes, updatedConfigPath };
38708
38844
  }
38709
38845
  function writeDoctorArtifact(directory, result) {
38710
- const swarmDir = path21.join(directory, ".swarm");
38846
+ const swarmDir = path20.join(directory, ".swarm");
38711
38847
  if (!fs8.existsSync(swarmDir)) {
38712
38848
  fs8.mkdirSync(swarmDir, { recursive: true });
38713
38849
  }
38714
38850
  const artifactFilename = "config-doctor.json";
38715
- const artifactPath = path21.join(swarmDir, artifactFilename);
38851
+ const artifactPath = path20.join(swarmDir, artifactFilename);
38716
38852
  const guiOutput = {
38717
38853
  timestamp: result.timestamp,
38718
38854
  summary: result.summary,
@@ -39815,7 +39951,7 @@ var init_detector = __esm(() => {
39815
39951
 
39816
39952
  // src/build/discovery.ts
39817
39953
  import * as fs9 from "fs";
39818
- import * as path22 from "path";
39954
+ import * as path21 from "path";
39819
39955
  function isCommandAvailable(command) {
39820
39956
  if (toolchainCache.has(command)) {
39821
39957
  return toolchainCache.get(command);
@@ -39847,11 +39983,11 @@ function findBuildFiles(workingDir, patterns) {
39847
39983
  const regex = simpleGlobToRegex(pattern);
39848
39984
  const matches = files.filter((f) => regex.test(f));
39849
39985
  if (matches.length > 0) {
39850
- return path22.join(dir, matches[0]);
39986
+ return path21.join(dir, matches[0]);
39851
39987
  }
39852
39988
  } catch {}
39853
39989
  } else {
39854
- const filePath = path22.join(workingDir, pattern);
39990
+ const filePath = path21.join(workingDir, pattern);
39855
39991
  if (fs9.existsSync(filePath)) {
39856
39992
  return filePath;
39857
39993
  }
@@ -39860,7 +39996,7 @@ function findBuildFiles(workingDir, patterns) {
39860
39996
  return null;
39861
39997
  }
39862
39998
  function getRepoDefinedScripts(workingDir, scripts) {
39863
- const packageJsonPath = path22.join(workingDir, "package.json");
39999
+ const packageJsonPath = path21.join(workingDir, "package.json");
39864
40000
  if (!fs9.existsSync(packageJsonPath)) {
39865
40001
  return [];
39866
40002
  }
@@ -39901,7 +40037,7 @@ function findAllBuildFiles(workingDir) {
39901
40037
  const regex = simpleGlobToRegex(pattern);
39902
40038
  findFilesRecursive(workingDir, regex, allBuildFiles);
39903
40039
  } else {
39904
- const filePath = path22.join(workingDir, pattern);
40040
+ const filePath = path21.join(workingDir, pattern);
39905
40041
  if (fs9.existsSync(filePath)) {
39906
40042
  allBuildFiles.add(filePath);
39907
40043
  }
@@ -39914,7 +40050,7 @@ function findFilesRecursive(dir, regex, results) {
39914
40050
  try {
39915
40051
  const entries = fs9.readdirSync(dir, { withFileTypes: true });
39916
40052
  for (const entry of entries) {
39917
- const fullPath = path22.join(dir, entry.name);
40053
+ const fullPath = path21.join(dir, entry.name);
39918
40054
  if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
39919
40055
  findFilesRecursive(fullPath, regex, results);
39920
40056
  } else if (entry.isFile() && regex.test(entry.name)) {
@@ -39937,7 +40073,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
39937
40073
  let foundCommand = false;
39938
40074
  for (const cmd of sortedCommands) {
39939
40075
  if (cmd.detectFile) {
39940
- const detectFilePath = path22.join(workingDir, cmd.detectFile);
40076
+ const detectFilePath = path21.join(workingDir, cmd.detectFile);
39941
40077
  if (!fs9.existsSync(detectFilePath)) {
39942
40078
  continue;
39943
40079
  }
@@ -39970,7 +40106,7 @@ async function discoverBuildCommands(workingDir, options) {
39970
40106
  const scope = options?.scope ?? "all";
39971
40107
  const changedFiles = options?.changedFiles ?? [];
39972
40108
  const _filesToCheck = filterByScope(workingDir, scope, changedFiles);
39973
- const profileResult = await _internals11.discoverBuildCommandsFromProfiles(workingDir);
40109
+ const profileResult = await _internals10.discoverBuildCommandsFromProfiles(workingDir);
39974
40110
  const profileCommands = profileResult.commands;
39975
40111
  const profileSkipped = profileResult.skipped;
39976
40112
  const coveredEcosystems = new Set;
@@ -40033,7 +40169,7 @@ function clearToolchainCache() {
40033
40169
  function getEcosystems() {
40034
40170
  return ECOSYSTEMS.map((e) => e.ecosystem);
40035
40171
  }
40036
- var ECOSYSTEMS, PROFILE_TO_ECOSYSTEM_NAMES, toolchainCache, _internals11, build_discovery;
40172
+ var ECOSYSTEMS, PROFILE_TO_ECOSYSTEM_NAMES, toolchainCache, _internals10, build_discovery;
40037
40173
  var init_discovery = __esm(() => {
40038
40174
  init_dist();
40039
40175
  init_detector();
@@ -40151,7 +40287,7 @@ var init_discovery = __esm(() => {
40151
40287
  php: ["php-composer"]
40152
40288
  };
40153
40289
  toolchainCache = new Map;
40154
- _internals11 = {
40290
+ _internals10 = {
40155
40291
  isCommandAvailable,
40156
40292
  discoverBuildCommandsFromProfiles,
40157
40293
  discoverBuildCommands,
@@ -40177,7 +40313,7 @@ var init_discovery = __esm(() => {
40177
40313
 
40178
40314
  // src/services/tool-doctor.ts
40179
40315
  import * as fs10 from "fs";
40180
- import * as path23 from "path";
40316
+ import * as path22 from "path";
40181
40317
  function extractRegisteredToolKeys(indexPath) {
40182
40318
  const registeredKeys = new Set;
40183
40319
  try {
@@ -40232,8 +40368,8 @@ function checkBinaryReadiness() {
40232
40368
  }
40233
40369
  function runToolDoctor(_directory, pluginRoot) {
40234
40370
  const findings = [];
40235
- const resolvedPluginRoot = pluginRoot ?? path23.resolve(import.meta.dir, "..", "..");
40236
- 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");
40237
40373
  if (!fs10.existsSync(indexPath)) {
40238
40374
  return {
40239
40375
  findings: [
@@ -40403,7 +40539,7 @@ var exports_evidence_summary_service = {};
40403
40539
  __export(exports_evidence_summary_service, {
40404
40540
  isAutoSummaryEnabled: () => isAutoSummaryEnabled,
40405
40541
  buildEvidenceSummary: () => buildEvidenceSummary,
40406
- _internals: () => _internals12,
40542
+ _internals: () => _internals11,
40407
40543
  REQUIRED_EVIDENCE_TYPES: () => REQUIRED_EVIDENCE_TYPES,
40408
40544
  EVIDENCE_SUMMARY_VERSION: () => EVIDENCE_SUMMARY_VERSION
40409
40545
  });
@@ -40441,14 +40577,14 @@ function getTaskStatus(task, bundle) {
40441
40577
  if (task?.status) {
40442
40578
  return task.status;
40443
40579
  }
40444
- const entries = _internals12.normalizeBundleEntries(bundle);
40580
+ const entries = _internals11.normalizeBundleEntries(bundle);
40445
40581
  if (entries.length > 0) {
40446
40582
  return "completed";
40447
40583
  }
40448
40584
  return "pending";
40449
40585
  }
40450
40586
  function isEvidenceComplete(bundle) {
40451
- const entries = _internals12.normalizeBundleEntries(bundle);
40587
+ const entries = _internals11.normalizeBundleEntries(bundle);
40452
40588
  if (entries.length === 0) {
40453
40589
  return {
40454
40590
  isComplete: false,
@@ -40484,10 +40620,10 @@ async function buildTaskSummary(directory, task, taskId) {
40484
40620
  const result = await loadEvidence(directory, taskId);
40485
40621
  const bundle = result.status === "found" ? result.bundle : null;
40486
40622
  const phase = task?.phase ?? 0;
40487
- const status = _internals12.getTaskStatus(task, bundle);
40488
- const evidenceCheck = _internals12.isEvidenceComplete(bundle);
40489
- const blockers = _internals12.getTaskBlockers(task, evidenceCheck, status);
40490
- 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);
40491
40627
  const hasReview = entries.some((e) => e.type === "review");
40492
40628
  const hasTest = entries.some((e) => e.type === "test");
40493
40629
  const hasApproval = entries.some((e) => e.type === "approval");
@@ -40516,12 +40652,12 @@ async function buildPhaseSummary(directory, phase) {
40516
40652
  const taskSummaries = [];
40517
40653
  const _taskMap = new Map(phase.tasks.map((t) => [t.id, t]));
40518
40654
  for (const task of phase.tasks) {
40519
- const summary = await _internals12.buildTaskSummary(directory, task, task.id);
40655
+ const summary = await _internals11.buildTaskSummary(directory, task, task.id);
40520
40656
  taskSummaries.push(summary);
40521
40657
  }
40522
40658
  const extraTaskIds = taskIds.filter((id) => !phaseTaskIds.has(id));
40523
40659
  for (const taskId of extraTaskIds) {
40524
- const summary = await _internals12.buildTaskSummary(directory, undefined, taskId);
40660
+ const summary = await _internals11.buildTaskSummary(directory, undefined, taskId);
40525
40661
  if (summary.phase === phase.id) {
40526
40662
  taskSummaries.push(summary);
40527
40663
  }
@@ -40622,7 +40758,7 @@ async function buildEvidenceSummary(directory, currentPhase) {
40622
40758
  let totalTasks = 0;
40623
40759
  let completedTasks = 0;
40624
40760
  for (const phase of phasesToProcess) {
40625
- const summary = await _internals12.buildPhaseSummary(directory, phase);
40761
+ const summary = await _internals11.buildPhaseSummary(directory, phase);
40626
40762
  phaseSummaries.push(summary);
40627
40763
  totalTasks += summary.totalTasks;
40628
40764
  completedTasks += summary.completedTasks;
@@ -40644,7 +40780,7 @@ async function buildEvidenceSummary(directory, currentPhase) {
40644
40780
  overallBlockers,
40645
40781
  summaryText: ""
40646
40782
  };
40647
- artifact.summaryText = _internals12.generateSummaryText(artifact);
40783
+ artifact.summaryText = _internals11.generateSummaryText(artifact);
40648
40784
  log("[EvidenceSummary] Summary built", {
40649
40785
  phases: phaseSummaries.length,
40650
40786
  totalTasks,
@@ -40663,7 +40799,7 @@ function isAutoSummaryEnabled(automationConfig) {
40663
40799
  }
40664
40800
  return automationConfig.capabilities?.evidence_auto_summaries === true;
40665
40801
  }
40666
- 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;
40667
40803
  var init_evidence_summary_service = __esm(() => {
40668
40804
  init_manager2();
40669
40805
  init_manager();
@@ -40677,7 +40813,7 @@ var init_evidence_summary_service = __esm(() => {
40677
40813
  "retrospective"
40678
40814
  ]);
40679
40815
  REQUIRED_EVIDENCE_TYPES = ["review", "test"];
40680
- _internals12 = {
40816
+ _internals11 = {
40681
40817
  buildEvidenceSummary,
40682
40818
  isAutoSummaryEnabled,
40683
40819
  normalizeBundleEntries,
@@ -40924,12 +41060,12 @@ var init_export = __esm(() => {
40924
41060
 
40925
41061
  // src/full-auto/state.ts
40926
41062
  import * as fs11 from "fs";
40927
- import * as path24 from "path";
41063
+ import * as path23 from "path";
40928
41064
  function nowISO() {
40929
41065
  return new Date().toISOString();
40930
41066
  }
40931
41067
  function ensureSwarmDir(directory) {
40932
- const swarmDir = path24.resolve(directory, ".swarm");
41068
+ const swarmDir = path23.resolve(directory, ".swarm");
40933
41069
  if (!fs11.existsSync(swarmDir)) {
40934
41070
  fs11.mkdirSync(swarmDir, { recursive: true });
40935
41071
  }
@@ -41280,7 +41416,7 @@ function extractCurrentPhaseFromPlan2(plan) {
41280
41416
  if (!plan) {
41281
41417
  return { currentPhase: null, currentTask: null, incompleteTasks: [] };
41282
41418
  }
41283
- if (!_internals13.validatePlanPhases(plan)) {
41419
+ if (!_internals12.validatePlanPhases(plan)) {
41284
41420
  return { currentPhase: null, currentTask: null, incompleteTasks: [] };
41285
41421
  }
41286
41422
  let currentPhase = null;
@@ -41422,9 +41558,9 @@ function extractPhaseMetrics(content) {
41422
41558
  async function getHandoffData(directory) {
41423
41559
  const now = new Date().toISOString();
41424
41560
  const sessionContent = await readSwarmFileAsync(directory, "session/state.json");
41425
- const sessionState = _internals13.parseSessionState(sessionContent);
41561
+ const sessionState = _internals12.parseSessionState(sessionContent);
41426
41562
  const plan = await loadPlanJsonOnly(directory);
41427
- const planInfo = _internals13.extractCurrentPhaseFromPlan(plan);
41563
+ const planInfo = _internals12.extractCurrentPhaseFromPlan(plan);
41428
41564
  if (!plan) {
41429
41565
  const planMdContent = await readSwarmFileAsync(directory, "plan.md");
41430
41566
  if (planMdContent) {
@@ -41443,8 +41579,8 @@ async function getHandoffData(directory) {
41443
41579
  }
41444
41580
  }
41445
41581
  const contextContent = await readSwarmFileAsync(directory, "context.md");
41446
- const recentDecisions = _internals13.extractDecisions(contextContent);
41447
- const rawPhaseMetrics = _internals13.extractPhaseMetrics(contextContent);
41582
+ const recentDecisions = _internals12.extractDecisions(contextContent);
41583
+ const rawPhaseMetrics = _internals12.extractPhaseMetrics(contextContent);
41448
41584
  const phaseMetrics = sanitizeString(rawPhaseMetrics, 1000);
41449
41585
  let delegationState = null;
41450
41586
  if (sessionState?.delegationState) {
@@ -41608,13 +41744,13 @@ ${lines.join(`
41608
41744
  `)}
41609
41745
  \`\`\``;
41610
41746
  }
41611
- 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;
41612
41748
  var init_handoff_service = __esm(() => {
41613
41749
  init_utils2();
41614
41750
  init_manager();
41615
41751
  init_utils();
41616
41752
  RTL_OVERRIDE_PATTERN = /[\u202e\u202d\u202c\u200f]/g;
41617
- _internals13 = {
41753
+ _internals12 = {
41618
41754
  getHandoffData,
41619
41755
  formatHandoffMarkdown,
41620
41756
  formatContinuationPrompt,
@@ -41628,6 +41764,133 @@ var init_handoff_service = __esm(() => {
41628
41764
  };
41629
41765
  });
41630
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
+
41631
41894
  // src/commands/handoff.ts
41632
41895
  import crypto4 from "crypto";
41633
41896
  import { renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
@@ -47772,7 +48035,7 @@ async function handleSimulateCommand(directory, args) {
47772
48035
  }
47773
48036
  let darkMatterPairs;
47774
48037
  try {
47775
- darkMatterPairs = await _internals10.detectDarkMatter(directory, options);
48038
+ darkMatterPairs = await _internals9.detectDarkMatter(directory, options);
47776
48039
  } catch (err) {
47777
48040
  const errMsg = err instanceof Error ? err.message : String(err);
47778
48041
  return `## Simulate Report