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