opencode-swarm-plugin 0.48.1 → 0.49.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/README.md +10 -7
- package/bin/swarm-setup-consolidate.test.ts +84 -0
- package/bin/swarm.test.ts +170 -0
- package/bin/swarm.ts +300 -2
- package/bin/test-setup-manual.md +67 -0
- package/dist/bin/swarm.js +1035 -184
- package/dist/coordinator-guard.d.ts +79 -0
- package/dist/coordinator-guard.d.ts.map +1 -0
- package/dist/examples/plugin-wrapper-template.ts +13 -2
- package/dist/hive.d.ts.map +1 -1
- package/dist/hive.js +5 -4
- package/dist/index.d.ts +18 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +376 -16
- package/dist/memory.d.ts.map +1 -1
- package/dist/plugin.js +373 -16
- package/dist/query-tools.d.ts +5 -0
- package/dist/query-tools.d.ts.map +1 -1
- package/dist/schemas/cell.d.ts +12 -0
- package/dist/schemas/cell.d.ts.map +1 -1
- package/dist/swarm-insights.d.ts +158 -0
- package/dist/swarm-insights.d.ts.map +1 -1
- package/dist/swarm-orchestrate.d.ts +4 -4
- package/dist/swarm-prompts.d.ts +1 -1
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-prompts.js +335 -16
- package/dist/swarm-strategies.d.ts +1 -1
- package/dist/swarm.d.ts +2 -2
- package/examples/plugin-wrapper-template.ts +13 -2
- package/package.json +2 -2
package/dist/bin/swarm.js
CHANGED
|
@@ -26930,7 +26930,7 @@ __export(exports_skills2, {
|
|
|
26930
26930
|
});
|
|
26931
26931
|
import { readdir as readdir2, readFile as readFile2, stat as stat2, mkdir as mkdir2, writeFile as writeFile2, rm as rm2 } from "fs/promises";
|
|
26932
26932
|
import {
|
|
26933
|
-
join as
|
|
26933
|
+
join as join17,
|
|
26934
26934
|
basename as basename2,
|
|
26935
26935
|
dirname as dirname8,
|
|
26936
26936
|
resolve as resolve2,
|
|
@@ -27006,19 +27006,19 @@ function validateSkillMetadata2(raw, filePath) {
|
|
|
27006
27006
|
}
|
|
27007
27007
|
function getGlobalSkillsDir2() {
|
|
27008
27008
|
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
27009
|
-
return
|
|
27009
|
+
return join17(home, ".config", "opencode", "skill");
|
|
27010
27010
|
}
|
|
27011
27011
|
function getClaudeGlobalSkillsDir2() {
|
|
27012
27012
|
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
27013
|
-
return
|
|
27013
|
+
return join17(home, ".claude", "skills");
|
|
27014
27014
|
}
|
|
27015
27015
|
function getPackageSkillsDir2() {
|
|
27016
27016
|
try {
|
|
27017
27017
|
const currentFilePath = fileURLToPath2(import.meta.url);
|
|
27018
|
-
return
|
|
27018
|
+
return join17(dirname8(currentFilePath), "..", "global-skills");
|
|
27019
27019
|
} catch {
|
|
27020
27020
|
const currentDir = decodeURIComponent(new URL(".", import.meta.url).pathname);
|
|
27021
|
-
return
|
|
27021
|
+
return join17(currentDir, "..", "global-skills");
|
|
27022
27022
|
}
|
|
27023
27023
|
}
|
|
27024
27024
|
async function findSkillFiles2(baseDir) {
|
|
@@ -27027,7 +27027,7 @@ async function findSkillFiles2(baseDir) {
|
|
|
27027
27027
|
const entries = await readdir2(baseDir, { withFileTypes: true });
|
|
27028
27028
|
for (const entry of entries) {
|
|
27029
27029
|
if (entry.isDirectory()) {
|
|
27030
|
-
const skillPath =
|
|
27030
|
+
const skillPath = join17(baseDir, entry.name, "SKILL.md");
|
|
27031
27031
|
try {
|
|
27032
27032
|
const s = await stat2(skillPath);
|
|
27033
27033
|
if (s.isFile()) {
|
|
@@ -27041,7 +27041,7 @@ async function findSkillFiles2(baseDir) {
|
|
|
27041
27041
|
}
|
|
27042
27042
|
async function findSkillScripts2(skillDir) {
|
|
27043
27043
|
const scripts = [];
|
|
27044
|
-
const scriptsDir =
|
|
27044
|
+
const scriptsDir = join17(skillDir, "scripts");
|
|
27045
27045
|
try {
|
|
27046
27046
|
const entries = await readdir2(scriptsDir, { withFileTypes: true });
|
|
27047
27047
|
for (const entry of entries) {
|
|
@@ -27089,7 +27089,7 @@ async function discoverSkills2(projectDir) {
|
|
|
27089
27089
|
}
|
|
27090
27090
|
}
|
|
27091
27091
|
for (const relPath of PROJECT_SKILL_DIRECTORIES2) {
|
|
27092
|
-
await loadSkillsFromDir(
|
|
27092
|
+
await loadSkillsFromDir(join17(dir, relPath));
|
|
27093
27093
|
}
|
|
27094
27094
|
await loadSkillsFromDir(getGlobalSkillsDir2());
|
|
27095
27095
|
await loadSkillsFromDir(getClaudeGlobalSkillsDir2());
|
|
@@ -27460,7 +27460,7 @@ Scripts run in the skill's directory with the project directory as an argument.`
|
|
|
27460
27460
|
if (!skill.scripts.includes(args2.script)) {
|
|
27461
27461
|
return `Script '${args2.script}' not found in skill '${args2.skill}'. Available: ${skill.scripts.join(", ") || "none"}`;
|
|
27462
27462
|
}
|
|
27463
|
-
const scriptPath =
|
|
27463
|
+
const scriptPath = join17(skill.directory, "scripts", args2.script);
|
|
27464
27464
|
const scriptArgs = args2.args || [];
|
|
27465
27465
|
try {
|
|
27466
27466
|
const TIMEOUT_MS = 60000;
|
|
@@ -27569,14 +27569,14 @@ Good skills have:
|
|
|
27569
27569
|
const csoWarnings = validateCSOCompliance2(args2.name, args2.description);
|
|
27570
27570
|
let skillDir;
|
|
27571
27571
|
if (args2.directory === "global") {
|
|
27572
|
-
skillDir =
|
|
27572
|
+
skillDir = join17(getGlobalSkillsDir2(), args2.name);
|
|
27573
27573
|
} else if (args2.directory === "global-claude") {
|
|
27574
|
-
skillDir =
|
|
27574
|
+
skillDir = join17(getClaudeGlobalSkillsDir2(), args2.name);
|
|
27575
27575
|
} else {
|
|
27576
27576
|
const baseDir = args2.directory || DEFAULT_SKILLS_DIR2;
|
|
27577
|
-
skillDir =
|
|
27577
|
+
skillDir = join17(skillsProjectDirectory2, baseDir, args2.name);
|
|
27578
27578
|
}
|
|
27579
|
-
const skillPath =
|
|
27579
|
+
const skillPath = join17(skillDir, "SKILL.md");
|
|
27580
27580
|
try {
|
|
27581
27581
|
await mkdir2(skillDir, { recursive: true });
|
|
27582
27582
|
const content = generateSkillContent2(args2.name, args2.description, args2.body, { tags: args2.tags, tools: args2.tools });
|
|
@@ -27733,8 +27733,8 @@ executed with skills_execute. Use for:
|
|
|
27733
27733
|
if (isAbsolute2(args2.script_name) || args2.script_name.includes("..") || args2.script_name.includes("/") || args2.script_name.includes("\\") || basename2(args2.script_name) !== args2.script_name) {
|
|
27734
27734
|
return "Invalid script name. Use simple filenames without paths.";
|
|
27735
27735
|
}
|
|
27736
|
-
const scriptsDir =
|
|
27737
|
-
const scriptPath =
|
|
27736
|
+
const scriptsDir = join17(skill.directory, "scripts");
|
|
27737
|
+
const scriptPath = join17(scriptsDir, args2.script_name);
|
|
27738
27738
|
try {
|
|
27739
27739
|
await mkdir2(scriptsDir, { recursive: true });
|
|
27740
27740
|
await writeFile2(scriptPath, args2.content, {
|
|
@@ -27783,20 +27783,20 @@ Perfect for learning to create effective skills.`,
|
|
|
27783
27783
|
}
|
|
27784
27784
|
let skillDir;
|
|
27785
27785
|
if (args2.directory === "global") {
|
|
27786
|
-
skillDir =
|
|
27786
|
+
skillDir = join17(getGlobalSkillsDir2(), args2.name);
|
|
27787
27787
|
} else {
|
|
27788
27788
|
const baseDir = args2.directory || DEFAULT_SKILLS_DIR2;
|
|
27789
|
-
skillDir =
|
|
27789
|
+
skillDir = join17(skillsProjectDirectory2, baseDir, args2.name);
|
|
27790
27790
|
}
|
|
27791
27791
|
const createdFiles = [];
|
|
27792
27792
|
try {
|
|
27793
27793
|
await mkdir2(skillDir, { recursive: true });
|
|
27794
|
-
const skillPath =
|
|
27794
|
+
const skillPath = join17(skillDir, "SKILL.md");
|
|
27795
27795
|
const skillContent = generateSkillTemplate2(args2.name, args2.description);
|
|
27796
27796
|
await writeFile2(skillPath, skillContent, "utf-8");
|
|
27797
27797
|
createdFiles.push("SKILL.md");
|
|
27798
27798
|
if (args2.include_example_script !== false) {
|
|
27799
|
-
const scriptsDir =
|
|
27799
|
+
const scriptsDir = join17(skillDir, "scripts");
|
|
27800
27800
|
await mkdir2(scriptsDir, { recursive: true });
|
|
27801
27801
|
const exampleScript = `#!/usr/bin/env bash
|
|
27802
27802
|
# Example helper script for ${args2.name}
|
|
@@ -27810,15 +27810,15 @@ echo "Project directory: $1"
|
|
|
27810
27810
|
|
|
27811
27811
|
# TODO: Add actual script logic
|
|
27812
27812
|
`;
|
|
27813
|
-
const scriptPath =
|
|
27813
|
+
const scriptPath = join17(scriptsDir, "example.sh");
|
|
27814
27814
|
await writeFile2(scriptPath, exampleScript, { mode: 493 });
|
|
27815
27815
|
createdFiles.push("scripts/example.sh");
|
|
27816
27816
|
}
|
|
27817
27817
|
if (args2.include_reference !== false) {
|
|
27818
|
-
const refsDir =
|
|
27818
|
+
const refsDir = join17(skillDir, "references");
|
|
27819
27819
|
await mkdir2(refsDir, { recursive: true });
|
|
27820
27820
|
const refContent = generateReferenceTemplate2(args2.name);
|
|
27821
|
-
const refPath =
|
|
27821
|
+
const refPath = join17(refsDir, "guide.md");
|
|
27822
27822
|
await writeFile2(refPath, refContent, "utf-8");
|
|
27823
27823
|
createdFiles.push("references/guide.md");
|
|
27824
27824
|
}
|
|
@@ -27874,11 +27874,16 @@ echo "Project directory: $1"
|
|
|
27874
27874
|
// src/swarm-insights.ts
|
|
27875
27875
|
var exports_swarm_insights2 = {};
|
|
27876
27876
|
__export(exports_swarm_insights2, {
|
|
27877
|
+
trackCoordinatorViolation: () => trackCoordinatorViolation2,
|
|
27878
|
+
getViolationAnalytics: () => getViolationAnalytics2,
|
|
27877
27879
|
getStrategyInsights: () => getStrategyInsights2,
|
|
27880
|
+
getRejectionAnalytics: () => getRejectionAnalytics3,
|
|
27878
27881
|
getPatternInsights: () => getPatternInsights2,
|
|
27879
27882
|
getFileInsights: () => getFileInsights2,
|
|
27883
|
+
getFileFailureHistory: () => getFileFailureHistory2,
|
|
27880
27884
|
getCachedInsights: () => getCachedInsights2,
|
|
27881
27885
|
formatInsightsForPrompt: () => formatInsightsForPrompt2,
|
|
27886
|
+
formatFileHistoryWarnings: () => formatFileHistoryWarnings2,
|
|
27882
27887
|
clearInsightsCache: () => clearInsightsCache2
|
|
27883
27888
|
});
|
|
27884
27889
|
async function getStrategyInsights2(swarmMail, _task) {
|
|
@@ -27950,6 +27955,136 @@ async function getFileInsights2(swarmMail, files) {
|
|
|
27950
27955
|
async function getFileGotchas2(_swarmMail, _file4) {
|
|
27951
27956
|
return [];
|
|
27952
27957
|
}
|
|
27958
|
+
async function getFileFailureHistory2(swarmMail, files) {
|
|
27959
|
+
if (files.length === 0)
|
|
27960
|
+
return [];
|
|
27961
|
+
const db = await swarmMail.getDatabase();
|
|
27962
|
+
const histories = [];
|
|
27963
|
+
for (const file4 of files) {
|
|
27964
|
+
const query = `
|
|
27965
|
+
SELECT data
|
|
27966
|
+
FROM events
|
|
27967
|
+
WHERE type = 'review_feedback'
|
|
27968
|
+
AND json_extract(data, '$.status') = 'needs_changes'
|
|
27969
|
+
AND json_extract(data, '$.issues') LIKE ?
|
|
27970
|
+
`;
|
|
27971
|
+
const result = await db.query(query, [`%${file4}%`]);
|
|
27972
|
+
if (!result.rows || result.rows.length === 0) {
|
|
27973
|
+
continue;
|
|
27974
|
+
}
|
|
27975
|
+
const issueTexts = [];
|
|
27976
|
+
for (const row of result.rows) {
|
|
27977
|
+
try {
|
|
27978
|
+
const data = JSON.parse(row.data);
|
|
27979
|
+
const issuesStr = data.issues;
|
|
27980
|
+
if (!issuesStr)
|
|
27981
|
+
continue;
|
|
27982
|
+
const issues = JSON.parse(issuesStr);
|
|
27983
|
+
for (const issue4 of issues) {
|
|
27984
|
+
if (issue4.file === file4) {
|
|
27985
|
+
issueTexts.push(issue4.issue);
|
|
27986
|
+
}
|
|
27987
|
+
}
|
|
27988
|
+
} catch (e) {
|
|
27989
|
+
continue;
|
|
27990
|
+
}
|
|
27991
|
+
}
|
|
27992
|
+
if (issueTexts.length === 0) {
|
|
27993
|
+
continue;
|
|
27994
|
+
}
|
|
27995
|
+
const issueCounts = new Map;
|
|
27996
|
+
for (const text of issueTexts) {
|
|
27997
|
+
issueCounts.set(text, (issueCounts.get(text) || 0) + 1);
|
|
27998
|
+
}
|
|
27999
|
+
const topIssues = Array.from(issueCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 3).map(([text]) => text);
|
|
28000
|
+
histories.push({
|
|
28001
|
+
file: file4,
|
|
28002
|
+
rejectionCount: issueTexts.length,
|
|
28003
|
+
topIssues
|
|
28004
|
+
});
|
|
28005
|
+
}
|
|
28006
|
+
return histories;
|
|
28007
|
+
}
|
|
28008
|
+
async function getRejectionAnalytics3(swarmMail) {
|
|
28009
|
+
const db = await swarmMail.getDatabase();
|
|
28010
|
+
const query = `
|
|
28011
|
+
SELECT data
|
|
28012
|
+
FROM events
|
|
28013
|
+
WHERE type = 'review_feedback'
|
|
28014
|
+
ORDER BY timestamp DESC
|
|
28015
|
+
`;
|
|
28016
|
+
const result = await db.query(query, []);
|
|
28017
|
+
if (!result.rows || result.rows.length === 0) {
|
|
28018
|
+
return {
|
|
28019
|
+
totalReviews: 0,
|
|
28020
|
+
approved: 0,
|
|
28021
|
+
rejected: 0,
|
|
28022
|
+
approvalRate: 0,
|
|
28023
|
+
topReasons: []
|
|
28024
|
+
};
|
|
28025
|
+
}
|
|
28026
|
+
let approved = 0;
|
|
28027
|
+
let rejected = 0;
|
|
28028
|
+
const reasonCounts = new Map;
|
|
28029
|
+
for (const row of result.rows) {
|
|
28030
|
+
try {
|
|
28031
|
+
const data = JSON.parse(row.data);
|
|
28032
|
+
if (data.status === "approved") {
|
|
28033
|
+
approved++;
|
|
28034
|
+
} else if (data.status === "needs_changes") {
|
|
28035
|
+
rejected++;
|
|
28036
|
+
if (data.issues) {
|
|
28037
|
+
const issues = JSON.parse(data.issues);
|
|
28038
|
+
for (const issue4 of issues) {
|
|
28039
|
+
const category = categorizeRejectionReason3(issue4.issue);
|
|
28040
|
+
reasonCounts.set(category, (reasonCounts.get(category) || 0) + 1);
|
|
28041
|
+
}
|
|
28042
|
+
}
|
|
28043
|
+
}
|
|
28044
|
+
} catch (e) {
|
|
28045
|
+
continue;
|
|
28046
|
+
}
|
|
28047
|
+
}
|
|
28048
|
+
const totalReviews = approved + rejected;
|
|
28049
|
+
const approvalRate = totalReviews > 0 ? approved / totalReviews * 100 : 0;
|
|
28050
|
+
const topReasons = Array.from(reasonCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([category, count]) => ({
|
|
28051
|
+
category,
|
|
28052
|
+
count,
|
|
28053
|
+
percentage: rejected > 0 ? count / rejected * 100 : 0
|
|
28054
|
+
}));
|
|
28055
|
+
return {
|
|
28056
|
+
totalReviews,
|
|
28057
|
+
approved,
|
|
28058
|
+
rejected,
|
|
28059
|
+
approvalRate,
|
|
28060
|
+
topReasons
|
|
28061
|
+
};
|
|
28062
|
+
}
|
|
28063
|
+
function categorizeRejectionReason3(reason) {
|
|
28064
|
+
const lowerReason = reason.toLowerCase();
|
|
28065
|
+
if (lowerReason.includes("test") || lowerReason.includes("spec") || lowerReason.includes("coverage")) {
|
|
28066
|
+
return "Missing tests";
|
|
28067
|
+
}
|
|
28068
|
+
if (lowerReason.includes("type") || lowerReason.includes("undefined") || lowerReason.includes("null") || lowerReason.includes("assignable")) {
|
|
28069
|
+
return "Type errors";
|
|
28070
|
+
}
|
|
28071
|
+
if (lowerReason.includes("incomplete") || lowerReason.includes("missing") || lowerReason.includes("forgot") || lowerReason.includes("didn't implement")) {
|
|
28072
|
+
return "Incomplete implementation";
|
|
28073
|
+
}
|
|
28074
|
+
if (lowerReason.includes("wrong file") || lowerReason.includes("modified incorrect") || lowerReason.includes("shouldn't have changed")) {
|
|
28075
|
+
return "Wrong file modified";
|
|
28076
|
+
}
|
|
28077
|
+
if (lowerReason.includes("performance") || lowerReason.includes("slow") || lowerReason.includes("inefficient")) {
|
|
28078
|
+
return "Performance issue";
|
|
28079
|
+
}
|
|
28080
|
+
if (lowerReason.includes("security") || lowerReason.includes("vulnerability") || lowerReason.includes("unsafe")) {
|
|
28081
|
+
return "Security vulnerability";
|
|
28082
|
+
}
|
|
28083
|
+
if (lowerReason.includes("error handling") || lowerReason.includes("try/catch") || lowerReason.includes("exception")) {
|
|
28084
|
+
return "Missing error handling";
|
|
28085
|
+
}
|
|
28086
|
+
return "Other";
|
|
28087
|
+
}
|
|
27953
28088
|
async function getPatternInsights2(swarmMail) {
|
|
27954
28089
|
const db = await swarmMail.getDatabase();
|
|
27955
28090
|
const patterns = [];
|
|
@@ -28023,24 +28158,125 @@ ${patternLines.join(`
|
|
|
28023
28158
|
return result;
|
|
28024
28159
|
}
|
|
28025
28160
|
async function getCachedInsights2(_swarmMail, cacheKey, computeFn) {
|
|
28026
|
-
const cached6 =
|
|
28161
|
+
const cached6 = insightsCache3.get(cacheKey);
|
|
28027
28162
|
if (cached6 && cached6.expires > Date.now()) {
|
|
28028
28163
|
return cached6.data;
|
|
28029
28164
|
}
|
|
28030
28165
|
const data = await computeFn();
|
|
28031
|
-
|
|
28166
|
+
insightsCache3.set(cacheKey, {
|
|
28032
28167
|
data,
|
|
28033
|
-
expires: Date.now() +
|
|
28168
|
+
expires: Date.now() + CACHE_TTL_MS3
|
|
28034
28169
|
});
|
|
28035
28170
|
return data;
|
|
28036
28171
|
}
|
|
28037
28172
|
function clearInsightsCache2() {
|
|
28038
|
-
|
|
28173
|
+
insightsCache3.clear();
|
|
28174
|
+
}
|
|
28175
|
+
async function trackCoordinatorViolation2(swarmMail, violation) {
|
|
28176
|
+
const db = await swarmMail.getDatabase();
|
|
28177
|
+
const query = `
|
|
28178
|
+
INSERT INTO events (type, project_key, timestamp, data)
|
|
28179
|
+
VALUES (?, ?, ?, ?)
|
|
28180
|
+
RETURNING id
|
|
28181
|
+
`;
|
|
28182
|
+
const data = JSON.stringify({
|
|
28183
|
+
session_id: violation.session_id,
|
|
28184
|
+
epic_id: violation.epic_id,
|
|
28185
|
+
event_type: "VIOLATION",
|
|
28186
|
+
violation_type: violation.violation_type,
|
|
28187
|
+
payload: violation.payload
|
|
28188
|
+
});
|
|
28189
|
+
const result = await db.query(query, [
|
|
28190
|
+
"coordinator_violation",
|
|
28191
|
+
violation.project_key,
|
|
28192
|
+
Date.now(),
|
|
28193
|
+
data
|
|
28194
|
+
]);
|
|
28195
|
+
return result.rows[0].id;
|
|
28196
|
+
}
|
|
28197
|
+
async function getViolationAnalytics2(swarmMail, projectKey) {
|
|
28198
|
+
const db = await swarmMail.getDatabase();
|
|
28199
|
+
const violationsQuery = projectKey ? `
|
|
28200
|
+
SELECT data
|
|
28201
|
+
FROM events
|
|
28202
|
+
WHERE type = 'coordinator_violation'
|
|
28203
|
+
AND project_key = ?
|
|
28204
|
+
ORDER BY timestamp DESC
|
|
28205
|
+
` : `
|
|
28206
|
+
SELECT data
|
|
28207
|
+
FROM events
|
|
28208
|
+
WHERE type = 'coordinator_violation'
|
|
28209
|
+
ORDER BY timestamp DESC
|
|
28210
|
+
`;
|
|
28211
|
+
const params = projectKey ? [projectKey] : [];
|
|
28212
|
+
const result = await db.query(violationsQuery, params);
|
|
28213
|
+
if (!result.rows || result.rows.length === 0) {
|
|
28214
|
+
return {
|
|
28215
|
+
totalViolations: 0,
|
|
28216
|
+
byType: [],
|
|
28217
|
+
violationRate: 0
|
|
28218
|
+
};
|
|
28219
|
+
}
|
|
28220
|
+
const violationCounts = new Map;
|
|
28221
|
+
let totalViolations = 0;
|
|
28222
|
+
for (const row of result.rows) {
|
|
28223
|
+
try {
|
|
28224
|
+
const data = JSON.parse(row.data);
|
|
28225
|
+
const violationType = data.violation_type;
|
|
28226
|
+
if (violationType) {
|
|
28227
|
+
violationCounts.set(violationType, (violationCounts.get(violationType) || 0) + 1);
|
|
28228
|
+
totalViolations++;
|
|
28229
|
+
}
|
|
28230
|
+
} catch (e) {
|
|
28231
|
+
continue;
|
|
28232
|
+
}
|
|
28233
|
+
}
|
|
28234
|
+
const byType = Array.from(violationCounts.entries()).sort((a, b) => b[1] - a[1]).map(([violationType, count]) => ({
|
|
28235
|
+
violationType,
|
|
28236
|
+
count,
|
|
28237
|
+
percentage: count / totalViolations * 100
|
|
28238
|
+
}));
|
|
28239
|
+
const coordinationQuery = projectKey ? `
|
|
28240
|
+
SELECT COUNT(*) as count
|
|
28241
|
+
FROM events
|
|
28242
|
+
WHERE type IN ('worker_spawned', 'review_feedback', 'message_sent')
|
|
28243
|
+
AND project_key = ?
|
|
28244
|
+
` : `
|
|
28245
|
+
SELECT COUNT(*) as count
|
|
28246
|
+
FROM events
|
|
28247
|
+
WHERE type IN ('worker_spawned', 'review_feedback', 'message_sent')
|
|
28248
|
+
`;
|
|
28249
|
+
const coordResult = await db.query(coordinationQuery, params);
|
|
28250
|
+
const coordinationCount = coordResult.rows[0]?.count || 0;
|
|
28251
|
+
const violationRate = coordinationCount > 0 ? totalViolations / coordinationCount * 100 : 0;
|
|
28252
|
+
return {
|
|
28253
|
+
totalViolations,
|
|
28254
|
+
byType,
|
|
28255
|
+
violationRate
|
|
28256
|
+
};
|
|
28039
28257
|
}
|
|
28040
|
-
|
|
28258
|
+
function formatFileHistoryWarnings2(histories) {
|
|
28259
|
+
if (histories.length === 0) {
|
|
28260
|
+
return "";
|
|
28261
|
+
}
|
|
28262
|
+
const lines = ["⚠️ FILE HISTORY WARNINGS:"];
|
|
28263
|
+
for (const history of histories) {
|
|
28264
|
+
const workerText = history.rejectionCount === 1 ? "1 previous worker rejected" : `${history.rejectionCount} previous workers rejected`;
|
|
28265
|
+
const issuesText = history.topIssues.join(", ");
|
|
28266
|
+
lines.push(`- ${history.file}: ${workerText} for ${issuesText}`);
|
|
28267
|
+
}
|
|
28268
|
+
let result = lines.join(`
|
|
28269
|
+
`);
|
|
28270
|
+
const maxChars = 300 * 4;
|
|
28271
|
+
if (result.length > maxChars) {
|
|
28272
|
+
result = result.slice(0, maxChars - 3) + "...";
|
|
28273
|
+
}
|
|
28274
|
+
return result;
|
|
28275
|
+
}
|
|
28276
|
+
var insightsCache3, CACHE_TTL_MS3;
|
|
28041
28277
|
var init_swarm_insights2 = __esm(() => {
|
|
28042
|
-
|
|
28043
|
-
|
|
28278
|
+
insightsCache3 = new Map;
|
|
28279
|
+
CACHE_TTL_MS3 = 5 * 60 * 1000;
|
|
28044
28280
|
});
|
|
28045
28281
|
|
|
28046
28282
|
// src/model-selection.ts
|
|
@@ -39175,8 +39411,8 @@ import {
|
|
|
39175
39411
|
statSync as statSync2,
|
|
39176
39412
|
writeFileSync as writeFileSync7
|
|
39177
39413
|
} from "fs";
|
|
39178
|
-
import { homedir as
|
|
39179
|
-
import { basename as basename3, dirname as dirname9, join as
|
|
39414
|
+
import { homedir as homedir10 } from "os";
|
|
39415
|
+
import { basename as basename3, dirname as dirname9, join as join28 } from "path";
|
|
39180
39416
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
39181
39417
|
|
|
39182
39418
|
// dist/hive.js
|
|
@@ -52662,7 +52898,8 @@ var CellTreeSchema = exports_external.object({
|
|
|
52662
52898
|
title: exports_external.string().min(1),
|
|
52663
52899
|
description: exports_external.string().optional().default("")
|
|
52664
52900
|
}),
|
|
52665
|
-
subtasks: exports_external.array(SubtaskSpecSchema).min(1)
|
|
52901
|
+
subtasks: exports_external.array(SubtaskSpecSchema).min(1),
|
|
52902
|
+
strategy: exports_external.enum(["file-based", "feature-based", "risk-based", "research-based"]).optional().describe("Decomposition strategy from swarm_select_strategy. If not provided, defaults to feature-based.")
|
|
52666
52903
|
});
|
|
52667
52904
|
var EpicCreateArgsSchema = exports_external.object({
|
|
52668
52905
|
epic_title: exports_external.string().min(1),
|
|
@@ -53369,13 +53606,13 @@ async function autoMigrateFromJSONL(adapter, projectKey) {
|
|
|
53369
53606
|
skipExisting: true
|
|
53370
53607
|
});
|
|
53371
53608
|
if (result.created > 0 || result.updated > 0) {
|
|
53372
|
-
console.
|
|
53609
|
+
console.error(`[hive] Auto-migrated ${result.created} cells from ${jsonlPath} (${result.skipped} skipped, ${result.errors.length} errors)`);
|
|
53373
53610
|
}
|
|
53374
53611
|
if (result.errors.length > 0) {
|
|
53375
|
-
console.
|
|
53612
|
+
console.error(`[hive] Migration errors:`, result.errors.slice(0, 5).map((e) => `${e.cellId}: ${e.error}`));
|
|
53376
53613
|
}
|
|
53377
53614
|
} catch (error45) {
|
|
53378
|
-
console.
|
|
53615
|
+
console.error(`[hive] Failed to auto-migrate from ${jsonlPath}:`, error45 instanceof Error ? error45.message : String(error45));
|
|
53379
53616
|
}
|
|
53380
53617
|
}
|
|
53381
53618
|
function formatCellForOutput(adapterCell) {
|
|
@@ -72486,11 +72723,16 @@ echo "Project directory: $1"
|
|
|
72486
72723
|
});
|
|
72487
72724
|
var exports_swarm_insights = {};
|
|
72488
72725
|
__export3(exports_swarm_insights, {
|
|
72726
|
+
trackCoordinatorViolation: () => trackCoordinatorViolation,
|
|
72727
|
+
getViolationAnalytics: () => getViolationAnalytics,
|
|
72489
72728
|
getStrategyInsights: () => getStrategyInsights,
|
|
72729
|
+
getRejectionAnalytics: () => getRejectionAnalytics,
|
|
72490
72730
|
getPatternInsights: () => getPatternInsights,
|
|
72491
72731
|
getFileInsights: () => getFileInsights,
|
|
72732
|
+
getFileFailureHistory: () => getFileFailureHistory,
|
|
72492
72733
|
getCachedInsights: () => getCachedInsights,
|
|
72493
72734
|
formatInsightsForPrompt: () => formatInsightsForPrompt,
|
|
72735
|
+
formatFileHistoryWarnings: () => formatFileHistoryWarnings,
|
|
72494
72736
|
clearInsightsCache: () => clearInsightsCache
|
|
72495
72737
|
});
|
|
72496
72738
|
async function getStrategyInsights(swarmMail, _task) {
|
|
@@ -72562,6 +72804,136 @@ async function getFileInsights(swarmMail, files) {
|
|
|
72562
72804
|
async function getFileGotchas(_swarmMail, _file22) {
|
|
72563
72805
|
return [];
|
|
72564
72806
|
}
|
|
72807
|
+
async function getFileFailureHistory(swarmMail, files) {
|
|
72808
|
+
if (files.length === 0)
|
|
72809
|
+
return [];
|
|
72810
|
+
const db = await swarmMail.getDatabase();
|
|
72811
|
+
const histories = [];
|
|
72812
|
+
for (const file22 of files) {
|
|
72813
|
+
const query = `
|
|
72814
|
+
SELECT data
|
|
72815
|
+
FROM events
|
|
72816
|
+
WHERE type = 'review_feedback'
|
|
72817
|
+
AND json_extract(data, '$.status') = 'needs_changes'
|
|
72818
|
+
AND json_extract(data, '$.issues') LIKE ?
|
|
72819
|
+
`;
|
|
72820
|
+
const result = await db.query(query, [`%${file22}%`]);
|
|
72821
|
+
if (!result.rows || result.rows.length === 0) {
|
|
72822
|
+
continue;
|
|
72823
|
+
}
|
|
72824
|
+
const issueTexts = [];
|
|
72825
|
+
for (const row of result.rows) {
|
|
72826
|
+
try {
|
|
72827
|
+
const data = JSON.parse(row.data);
|
|
72828
|
+
const issuesStr = data.issues;
|
|
72829
|
+
if (!issuesStr)
|
|
72830
|
+
continue;
|
|
72831
|
+
const issues = JSON.parse(issuesStr);
|
|
72832
|
+
for (const issue22 of issues) {
|
|
72833
|
+
if (issue22.file === file22) {
|
|
72834
|
+
issueTexts.push(issue22.issue);
|
|
72835
|
+
}
|
|
72836
|
+
}
|
|
72837
|
+
} catch (e) {
|
|
72838
|
+
continue;
|
|
72839
|
+
}
|
|
72840
|
+
}
|
|
72841
|
+
if (issueTexts.length === 0) {
|
|
72842
|
+
continue;
|
|
72843
|
+
}
|
|
72844
|
+
const issueCounts = new Map;
|
|
72845
|
+
for (const text of issueTexts) {
|
|
72846
|
+
issueCounts.set(text, (issueCounts.get(text) || 0) + 1);
|
|
72847
|
+
}
|
|
72848
|
+
const topIssues = Array.from(issueCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 3).map(([text]) => text);
|
|
72849
|
+
histories.push({
|
|
72850
|
+
file: file22,
|
|
72851
|
+
rejectionCount: issueTexts.length,
|
|
72852
|
+
topIssues
|
|
72853
|
+
});
|
|
72854
|
+
}
|
|
72855
|
+
return histories;
|
|
72856
|
+
}
|
|
72857
|
+
async function getRejectionAnalytics(swarmMail) {
|
|
72858
|
+
const db = await swarmMail.getDatabase();
|
|
72859
|
+
const query = `
|
|
72860
|
+
SELECT data
|
|
72861
|
+
FROM events
|
|
72862
|
+
WHERE type = 'review_feedback'
|
|
72863
|
+
ORDER BY timestamp DESC
|
|
72864
|
+
`;
|
|
72865
|
+
const result = await db.query(query, []);
|
|
72866
|
+
if (!result.rows || result.rows.length === 0) {
|
|
72867
|
+
return {
|
|
72868
|
+
totalReviews: 0,
|
|
72869
|
+
approved: 0,
|
|
72870
|
+
rejected: 0,
|
|
72871
|
+
approvalRate: 0,
|
|
72872
|
+
topReasons: []
|
|
72873
|
+
};
|
|
72874
|
+
}
|
|
72875
|
+
let approved = 0;
|
|
72876
|
+
let rejected = 0;
|
|
72877
|
+
const reasonCounts = new Map;
|
|
72878
|
+
for (const row of result.rows) {
|
|
72879
|
+
try {
|
|
72880
|
+
const data = JSON.parse(row.data);
|
|
72881
|
+
if (data.status === "approved") {
|
|
72882
|
+
approved++;
|
|
72883
|
+
} else if (data.status === "needs_changes") {
|
|
72884
|
+
rejected++;
|
|
72885
|
+
if (data.issues) {
|
|
72886
|
+
const issues = JSON.parse(data.issues);
|
|
72887
|
+
for (const issue22 of issues) {
|
|
72888
|
+
const category = categorizeRejectionReason(issue22.issue);
|
|
72889
|
+
reasonCounts.set(category, (reasonCounts.get(category) || 0) + 1);
|
|
72890
|
+
}
|
|
72891
|
+
}
|
|
72892
|
+
}
|
|
72893
|
+
} catch (e) {
|
|
72894
|
+
continue;
|
|
72895
|
+
}
|
|
72896
|
+
}
|
|
72897
|
+
const totalReviews = approved + rejected;
|
|
72898
|
+
const approvalRate = totalReviews > 0 ? approved / totalReviews * 100 : 0;
|
|
72899
|
+
const topReasons = Array.from(reasonCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([category, count]) => ({
|
|
72900
|
+
category,
|
|
72901
|
+
count,
|
|
72902
|
+
percentage: rejected > 0 ? count / rejected * 100 : 0
|
|
72903
|
+
}));
|
|
72904
|
+
return {
|
|
72905
|
+
totalReviews,
|
|
72906
|
+
approved,
|
|
72907
|
+
rejected,
|
|
72908
|
+
approvalRate,
|
|
72909
|
+
topReasons
|
|
72910
|
+
};
|
|
72911
|
+
}
|
|
72912
|
+
function categorizeRejectionReason(reason) {
|
|
72913
|
+
const lowerReason = reason.toLowerCase();
|
|
72914
|
+
if (lowerReason.includes("test") || lowerReason.includes("spec") || lowerReason.includes("coverage")) {
|
|
72915
|
+
return "Missing tests";
|
|
72916
|
+
}
|
|
72917
|
+
if (lowerReason.includes("type") || lowerReason.includes("undefined") || lowerReason.includes("null") || lowerReason.includes("assignable")) {
|
|
72918
|
+
return "Type errors";
|
|
72919
|
+
}
|
|
72920
|
+
if (lowerReason.includes("incomplete") || lowerReason.includes("missing") || lowerReason.includes("forgot") || lowerReason.includes("didn't implement")) {
|
|
72921
|
+
return "Incomplete implementation";
|
|
72922
|
+
}
|
|
72923
|
+
if (lowerReason.includes("wrong file") || lowerReason.includes("modified incorrect") || lowerReason.includes("shouldn't have changed")) {
|
|
72924
|
+
return "Wrong file modified";
|
|
72925
|
+
}
|
|
72926
|
+
if (lowerReason.includes("performance") || lowerReason.includes("slow") || lowerReason.includes("inefficient")) {
|
|
72927
|
+
return "Performance issue";
|
|
72928
|
+
}
|
|
72929
|
+
if (lowerReason.includes("security") || lowerReason.includes("vulnerability") || lowerReason.includes("unsafe")) {
|
|
72930
|
+
return "Security vulnerability";
|
|
72931
|
+
}
|
|
72932
|
+
if (lowerReason.includes("error handling") || lowerReason.includes("try/catch") || lowerReason.includes("exception")) {
|
|
72933
|
+
return "Missing error handling";
|
|
72934
|
+
}
|
|
72935
|
+
return "Other";
|
|
72936
|
+
}
|
|
72565
72937
|
async function getPatternInsights(swarmMail) {
|
|
72566
72938
|
const db = await swarmMail.getDatabase();
|
|
72567
72939
|
const patterns = [];
|
|
@@ -72649,6 +73021,107 @@ async function getCachedInsights(_swarmMail, cacheKey, computeFn) {
|
|
|
72649
73021
|
function clearInsightsCache() {
|
|
72650
73022
|
insightsCache.clear();
|
|
72651
73023
|
}
|
|
73024
|
+
async function trackCoordinatorViolation(swarmMail, violation) {
|
|
73025
|
+
const db = await swarmMail.getDatabase();
|
|
73026
|
+
const query = `
|
|
73027
|
+
INSERT INTO events (type, project_key, timestamp, data)
|
|
73028
|
+
VALUES (?, ?, ?, ?)
|
|
73029
|
+
RETURNING id
|
|
73030
|
+
`;
|
|
73031
|
+
const data = JSON.stringify({
|
|
73032
|
+
session_id: violation.session_id,
|
|
73033
|
+
epic_id: violation.epic_id,
|
|
73034
|
+
event_type: "VIOLATION",
|
|
73035
|
+
violation_type: violation.violation_type,
|
|
73036
|
+
payload: violation.payload
|
|
73037
|
+
});
|
|
73038
|
+
const result = await db.query(query, [
|
|
73039
|
+
"coordinator_violation",
|
|
73040
|
+
violation.project_key,
|
|
73041
|
+
Date.now(),
|
|
73042
|
+
data
|
|
73043
|
+
]);
|
|
73044
|
+
return result.rows[0].id;
|
|
73045
|
+
}
|
|
73046
|
+
async function getViolationAnalytics(swarmMail, projectKey) {
|
|
73047
|
+
const db = await swarmMail.getDatabase();
|
|
73048
|
+
const violationsQuery = projectKey ? `
|
|
73049
|
+
SELECT data
|
|
73050
|
+
FROM events
|
|
73051
|
+
WHERE type = 'coordinator_violation'
|
|
73052
|
+
AND project_key = ?
|
|
73053
|
+
ORDER BY timestamp DESC
|
|
73054
|
+
` : `
|
|
73055
|
+
SELECT data
|
|
73056
|
+
FROM events
|
|
73057
|
+
WHERE type = 'coordinator_violation'
|
|
73058
|
+
ORDER BY timestamp DESC
|
|
73059
|
+
`;
|
|
73060
|
+
const params = projectKey ? [projectKey] : [];
|
|
73061
|
+
const result = await db.query(violationsQuery, params);
|
|
73062
|
+
if (!result.rows || result.rows.length === 0) {
|
|
73063
|
+
return {
|
|
73064
|
+
totalViolations: 0,
|
|
73065
|
+
byType: [],
|
|
73066
|
+
violationRate: 0
|
|
73067
|
+
};
|
|
73068
|
+
}
|
|
73069
|
+
const violationCounts = new Map;
|
|
73070
|
+
let totalViolations = 0;
|
|
73071
|
+
for (const row of result.rows) {
|
|
73072
|
+
try {
|
|
73073
|
+
const data = JSON.parse(row.data);
|
|
73074
|
+
const violationType = data.violation_type;
|
|
73075
|
+
if (violationType) {
|
|
73076
|
+
violationCounts.set(violationType, (violationCounts.get(violationType) || 0) + 1);
|
|
73077
|
+
totalViolations++;
|
|
73078
|
+
}
|
|
73079
|
+
} catch (e) {
|
|
73080
|
+
continue;
|
|
73081
|
+
}
|
|
73082
|
+
}
|
|
73083
|
+
const byType = Array.from(violationCounts.entries()).sort((a, b) => b[1] - a[1]).map(([violationType, count]) => ({
|
|
73084
|
+
violationType,
|
|
73085
|
+
count,
|
|
73086
|
+
percentage: count / totalViolations * 100
|
|
73087
|
+
}));
|
|
73088
|
+
const coordinationQuery = projectKey ? `
|
|
73089
|
+
SELECT COUNT(*) as count
|
|
73090
|
+
FROM events
|
|
73091
|
+
WHERE type IN ('worker_spawned', 'review_feedback', 'message_sent')
|
|
73092
|
+
AND project_key = ?
|
|
73093
|
+
` : `
|
|
73094
|
+
SELECT COUNT(*) as count
|
|
73095
|
+
FROM events
|
|
73096
|
+
WHERE type IN ('worker_spawned', 'review_feedback', 'message_sent')
|
|
73097
|
+
`;
|
|
73098
|
+
const coordResult = await db.query(coordinationQuery, params);
|
|
73099
|
+
const coordinationCount = coordResult.rows[0]?.count || 0;
|
|
73100
|
+
const violationRate = coordinationCount > 0 ? totalViolations / coordinationCount * 100 : 0;
|
|
73101
|
+
return {
|
|
73102
|
+
totalViolations,
|
|
73103
|
+
byType,
|
|
73104
|
+
violationRate
|
|
73105
|
+
};
|
|
73106
|
+
}
|
|
73107
|
+
function formatFileHistoryWarnings(histories) {
|
|
73108
|
+
if (histories.length === 0) {
|
|
73109
|
+
return "";
|
|
73110
|
+
}
|
|
73111
|
+
const lines = ["⚠️ FILE HISTORY WARNINGS:"];
|
|
73112
|
+
for (const history of histories) {
|
|
73113
|
+
const workerText = history.rejectionCount === 1 ? "1 previous worker rejected" : `${history.rejectionCount} previous workers rejected`;
|
|
73114
|
+
const issuesText = history.topIssues.join(", ");
|
|
73115
|
+
lines.push(`- ${history.file}: ${workerText} for ${issuesText}`);
|
|
73116
|
+
}
|
|
73117
|
+
let result = lines.join(`
|
|
73118
|
+
`);
|
|
73119
|
+
const maxChars = 300 * 4;
|
|
73120
|
+
if (result.length > maxChars) {
|
|
73121
|
+
result = result.slice(0, maxChars - 3) + "...";
|
|
73122
|
+
}
|
|
73123
|
+
return result;
|
|
73124
|
+
}
|
|
72652
73125
|
var insightsCache;
|
|
72653
73126
|
var CACHE_TTL_MS;
|
|
72654
73127
|
var init_swarm_insights = __esm3(() => {
|
|
@@ -74537,7 +75010,8 @@ var CellTreeSchema2 = exports_external2.object({
|
|
|
74537
75010
|
title: exports_external2.string().min(1),
|
|
74538
75011
|
description: exports_external2.string().optional().default("")
|
|
74539
75012
|
}),
|
|
74540
|
-
subtasks: exports_external2.array(SubtaskSpecSchema2).min(1)
|
|
75013
|
+
subtasks: exports_external2.array(SubtaskSpecSchema2).min(1),
|
|
75014
|
+
strategy: exports_external2.enum(["file-based", "feature-based", "risk-based", "research-based"]).optional().describe("Decomposition strategy from swarm_select_strategy. If not provided, defaults to feature-based.")
|
|
74541
75015
|
});
|
|
74542
75016
|
var EpicCreateArgsSchema2 = exports_external2.object({
|
|
74543
75017
|
epic_title: exports_external2.string().min(1),
|
|
@@ -75411,13 +75885,13 @@ async function autoMigrateFromJSONL2(adapter, projectKey) {
|
|
|
75411
75885
|
skipExisting: true
|
|
75412
75886
|
});
|
|
75413
75887
|
if (result.created > 0 || result.updated > 0) {
|
|
75414
|
-
console.
|
|
75888
|
+
console.error(`[hive] Auto-migrated ${result.created} cells from ${jsonlPath} (${result.skipped} skipped, ${result.errors.length} errors)`);
|
|
75415
75889
|
}
|
|
75416
75890
|
if (result.errors.length > 0) {
|
|
75417
|
-
console.
|
|
75891
|
+
console.error(`[hive] Migration errors:`, result.errors.slice(0, 5).map((e) => `${e.cellId}: ${e.error}`));
|
|
75418
75892
|
}
|
|
75419
75893
|
} catch (error452) {
|
|
75420
|
-
console.
|
|
75894
|
+
console.error(`[hive] Failed to auto-migrate from ${jsonlPath}:`, error452 instanceof Error ? error452.message : String(error452));
|
|
75421
75895
|
}
|
|
75422
75896
|
}
|
|
75423
75897
|
function formatCellForOutput2(adapterCell) {
|
|
@@ -77566,7 +78040,7 @@ var swarm_complete = tool2({
|
|
|
77566
78040
|
files_touched: tool2.schema.array(tool2.schema.string()).optional().describe("Files modified - will be verified (typecheck, tests)"),
|
|
77567
78041
|
skip_verification: tool2.schema.boolean().optional().describe("Skip ALL verification (typecheck, tests). Use sparingly! (default: false)"),
|
|
77568
78042
|
planned_files: tool2.schema.array(tool2.schema.string()).optional().describe("Files that were originally planned to be modified"),
|
|
77569
|
-
start_time: tool2.schema.number().
|
|
78043
|
+
start_time: tool2.schema.number().describe("Task start timestamp (Unix ms) for duration calculation - REQUIRED for accurate analytics"),
|
|
77570
78044
|
error_count: tool2.schema.number().optional().describe("Number of errors encountered during task"),
|
|
77571
78045
|
retry_count: tool2.schema.number().optional().describe("Number of retry attempts during task"),
|
|
77572
78046
|
skip_review: tool2.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review.")
|
|
@@ -77770,7 +78244,7 @@ This will be recorded as a negative learning signal.`;
|
|
|
77770
78244
|
syncError = error452 instanceof Error ? error452.message : String(error452);
|
|
77771
78245
|
console.warn(`[swarm_complete] Auto-sync failed (non-fatal): ${syncError}`);
|
|
77772
78246
|
}
|
|
77773
|
-
const completionDurationMs =
|
|
78247
|
+
const completionDurationMs = Date.now() - args.start_time;
|
|
77774
78248
|
const eventEpicId = cell.parent_id || (args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id);
|
|
77775
78249
|
try {
|
|
77776
78250
|
const event = createEvent3("subtask_outcome", {
|
|
@@ -91824,14 +92298,14 @@ async function maybeAutoMigrate(db) {
|
|
|
91824
92298
|
if (memoryCount > 0) {
|
|
91825
92299
|
return;
|
|
91826
92300
|
}
|
|
91827
|
-
console.
|
|
92301
|
+
console.error("[memory] Legacy database detected, starting auto-migration...");
|
|
91828
92302
|
const result = await migrateLegacyMemories({
|
|
91829
92303
|
targetDb: db,
|
|
91830
92304
|
dryRun: false,
|
|
91831
|
-
onProgress: console.
|
|
92305
|
+
onProgress: (msg) => console.error(msg)
|
|
91832
92306
|
});
|
|
91833
92307
|
if (result.migrated > 0) {
|
|
91834
|
-
console.
|
|
92308
|
+
console.error(`[memory] Auto-migrated ${result.migrated} memories from legacy database`);
|
|
91835
92309
|
}
|
|
91836
92310
|
if (result.failed > 0) {
|
|
91837
92311
|
console.warn(`[memory] ${result.failed} memories failed to migrate. See errors above.`);
|
|
@@ -91900,6 +92374,7 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
91900
92374
|
async find(args2) {
|
|
91901
92375
|
const limit = args2.limit ?? 10;
|
|
91902
92376
|
let results;
|
|
92377
|
+
let usedFallback = false;
|
|
91903
92378
|
if (args2.fts) {
|
|
91904
92379
|
results = await store.ftsSearch(args2.query, {
|
|
91905
92380
|
limit,
|
|
@@ -91910,14 +92385,23 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
91910
92385
|
const ollama = yield* Ollama;
|
|
91911
92386
|
return yield* ollama.embed(args2.query);
|
|
91912
92387
|
});
|
|
91913
|
-
|
|
91914
|
-
|
|
91915
|
-
|
|
91916
|
-
|
|
91917
|
-
|
|
91918
|
-
|
|
92388
|
+
try {
|
|
92389
|
+
const queryEmbedding = await exports_Effect.runPromise(program.pipe(exports_Effect.provide(ollamaLayer)));
|
|
92390
|
+
results = await store.search(queryEmbedding, {
|
|
92391
|
+
limit,
|
|
92392
|
+
threshold: 0.3,
|
|
92393
|
+
collection: args2.collection
|
|
92394
|
+
});
|
|
92395
|
+
} catch (e) {
|
|
92396
|
+
console.warn("[hivemind] Ollama unavailable, falling back to full-text search");
|
|
92397
|
+
usedFallback = true;
|
|
92398
|
+
results = await store.ftsSearch(args2.query, {
|
|
92399
|
+
limit,
|
|
92400
|
+
collection: args2.collection
|
|
92401
|
+
});
|
|
92402
|
+
}
|
|
91919
92403
|
}
|
|
91920
|
-
|
|
92404
|
+
const response = {
|
|
91921
92405
|
results: results.map((r) => ({
|
|
91922
92406
|
id: r.memory.id,
|
|
91923
92407
|
content: args2.expand ? r.memory.content : truncateContent(r.memory.content),
|
|
@@ -91928,6 +92412,10 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
91928
92412
|
})),
|
|
91929
92413
|
count: results.length
|
|
91930
92414
|
};
|
|
92415
|
+
if (usedFallback) {
|
|
92416
|
+
response.fallback_used = true;
|
|
92417
|
+
}
|
|
92418
|
+
return response;
|
|
91931
92419
|
},
|
|
91932
92420
|
async get(args2) {
|
|
91933
92421
|
return store.get(args2.id);
|
|
@@ -92746,6 +93234,74 @@ Your role is **ONLY** to:
|
|
|
92746
93234
|
|
|
92747
93235
|
**ALWAYS spawn workers, even for sequential tasks.** Sequential just means spawn them in order and wait for each to complete before spawning the next.
|
|
92748
93236
|
|
|
93237
|
+
### Explicit NEVER Rules (With Examples)
|
|
93238
|
+
|
|
93239
|
+
\`\`\`
|
|
93240
|
+
╔═══════════════════════════════════════════════════════════════════════════╗
|
|
93241
|
+
║ ║
|
|
93242
|
+
║ ❌ COORDINATORS NEVER DO THIS: ║
|
|
93243
|
+
║ ║
|
|
93244
|
+
║ - Read implementation files (read(), glob src/**, grep for patterns) ║
|
|
93245
|
+
║ - Edit code (edit(), write() any .ts/.js/.tsx files) ║
|
|
93246
|
+
║ - Run tests (bash "bun test", "npm test", pytest) ║
|
|
93247
|
+
║ - Implement features (adding functions, components, logic) ║
|
|
93248
|
+
║ - Fix bugs (changing code to fix errors) ║
|
|
93249
|
+
║ - Install packages (bash "bun add", "npm install") ║
|
|
93250
|
+
║ - Commit changes (bash "git add", "git commit") ║
|
|
93251
|
+
║ - Reserve files (swarmmail_reserve - workers do this) ║
|
|
93252
|
+
║ ║
|
|
93253
|
+
║ ✅ COORDINATORS ONLY DO THIS: ║
|
|
93254
|
+
║ ║
|
|
93255
|
+
║ - Clarify task scope (ask questions, understand requirements) ║
|
|
93256
|
+
║ - Read package.json/tsconfig.json for structure (metadata only) ║
|
|
93257
|
+
║ - Decompose into subtasks (swarm_plan_prompt, validate_decomposition) ║
|
|
93258
|
+
║ - Spawn workers (swarm_spawn_subtask, Task(subagent_type="worker")) ║
|
|
93259
|
+
║ - Monitor progress (swarmmail_inbox, swarm_status) ║
|
|
93260
|
+
║ - Review completed work (swarm_review, swarm_review_feedback) ║
|
|
93261
|
+
║ - Verify final state (check all workers completed, hive_sync) ║
|
|
93262
|
+
║ ║
|
|
93263
|
+
╚═══════════════════════════════════════════════════════════════════════════╝
|
|
93264
|
+
\`\`\`
|
|
93265
|
+
|
|
93266
|
+
**Examples of Violations:**
|
|
93267
|
+
|
|
93268
|
+
❌ **WRONG** - Coordinator reading implementation:
|
|
93269
|
+
\`\`\`
|
|
93270
|
+
read("src/auth/login.ts") // NO - spawn worker to analyze
|
|
93271
|
+
glob("src/components/**/*.tsx") // NO - spawn worker to inventory
|
|
93272
|
+
grep(pattern="export", include="*.ts") // NO - spawn worker to search
|
|
93273
|
+
\`\`\`
|
|
93274
|
+
|
|
93275
|
+
❌ **WRONG** - Coordinator editing code:
|
|
93276
|
+
\`\`\`
|
|
93277
|
+
edit("src/types.ts", ...) // NO - spawn worker to fix
|
|
93278
|
+
write("src/new.ts", ...) // NO - spawn worker to create
|
|
93279
|
+
\`\`\`
|
|
93280
|
+
|
|
93281
|
+
❌ **WRONG** - Coordinator running tests:
|
|
93282
|
+
\`\`\`
|
|
93283
|
+
bash("bun test src/auth.test.ts") // NO - worker runs tests
|
|
93284
|
+
\`\`\`
|
|
93285
|
+
|
|
93286
|
+
❌ **WRONG** - Coordinator reserving files:
|
|
93287
|
+
\`\`\`
|
|
93288
|
+
swarmmail_reserve(paths=["src/auth.ts"]) // NO - worker reserves their own files
|
|
93289
|
+
swarm_spawn_subtask(bead_id="...", files=["src/auth.ts"])
|
|
93290
|
+
\`\`\`
|
|
93291
|
+
|
|
93292
|
+
✅ **CORRECT** - Coordinator spawning worker:
|
|
93293
|
+
\`\`\`
|
|
93294
|
+
// Coordinator delegates ALL work
|
|
93295
|
+
swarm_spawn_subtask(
|
|
93296
|
+
bead_id="fix-auth-bug",
|
|
93297
|
+
epic_id="epic-123",
|
|
93298
|
+
subtask_title="Fix null check in login handler",
|
|
93299
|
+
files=["src/auth/login.ts", "src/auth/login.test.ts"],
|
|
93300
|
+
shared_context="Bug: login fails when username is null"
|
|
93301
|
+
)
|
|
93302
|
+
Task(subagent_type="swarm-worker", prompt="<from above>")
|
|
93303
|
+
\`\`\`
|
|
93304
|
+
|
|
92749
93305
|
### Why This Matters
|
|
92750
93306
|
|
|
92751
93307
|
| Coordinator Work | Worker Work | Consequence of Mixing |
|
|
@@ -93830,15 +94386,15 @@ import {
|
|
|
93830
94386
|
createHiveAdapter as createHiveAdapter4,
|
|
93831
94387
|
resolvePartialId as resolvePartialId4,
|
|
93832
94388
|
createDurableStreamAdapter,
|
|
93833
|
-
createDurableStreamServer
|
|
94389
|
+
createDurableStreamServer,
|
|
94390
|
+
consolidateDatabases,
|
|
94391
|
+
getGlobalDbPath as getGlobalDbPath2
|
|
93834
94392
|
} from "swarm-mail";
|
|
93835
94393
|
import { execSync, spawn } from "child_process";
|
|
93836
94394
|
import { tmpdir as tmpdir3 } from "os";
|
|
93837
94395
|
|
|
93838
94396
|
// src/query-tools.ts
|
|
93839
|
-
import { createLibSQLAdapter as createLibSQLAdapter2 } from "swarm-mail";
|
|
93840
|
-
import { join as join7 } from "node:path";
|
|
93841
|
-
import { homedir as homedir3 } from "node:os";
|
|
94397
|
+
import { createLibSQLAdapter as createLibSQLAdapter2, getGlobalDbPath } from "swarm-mail";
|
|
93842
94398
|
var presetQueries = {
|
|
93843
94399
|
failed_decompositions: `
|
|
93844
94400
|
SELECT
|
|
@@ -93989,8 +94545,7 @@ var presetQueries = {
|
|
|
93989
94545
|
`
|
|
93990
94546
|
};
|
|
93991
94547
|
function getDbPath() {
|
|
93992
|
-
|
|
93993
|
-
return join7(home, ".swarm-tools", "swarm-mail.db");
|
|
94548
|
+
return getGlobalDbPath();
|
|
93994
94549
|
}
|
|
93995
94550
|
async function createDbAdapter() {
|
|
93996
94551
|
const dbPath = getDbPath();
|
|
@@ -95200,8 +95755,8 @@ function detectRegressions(projectPath, threshold = 0.1) {
|
|
|
95200
95755
|
}
|
|
95201
95756
|
|
|
95202
95757
|
// src/observability-health.ts
|
|
95203
|
-
import { homedir as
|
|
95204
|
-
import { join as
|
|
95758
|
+
import { homedir as homedir3 } from "node:os";
|
|
95759
|
+
import { join as join9 } from "node:path";
|
|
95205
95760
|
import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync8, statSync } from "node:fs";
|
|
95206
95761
|
var EXPECTED_HOOKS = [
|
|
95207
95762
|
"tool.execute.after",
|
|
@@ -95298,16 +95853,16 @@ function calculateSessionQuality(input) {
|
|
|
95298
95853
|
};
|
|
95299
95854
|
}
|
|
95300
95855
|
function querySessionQuality(options2) {
|
|
95301
|
-
const sessionsPath =
|
|
95856
|
+
const sessionsPath = join9(homedir3(), ".config", "swarm-tools", "sessions");
|
|
95302
95857
|
if (!existsSync8(sessionsPath)) {
|
|
95303
95858
|
return { totalSessions: 0, qualitySessions: 0 };
|
|
95304
95859
|
}
|
|
95305
95860
|
const since = Date.now() - options2.days * 24 * 60 * 60 * 1000;
|
|
95306
|
-
const sessionFiles = readdirSync(sessionsPath).filter((f) => f.endsWith(".jsonl") && statSync(
|
|
95861
|
+
const sessionFiles = readdirSync(sessionsPath).filter((f) => f.endsWith(".jsonl") && statSync(join9(sessionsPath, f)).mtimeMs >= since);
|
|
95307
95862
|
let qualityCount = 0;
|
|
95308
95863
|
for (const file4 of sessionFiles) {
|
|
95309
95864
|
try {
|
|
95310
|
-
const content = readFileSync8(
|
|
95865
|
+
const content = readFileSync8(join9(sessionsPath, file4), "utf-8");
|
|
95311
95866
|
const lines = content.trim().split(`
|
|
95312
95867
|
`);
|
|
95313
95868
|
let hasDecisions = false;
|
|
@@ -95417,6 +95972,90 @@ async function getObservabilityHealth(projectPath, options2 = {}) {
|
|
|
95417
95972
|
};
|
|
95418
95973
|
}
|
|
95419
95974
|
|
|
95975
|
+
// src/swarm-insights.ts
|
|
95976
|
+
async function getRejectionAnalytics2(swarmMail) {
|
|
95977
|
+
const db = await swarmMail.getDatabase();
|
|
95978
|
+
const query = `
|
|
95979
|
+
SELECT data
|
|
95980
|
+
FROM events
|
|
95981
|
+
WHERE type = 'review_feedback'
|
|
95982
|
+
ORDER BY timestamp DESC
|
|
95983
|
+
`;
|
|
95984
|
+
const result = await db.query(query, []);
|
|
95985
|
+
if (!result.rows || result.rows.length === 0) {
|
|
95986
|
+
return {
|
|
95987
|
+
totalReviews: 0,
|
|
95988
|
+
approved: 0,
|
|
95989
|
+
rejected: 0,
|
|
95990
|
+
approvalRate: 0,
|
|
95991
|
+
topReasons: []
|
|
95992
|
+
};
|
|
95993
|
+
}
|
|
95994
|
+
let approved = 0;
|
|
95995
|
+
let rejected = 0;
|
|
95996
|
+
const reasonCounts = new Map;
|
|
95997
|
+
for (const row of result.rows) {
|
|
95998
|
+
try {
|
|
95999
|
+
const data = JSON.parse(row.data);
|
|
96000
|
+
if (data.status === "approved") {
|
|
96001
|
+
approved++;
|
|
96002
|
+
} else if (data.status === "needs_changes") {
|
|
96003
|
+
rejected++;
|
|
96004
|
+
if (data.issues) {
|
|
96005
|
+
const issues = JSON.parse(data.issues);
|
|
96006
|
+
for (const issue4 of issues) {
|
|
96007
|
+
const category = categorizeRejectionReason2(issue4.issue);
|
|
96008
|
+
reasonCounts.set(category, (reasonCounts.get(category) || 0) + 1);
|
|
96009
|
+
}
|
|
96010
|
+
}
|
|
96011
|
+
}
|
|
96012
|
+
} catch (e) {
|
|
96013
|
+
continue;
|
|
96014
|
+
}
|
|
96015
|
+
}
|
|
96016
|
+
const totalReviews = approved + rejected;
|
|
96017
|
+
const approvalRate = totalReviews > 0 ? approved / totalReviews * 100 : 0;
|
|
96018
|
+
const topReasons = Array.from(reasonCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 5).map(([category, count]) => ({
|
|
96019
|
+
category,
|
|
96020
|
+
count,
|
|
96021
|
+
percentage: rejected > 0 ? count / rejected * 100 : 0
|
|
96022
|
+
}));
|
|
96023
|
+
return {
|
|
96024
|
+
totalReviews,
|
|
96025
|
+
approved,
|
|
96026
|
+
rejected,
|
|
96027
|
+
approvalRate,
|
|
96028
|
+
topReasons
|
|
96029
|
+
};
|
|
96030
|
+
}
|
|
96031
|
+
function categorizeRejectionReason2(reason) {
|
|
96032
|
+
const lowerReason = reason.toLowerCase();
|
|
96033
|
+
if (lowerReason.includes("test") || lowerReason.includes("spec") || lowerReason.includes("coverage")) {
|
|
96034
|
+
return "Missing tests";
|
|
96035
|
+
}
|
|
96036
|
+
if (lowerReason.includes("type") || lowerReason.includes("undefined") || lowerReason.includes("null") || lowerReason.includes("assignable")) {
|
|
96037
|
+
return "Type errors";
|
|
96038
|
+
}
|
|
96039
|
+
if (lowerReason.includes("incomplete") || lowerReason.includes("missing") || lowerReason.includes("forgot") || lowerReason.includes("didn't implement")) {
|
|
96040
|
+
return "Incomplete implementation";
|
|
96041
|
+
}
|
|
96042
|
+
if (lowerReason.includes("wrong file") || lowerReason.includes("modified incorrect") || lowerReason.includes("shouldn't have changed")) {
|
|
96043
|
+
return "Wrong file modified";
|
|
96044
|
+
}
|
|
96045
|
+
if (lowerReason.includes("performance") || lowerReason.includes("slow") || lowerReason.includes("inefficient")) {
|
|
96046
|
+
return "Performance issue";
|
|
96047
|
+
}
|
|
96048
|
+
if (lowerReason.includes("security") || lowerReason.includes("vulnerability") || lowerReason.includes("unsafe")) {
|
|
96049
|
+
return "Security vulnerability";
|
|
96050
|
+
}
|
|
96051
|
+
if (lowerReason.includes("error handling") || lowerReason.includes("try/catch") || lowerReason.includes("exception")) {
|
|
96052
|
+
return "Missing error handling";
|
|
96053
|
+
}
|
|
96054
|
+
return "Other";
|
|
96055
|
+
}
|
|
96056
|
+
var insightsCache2 = new Map;
|
|
96057
|
+
var CACHE_TTL_MS2 = 5 * 60 * 1000;
|
|
96058
|
+
|
|
95420
96059
|
// src/eval-history.ts
|
|
95421
96060
|
import * as fs5 from "node:fs";
|
|
95422
96061
|
import * as path6 from "node:path";
|
|
@@ -95814,7 +96453,7 @@ import {
|
|
|
95814
96453
|
findCellsByPartialId as findCellsByPartialId3
|
|
95815
96454
|
} from "swarm-mail";
|
|
95816
96455
|
import { existsSync as existsSync13, readFileSync as readFileSync13 } from "node:fs";
|
|
95817
|
-
import { join as
|
|
96456
|
+
import { join as join13 } from "node:path";
|
|
95818
96457
|
|
|
95819
96458
|
// src/schemas/cell.ts
|
|
95820
96459
|
init_zod3();
|
|
@@ -95892,7 +96531,8 @@ var CellTreeSchema3 = exports_external3.object({
|
|
|
95892
96531
|
title: exports_external3.string().min(1),
|
|
95893
96532
|
description: exports_external3.string().optional().default("")
|
|
95894
96533
|
}),
|
|
95895
|
-
subtasks: exports_external3.array(SubtaskSpecSchema3).min(1)
|
|
96534
|
+
subtasks: exports_external3.array(SubtaskSpecSchema3).min(1),
|
|
96535
|
+
strategy: exports_external3.enum(["file-based", "feature-based", "risk-based", "research-based"]).optional().describe("Decomposition strategy from swarm_select_strategy. If not provided, defaults to feature-based.")
|
|
95896
96536
|
});
|
|
95897
96537
|
var EpicCreateArgsSchema3 = exports_external3.object({
|
|
95898
96538
|
epic_title: exports_external3.string().min(1),
|
|
@@ -96412,7 +97052,7 @@ class HiveError3 extends Error {
|
|
|
96412
97052
|
}
|
|
96413
97053
|
}
|
|
96414
97054
|
function ensureHiveDirectory3(projectPath) {
|
|
96415
|
-
const hiveDir =
|
|
97055
|
+
const hiveDir = join13(projectPath, ".hive");
|
|
96416
97056
|
if (!existsSync13(hiveDir)) {
|
|
96417
97057
|
const { mkdirSync: mkdirSync7 } = __require("node:fs");
|
|
96418
97058
|
mkdirSync7(hiveDir, { recursive: true });
|
|
@@ -96469,7 +97109,7 @@ async function getHiveAdapter3(projectKey) {
|
|
|
96469
97109
|
return adapter;
|
|
96470
97110
|
}
|
|
96471
97111
|
async function autoMigrateFromJSONL3(adapter, projectKey) {
|
|
96472
|
-
const jsonlPath =
|
|
97112
|
+
const jsonlPath = join13(projectKey, ".hive", "issues.jsonl");
|
|
96473
97113
|
if (!existsSync13(jsonlPath)) {
|
|
96474
97114
|
return;
|
|
96475
97115
|
}
|
|
@@ -96483,13 +97123,13 @@ async function autoMigrateFromJSONL3(adapter, projectKey) {
|
|
|
96483
97123
|
skipExisting: true
|
|
96484
97124
|
});
|
|
96485
97125
|
if (result.created > 0 || result.updated > 0) {
|
|
96486
|
-
console.
|
|
97126
|
+
console.error(`[hive] Auto-migrated ${result.created} cells from ${jsonlPath} (${result.skipped} skipped, ${result.errors.length} errors)`);
|
|
96487
97127
|
}
|
|
96488
97128
|
if (result.errors.length > 0) {
|
|
96489
|
-
console.
|
|
97129
|
+
console.error(`[hive] Migration errors:`, result.errors.slice(0, 5).map((e) => `${e.cellId}: ${e.error}`));
|
|
96490
97130
|
}
|
|
96491
97131
|
} catch (error54) {
|
|
96492
|
-
console.
|
|
97132
|
+
console.error(`[hive] Failed to auto-migrate from ${jsonlPath}:`, error54 instanceof Error ? error54.message : String(error54));
|
|
96493
97133
|
}
|
|
96494
97134
|
}
|
|
96495
97135
|
function formatCellForOutput3(adapterCell) {
|
|
@@ -97090,7 +97730,7 @@ var hive_sync3 = tool3({
|
|
|
97090
97730
|
const flushResult = await withTimeout(flushManager.flush(), TIMEOUT_MS, "flush hive");
|
|
97091
97731
|
const swarmMail = await getSwarmMailLibSQL12(projectKey);
|
|
97092
97732
|
const db = await swarmMail.getDatabase();
|
|
97093
|
-
const hivePath =
|
|
97733
|
+
const hivePath = join13(projectKey, ".hive");
|
|
97094
97734
|
let memoriesSynced = 0;
|
|
97095
97735
|
try {
|
|
97096
97736
|
const memoryResult = await syncMemories3(db, hivePath);
|
|
@@ -97594,8 +98234,8 @@ function formatToolAvailability2(availability) {
|
|
|
97594
98234
|
// src/rate-limiter.ts
|
|
97595
98235
|
var import_ioredis = __toESM(require_built3(), 1);
|
|
97596
98236
|
import { mkdirSync as mkdirSync7, existsSync as existsSync14 } from "node:fs";
|
|
97597
|
-
import { dirname as dirname7, join as
|
|
97598
|
-
import { homedir as
|
|
98237
|
+
import { dirname as dirname7, join as join14 } from "node:path";
|
|
98238
|
+
import { homedir as homedir6 } from "node:os";
|
|
97599
98239
|
var sqliteAvailable = false;
|
|
97600
98240
|
var createDatabase = null;
|
|
97601
98241
|
try {
|
|
@@ -97855,7 +98495,7 @@ async function createRateLimiter(options2) {
|
|
|
97855
98495
|
const {
|
|
97856
98496
|
backend,
|
|
97857
98497
|
redisUrl = process.env.OPENCODE_RATE_LIMIT_REDIS_URL || "redis://localhost:6379",
|
|
97858
|
-
sqlitePath = process.env.OPENCODE_RATE_LIMIT_SQLITE_PATH ||
|
|
98498
|
+
sqlitePath = process.env.OPENCODE_RATE_LIMIT_SQLITE_PATH || join14(homedir6(), ".config", "opencode", "rate-limits.db")
|
|
97859
98499
|
} = options2 || {};
|
|
97860
98500
|
if (backend === "memory") {
|
|
97861
98501
|
return new InMemoryRateLimiter;
|
|
@@ -97921,7 +98561,7 @@ import {
|
|
|
97921
98561
|
writeFileSync as writeFileSync5,
|
|
97922
98562
|
unlinkSync
|
|
97923
98563
|
} from "fs";
|
|
97924
|
-
import { join as
|
|
98564
|
+
import { join as join15 } from "path";
|
|
97925
98565
|
import { tmpdir } from "os";
|
|
97926
98566
|
var AGENT_MAIL_URL = "http://127.0.0.1:8765";
|
|
97927
98567
|
var DEFAULT_TTL_SECONDS = 3600;
|
|
@@ -97942,10 +98582,10 @@ var RECOVERY_CONFIG = {
|
|
|
97942
98582
|
restartCooldownMs: 1e4,
|
|
97943
98583
|
enabled: process.env.OPENCODE_AGENT_MAIL_AUTO_RESTART !== "false"
|
|
97944
98584
|
};
|
|
97945
|
-
var SESSION_STATE_DIR = process.env.SWARM_STATE_DIR ||
|
|
98585
|
+
var SESSION_STATE_DIR = process.env.SWARM_STATE_DIR || join15(tmpdir(), "swarm-sessions");
|
|
97946
98586
|
function getSessionStatePath(sessionID) {
|
|
97947
98587
|
const safeID = sessionID.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
97948
|
-
return
|
|
98588
|
+
return join15(SESSION_STATE_DIR, `${safeID}.json`);
|
|
97949
98589
|
}
|
|
97950
98590
|
function loadSessionState(sessionID) {
|
|
97951
98591
|
const path4 = getSessionStatePath(sessionID);
|
|
@@ -98655,17 +99295,17 @@ import {
|
|
|
98655
99295
|
writeFileSync as writeFileSync6,
|
|
98656
99296
|
unlinkSync as unlinkSync2
|
|
98657
99297
|
} from "node:fs";
|
|
98658
|
-
import { join as
|
|
99298
|
+
import { join as join16 } from "node:path";
|
|
98659
99299
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
98660
99300
|
var MAX_INBOX_LIMIT2 = 5;
|
|
98661
99301
|
var swarmMailProjectDirectory = null;
|
|
98662
99302
|
function getSwarmMailProjectDirectory() {
|
|
98663
99303
|
return swarmMailProjectDirectory ?? undefined;
|
|
98664
99304
|
}
|
|
98665
|
-
var SESSION_STATE_DIR2 = process.env.SWARM_STATE_DIR ||
|
|
99305
|
+
var SESSION_STATE_DIR2 = process.env.SWARM_STATE_DIR || join16(tmpdir2(), "swarm-sessions");
|
|
98666
99306
|
function getSessionStatePath2(sessionID) {
|
|
98667
99307
|
const safeID = sessionID.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
98668
|
-
return
|
|
99308
|
+
return join16(SESSION_STATE_DIR2, `${safeID}.json`);
|
|
98669
99309
|
}
|
|
98670
99310
|
function loadSessionState2(sessionID) {
|
|
98671
99311
|
const path4 = getSessionStatePath2(sessionID);
|
|
@@ -101812,12 +102452,12 @@ init_skills2();
|
|
|
101812
102452
|
// src/swarm-worktree.ts
|
|
101813
102453
|
init_dist2();
|
|
101814
102454
|
init_zod3();
|
|
101815
|
-
import { join as
|
|
102455
|
+
import { join as join18 } from "node:path";
|
|
101816
102456
|
import { existsSync as existsSync17 } from "node:fs";
|
|
101817
102457
|
var WORKTREE_DIR2 = ".swarm/worktrees";
|
|
101818
102458
|
function getWorktreePath2(projectPath, taskId) {
|
|
101819
102459
|
const safeTaskId = taskId.replace(/[^a-zA-Z0-9.-]/g, "_");
|
|
101820
|
-
return
|
|
102460
|
+
return join18(projectPath, WORKTREE_DIR2, safeTaskId);
|
|
101821
102461
|
}
|
|
101822
102462
|
function parseTaskIdFromPath2(worktreePath) {
|
|
101823
102463
|
const parts2 = worktreePath.split("/");
|
|
@@ -101851,7 +102491,7 @@ async function getWorktreeCommits2(worktreePath, startCommit) {
|
|
|
101851
102491
|
`).filter((c) => c.length > 0);
|
|
101852
102492
|
}
|
|
101853
102493
|
async function ensureWorktreeDir2(projectPath) {
|
|
101854
|
-
const worktreeDir =
|
|
102494
|
+
const worktreeDir = join18(projectPath, WORKTREE_DIR2);
|
|
101855
102495
|
await Bun.$`mkdir -p ${worktreeDir}`.quiet().nothrow();
|
|
101856
102496
|
}
|
|
101857
102497
|
var swarm_worktree_create2 = tool3({
|
|
@@ -101988,7 +102628,7 @@ var swarm_worktree_cleanup2 = tool3({
|
|
|
101988
102628
|
return JSON.stringify(result3, null, 2);
|
|
101989
102629
|
}
|
|
101990
102630
|
const output = listResult.stdout.toString();
|
|
101991
|
-
const worktreeDir =
|
|
102631
|
+
const worktreeDir = join18(args2.project_path, WORKTREE_DIR2);
|
|
101992
102632
|
const worktrees = output.split(`
|
|
101993
102633
|
|
|
101994
102634
|
`).filter((block) => block.includes(worktreeDir)).map((block) => {
|
|
@@ -102053,7 +102693,7 @@ var swarm_worktree_list2 = tool3({
|
|
|
102053
102693
|
}, null, 2);
|
|
102054
102694
|
}
|
|
102055
102695
|
const output = listResult.stdout.toString();
|
|
102056
|
-
const worktreeDir =
|
|
102696
|
+
const worktreeDir = join18(args2.project_path, WORKTREE_DIR2);
|
|
102057
102697
|
const worktrees = [];
|
|
102058
102698
|
const blocks = output.split(`
|
|
102059
102699
|
|
|
@@ -103114,7 +103754,7 @@ var swarm_complete2 = tool3({
|
|
|
103114
103754
|
files_touched: tool3.schema.array(tool3.schema.string()).optional().describe("Files modified - will be verified (typecheck, tests)"),
|
|
103115
103755
|
skip_verification: tool3.schema.boolean().optional().describe("Skip ALL verification (typecheck, tests). Use sparingly! (default: false)"),
|
|
103116
103756
|
planned_files: tool3.schema.array(tool3.schema.string()).optional().describe("Files that were originally planned to be modified"),
|
|
103117
|
-
start_time: tool3.schema.number().
|
|
103757
|
+
start_time: tool3.schema.number().describe("Task start timestamp (Unix ms) for duration calculation - REQUIRED for accurate analytics"),
|
|
103118
103758
|
error_count: tool3.schema.number().optional().describe("Number of errors encountered during task"),
|
|
103119
103759
|
retry_count: tool3.schema.number().optional().describe("Number of retry attempts during task"),
|
|
103120
103760
|
skip_review: tool3.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review.")
|
|
@@ -103318,7 +103958,7 @@ This will be recorded as a negative learning signal.`;
|
|
|
103318
103958
|
syncError = error54 instanceof Error ? error54.message : String(error54);
|
|
103319
103959
|
console.warn(`[swarm_complete] Auto-sync failed (non-fatal): ${syncError}`);
|
|
103320
103960
|
}
|
|
103321
|
-
const completionDurationMs =
|
|
103961
|
+
const completionDurationMs = Date.now() - args2.start_time;
|
|
103322
103962
|
const eventEpicId = cell.parent_id || (args2.bead_id.includes(".") ? args2.bead_id.split(".")[0] : args2.bead_id);
|
|
103323
103963
|
try {
|
|
103324
103964
|
const event = createEvent8("subtask_outcome", {
|
|
@@ -105254,7 +105894,7 @@ var dedupeWith2 = /* @__PURE__ */ dual2(2, (self, isEquivalent) => {
|
|
|
105254
105894
|
return [];
|
|
105255
105895
|
});
|
|
105256
105896
|
var dedupe2 = (self) => dedupeWith2(self, equivalence2());
|
|
105257
|
-
var
|
|
105897
|
+
var join19 = /* @__PURE__ */ dual2(2, (self, sep4) => fromIterable8(self).join(sep4));
|
|
105258
105898
|
|
|
105259
105899
|
// ../../node_modules/.bun/effect@3.19.12/node_modules/effect/dist/esm/Number.js
|
|
105260
105900
|
var Order3 = number10;
|
|
@@ -109805,7 +110445,7 @@ var InvalidData2 = (path4, message, options2 = {
|
|
|
109805
110445
|
Object.defineProperty(error54, "toString", {
|
|
109806
110446
|
enumerable: false,
|
|
109807
110447
|
value() {
|
|
109808
|
-
const path10 = pipe4(this.path,
|
|
110448
|
+
const path10 = pipe4(this.path, join19(options2.pathDelim));
|
|
109809
110449
|
return `(Invalid data at ${path10}: "${this.message}")`;
|
|
109810
110450
|
}
|
|
109811
110451
|
});
|
|
@@ -109821,7 +110461,7 @@ var MissingData2 = (path4, message, options2 = {
|
|
|
109821
110461
|
Object.defineProperty(error54, "toString", {
|
|
109822
110462
|
enumerable: false,
|
|
109823
110463
|
value() {
|
|
109824
|
-
const path10 = pipe4(this.path,
|
|
110464
|
+
const path10 = pipe4(this.path, join19(options2.pathDelim));
|
|
109825
110465
|
return `(Missing data at ${path10}: "${this.message}")`;
|
|
109826
110466
|
}
|
|
109827
110467
|
});
|
|
@@ -109838,7 +110478,7 @@ var SourceUnavailable2 = (path4, message, cause3, options2 = {
|
|
|
109838
110478
|
Object.defineProperty(error54, "toString", {
|
|
109839
110479
|
enumerable: false,
|
|
109840
110480
|
value() {
|
|
109841
|
-
const path10 = pipe4(this.path,
|
|
110481
|
+
const path10 = pipe4(this.path, join19(options2.pathDelim));
|
|
109842
110482
|
return `(Source unavailable at ${path10}: "${this.message}")`;
|
|
109843
110483
|
}
|
|
109844
110484
|
});
|
|
@@ -109854,7 +110494,7 @@ var Unsupported2 = (path4, message, options2 = {
|
|
|
109854
110494
|
Object.defineProperty(error54, "toString", {
|
|
109855
110495
|
enumerable: false,
|
|
109856
110496
|
value() {
|
|
109857
|
-
const path10 = pipe4(this.path,
|
|
110497
|
+
const path10 = pipe4(this.path, join19(options2.pathDelim));
|
|
109858
110498
|
return `(Unsupported operation at ${path10}: "${this.message}")`;
|
|
109859
110499
|
}
|
|
109860
110500
|
});
|
|
@@ -109974,7 +110614,7 @@ var fromEnv2 = (options2) => {
|
|
|
109974
110614
|
pathDelim: "_",
|
|
109975
110615
|
seqDelim: ","
|
|
109976
110616
|
}, options2);
|
|
109977
|
-
const makePathString = (path4) => pipe4(path4,
|
|
110617
|
+
const makePathString = (path4) => pipe4(path4, join19(pathDelim));
|
|
109978
110618
|
const unmakePathString = (pathString) => pathString.split(pathDelim);
|
|
109979
110619
|
const getEnv = () => typeof process !== "undefined" && ("env" in process) && typeof process.env === "object" ? process.env : {};
|
|
109980
110620
|
const load = (path4, primitive, split = true) => {
|
|
@@ -110098,7 +110738,7 @@ var fromFlatLoop2 = (flat, prefix, config4, split) => {
|
|
|
110098
110738
|
return fail5(right4.left);
|
|
110099
110739
|
}
|
|
110100
110740
|
if (isRight5(left4) && isRight5(right4)) {
|
|
110101
|
-
const path4 = pipe4(prefix,
|
|
110741
|
+
const path4 = pipe4(prefix, join19("."));
|
|
110102
110742
|
const fail6 = fromFlatLoopFail2(prefix, path4);
|
|
110103
110743
|
const [lefts, rights] = extend4(fail6, fail6, pipe4(left4.right, map8(right5)), pipe4(right4.right, map8(right5)));
|
|
110104
110744
|
return pipe4(lefts, zip3(rights), forEachSequential2(([left6, right6]) => pipe4(zip5(left6, right6), map18(([left7, right7]) => op.zip(left7, right7)))));
|
|
@@ -112272,11 +112912,11 @@ var interruptAllAs2 = /* @__PURE__ */ dual2(2, /* @__PURE__ */ fnUntraced3(funct
|
|
|
112272
112912
|
}
|
|
112273
112913
|
}));
|
|
112274
112914
|
var interruptAsFork2 = /* @__PURE__ */ dual2(2, (self, fiberId4) => self.interruptAsFork(fiberId4));
|
|
112275
|
-
var
|
|
112915
|
+
var join20 = (self) => zipLeft3(flatten11(self.await), self.inheritAll);
|
|
112276
112916
|
var _never4 = {
|
|
112277
112917
|
...CommitPrototype3,
|
|
112278
112918
|
commit() {
|
|
112279
|
-
return
|
|
112919
|
+
return join20(this);
|
|
112280
112920
|
},
|
|
112281
112921
|
...fiberProto2,
|
|
112282
112922
|
id: () => none14,
|
|
@@ -113523,7 +114163,7 @@ class FiberRuntime2 extends Class4 {
|
|
|
113523
114163
|
this.refreshRefCache();
|
|
113524
114164
|
}
|
|
113525
114165
|
commit() {
|
|
113526
|
-
return
|
|
114166
|
+
return join20(this);
|
|
113527
114167
|
}
|
|
113528
114168
|
id() {
|
|
113529
114169
|
return this._fiberId;
|
|
@@ -114538,7 +115178,7 @@ var forEachConcurrentDiscard2 = (self, f, batching, processAll, n) => uninterrup
|
|
|
114538
115178
|
next();
|
|
114539
115179
|
}
|
|
114540
115180
|
}));
|
|
114541
|
-
return asVoid4(onExit4(flatten11(restore(
|
|
115181
|
+
return asVoid4(onExit4(flatten11(restore(join20(processingFiber))), exitMatch2({
|
|
114542
115182
|
onFailure: (cause4) => {
|
|
114543
115183
|
onInterruptSignal();
|
|
114544
115184
|
const target2 = residual.length + 1;
|
|
@@ -114860,7 +115500,7 @@ var fiberAll2 = (fibers) => {
|
|
|
114860
115500
|
const _fiberAll = {
|
|
114861
115501
|
...CommitPrototype5,
|
|
114862
115502
|
commit() {
|
|
114863
|
-
return
|
|
115503
|
+
return join20(this);
|
|
114864
115504
|
},
|
|
114865
115505
|
[FiberTypeId2]: fiberVariance5,
|
|
114866
115506
|
id: () => fromIterable8(fibers).reduce((id, fiber) => combine12(id, fiber.id()), none14),
|
|
@@ -114913,14 +115553,14 @@ var raceWith3 = /* @__PURE__ */ dual2(3, (self, other, options2) => raceFibersWi
|
|
|
114913
115553
|
}
|
|
114914
115554
|
})
|
|
114915
115555
|
}));
|
|
114916
|
-
var disconnect3 = (self) => uninterruptibleMask4((restore) => fiberIdWith3((fiberId4) => flatMap15(forkDaemon3(restore(self)), (fiber) => pipe4(restore(
|
|
115556
|
+
var disconnect3 = (self) => uninterruptibleMask4((restore) => fiberIdWith3((fiberId4) => flatMap15(forkDaemon3(restore(self)), (fiber) => pipe4(restore(join20(fiber)), onInterrupt3(() => pipe4(fiber, interruptAsFork2(fiberId4)))))));
|
|
114917
115557
|
var race3 = /* @__PURE__ */ dual2(2, (self, that) => fiberIdWith3((parentFiberId) => raceWith3(self, that, {
|
|
114918
115558
|
onSelfDone: (exit4, right4) => exitMatchEffect2(exit4, {
|
|
114919
|
-
onFailure: (cause4) => pipe4(
|
|
115559
|
+
onFailure: (cause4) => pipe4(join20(right4), mapErrorCause3((cause22) => parallel4(cause4, cause22))),
|
|
114920
115560
|
onSuccess: (value) => pipe4(right4, interruptAsFiber2(parentFiberId), as3(value))
|
|
114921
115561
|
}),
|
|
114922
115562
|
onOtherDone: (exit4, left4) => exitMatchEffect2(exit4, {
|
|
114923
|
-
onFailure: (cause4) => pipe4(
|
|
115563
|
+
onFailure: (cause4) => pipe4(join20(left4), mapErrorCause3((cause22) => parallel4(cause22, cause4))),
|
|
114924
115564
|
onSuccess: (value) => pipe4(left4, interruptAsFiber2(parentFiberId), as3(value))
|
|
114925
115565
|
})
|
|
114926
115566
|
})));
|
|
@@ -116074,8 +116714,8 @@ var forkIn3 = /* @__PURE__ */ dual2(2, (self, scope4) => withFiberRuntime3((pare
|
|
|
116074
116714
|
return succeed5(fiber);
|
|
116075
116715
|
}));
|
|
116076
116716
|
var forkScoped3 = (self) => scopeWith3((scope4) => forkIn3(self, scope4));
|
|
116077
|
-
var fromFiber3 = (fiber) =>
|
|
116078
|
-
var fromFiberEffect3 = (fiber) => suspend4(() => flatMap15(fiber,
|
|
116717
|
+
var fromFiber3 = (fiber) => join20(fiber);
|
|
116718
|
+
var fromFiberEffect3 = (fiber) => suspend4(() => flatMap15(fiber, join20));
|
|
116079
116719
|
var memoKeySymbol2 = /* @__PURE__ */ Symbol.for("effect/Effect/memoizeFunction.key");
|
|
116080
116720
|
|
|
116081
116721
|
class Key2 {
|
|
@@ -117659,14 +118299,14 @@ async function maybeAutoMigrate2(db) {
|
|
|
117659
118299
|
if (memoryCount > 0) {
|
|
117660
118300
|
return;
|
|
117661
118301
|
}
|
|
117662
|
-
console.
|
|
118302
|
+
console.error("[memory] Legacy database detected, starting auto-migration...");
|
|
117663
118303
|
const result = await migrateLegacyMemories2({
|
|
117664
118304
|
targetDb: db,
|
|
117665
118305
|
dryRun: false,
|
|
117666
|
-
onProgress: console.
|
|
118306
|
+
onProgress: (msg) => console.error(msg)
|
|
117667
118307
|
});
|
|
117668
118308
|
if (result.migrated > 0) {
|
|
117669
|
-
console.
|
|
118309
|
+
console.error(`[memory] Auto-migrated ${result.migrated} memories from legacy database`);
|
|
117670
118310
|
}
|
|
117671
118311
|
if (result.failed > 0) {
|
|
117672
118312
|
console.warn(`[memory] ${result.failed} memories failed to migrate. See errors above.`);
|
|
@@ -117735,6 +118375,7 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
117735
118375
|
async find(args3) {
|
|
117736
118376
|
const limit = args3.limit ?? 10;
|
|
117737
118377
|
let results;
|
|
118378
|
+
let usedFallback = false;
|
|
117738
118379
|
if (args3.fts) {
|
|
117739
118380
|
results = await store.ftsSearch(args3.query, {
|
|
117740
118381
|
limit,
|
|
@@ -117745,14 +118386,23 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
117745
118386
|
const ollama = yield* Ollama2;
|
|
117746
118387
|
return yield* ollama.embed(args3.query);
|
|
117747
118388
|
});
|
|
117748
|
-
|
|
117749
|
-
|
|
117750
|
-
|
|
117751
|
-
|
|
117752
|
-
|
|
117753
|
-
|
|
118389
|
+
try {
|
|
118390
|
+
const queryEmbedding = await exports_Effect2.runPromise(program.pipe(exports_Effect2.provide(ollamaLayer)));
|
|
118391
|
+
results = await store.search(queryEmbedding, {
|
|
118392
|
+
limit,
|
|
118393
|
+
threshold: 0.3,
|
|
118394
|
+
collection: args3.collection
|
|
118395
|
+
});
|
|
118396
|
+
} catch (e) {
|
|
118397
|
+
console.warn("[hivemind] Ollama unavailable, falling back to full-text search");
|
|
118398
|
+
usedFallback = true;
|
|
118399
|
+
results = await store.ftsSearch(args3.query, {
|
|
118400
|
+
limit,
|
|
118401
|
+
collection: args3.collection
|
|
118402
|
+
});
|
|
118403
|
+
}
|
|
117754
118404
|
}
|
|
117755
|
-
|
|
118405
|
+
const response = {
|
|
117756
118406
|
results: results.map((r) => ({
|
|
117757
118407
|
id: r.memory.id,
|
|
117758
118408
|
content: args3.expand ? r.memory.content : truncateContent(r.memory.content),
|
|
@@ -117763,6 +118413,10 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
117763
118413
|
})),
|
|
117764
118414
|
count: results.length
|
|
117765
118415
|
};
|
|
118416
|
+
if (usedFallback) {
|
|
118417
|
+
response.fallback_used = true;
|
|
118418
|
+
}
|
|
118419
|
+
return response;
|
|
117766
118420
|
},
|
|
117767
118421
|
async get(args3) {
|
|
117768
118422
|
return store.get(args3.id);
|
|
@@ -119301,7 +119955,7 @@ var promptTools2 = {
|
|
|
119301
119955
|
init_dist2();
|
|
119302
119956
|
import { existsSync as existsSync18 } from "node:fs";
|
|
119303
119957
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
119304
|
-
import { join as
|
|
119958
|
+
import { join as join21 } from "node:path";
|
|
119305
119959
|
|
|
119306
119960
|
// ../../node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/index.js
|
|
119307
119961
|
var composer = require_composer();
|
|
@@ -119479,20 +120133,20 @@ async function parsePackageJson(packageJsonPath, packages) {
|
|
|
119479
120133
|
}
|
|
119480
120134
|
}
|
|
119481
120135
|
async function getInstalledVersions(projectPath, packages, checkUpgrades = false) {
|
|
119482
|
-
const npmLock =
|
|
120136
|
+
const npmLock = join21(projectPath, "package-lock.json");
|
|
119483
120137
|
let versions2 = [];
|
|
119484
120138
|
if (existsSync18(npmLock)) {
|
|
119485
120139
|
versions2 = await parseNpmLockfile(npmLock, packages);
|
|
119486
120140
|
} else {
|
|
119487
|
-
const pnpmLock =
|
|
120141
|
+
const pnpmLock = join21(projectPath, "pnpm-lock.yaml");
|
|
119488
120142
|
if (existsSync18(pnpmLock)) {
|
|
119489
120143
|
versions2 = await parsePnpmLockfile(pnpmLock, packages);
|
|
119490
120144
|
} else {
|
|
119491
|
-
const yarnLock =
|
|
120145
|
+
const yarnLock = join21(projectPath, "yarn.lock");
|
|
119492
120146
|
if (existsSync18(yarnLock)) {
|
|
119493
120147
|
versions2 = await parseYarnLockfile(yarnLock, packages);
|
|
119494
120148
|
} else {
|
|
119495
|
-
const packageJson =
|
|
120149
|
+
const packageJson = join21(projectPath, "package.json");
|
|
119496
120150
|
if (existsSync18(packageJson)) {
|
|
119497
120151
|
versions2 = await parsePackageJson(packageJson, packages);
|
|
119498
120152
|
}
|
|
@@ -120644,7 +121298,7 @@ import {
|
|
|
120644
121298
|
} from "swarm-mail";
|
|
120645
121299
|
import * as os5 from "node:os";
|
|
120646
121300
|
import * as path10 from "node:path";
|
|
120647
|
-
import { join as
|
|
121301
|
+
import { join as join25 } from "node:path";
|
|
120648
121302
|
var cachedAdapter3 = null;
|
|
120649
121303
|
var cachedIndexer = null;
|
|
120650
121304
|
var cachedProjectPath3 = null;
|
|
@@ -120851,7 +121505,7 @@ var hivemind_sync = tool3({
|
|
|
120851
121505
|
const projectPath = cachedProjectPath3 || process.cwd();
|
|
120852
121506
|
const swarmMail = await getSwarmMailLibSQL16(projectPath);
|
|
120853
121507
|
const dbAdapter = await swarmMail.getDatabase();
|
|
120854
|
-
const hiveDir =
|
|
121508
|
+
const hiveDir = join25(projectPath, ".hive");
|
|
120855
121509
|
const result = await syncMemories4(dbAdapter, hiveDir);
|
|
120856
121510
|
await emitEvent("memories_synced", {
|
|
120857
121511
|
imported: result.imported.created,
|
|
@@ -121386,9 +122040,9 @@ import { checkSwarmHealth as checkSwarmHealth4 } from "swarm-mail";
|
|
|
121386
122040
|
// src/logger.ts
|
|
121387
122041
|
var import_pino = __toESM(require_pino(), 1);
|
|
121388
122042
|
import { mkdirSync as mkdirSync10, existsSync as existsSync19 } from "node:fs";
|
|
121389
|
-
import { join as
|
|
121390
|
-
import { homedir as
|
|
121391
|
-
var DEFAULT_LOG_DIR =
|
|
122043
|
+
import { join as join26 } from "node:path";
|
|
122044
|
+
import { homedir as homedir8 } from "node:os";
|
|
122045
|
+
var DEFAULT_LOG_DIR = join26(homedir8(), ".config", "swarm-tools", "logs");
|
|
121392
122046
|
function ensureLogDir(logDir) {
|
|
121393
122047
|
if (!existsSync19(logDir)) {
|
|
121394
122048
|
mkdirSync10(logDir, { recursive: true });
|
|
@@ -121407,7 +122061,7 @@ function getLogger(logDir = DEFAULT_LOG_DIR) {
|
|
|
121407
122061
|
let logger;
|
|
121408
122062
|
if (process.env.SWARM_LOG_FILE === "1") {
|
|
121409
122063
|
ensureLogDir(logDir);
|
|
121410
|
-
const logPath =
|
|
122064
|
+
const logPath = join26(logDir, "swarm.log");
|
|
121411
122065
|
logger = import_pino.default(baseConfig, import_pino.default.destination({ dest: logPath, sync: false }));
|
|
121412
122066
|
} else {
|
|
121413
122067
|
logger = import_pino.default(baseConfig);
|
|
@@ -121811,7 +122465,7 @@ var allTools = {
|
|
|
121811
122465
|
|
|
121812
122466
|
// bin/swarm.ts
|
|
121813
122467
|
var __dirname2 = dirname9(fileURLToPath3(import.meta.url));
|
|
121814
|
-
var pkgPath =
|
|
122468
|
+
var pkgPath = existsSync20(join28(__dirname2, "..", "package.json")) ? join28(__dirname2, "..", "package.json") : join28(__dirname2, "..", "..", "package.json");
|
|
121815
122469
|
var pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
|
|
121816
122470
|
var VERSION = pkg.version;
|
|
121817
122471
|
var BEE = `
|
|
@@ -122150,8 +122804,8 @@ function copyDirRecursiveSync(srcDir, destDir) {
|
|
|
122150
122804
|
mkdirSync11(destDir, { recursive: true });
|
|
122151
122805
|
const entries2 = readdirSync2(srcDir, { withFileTypes: true });
|
|
122152
122806
|
for (const entry of entries2) {
|
|
122153
|
-
const srcPath =
|
|
122154
|
-
const destPath =
|
|
122807
|
+
const srcPath = join28(srcDir, entry.name);
|
|
122808
|
+
const destPath = join28(destDir, entry.name);
|
|
122155
122809
|
if (entry.isDirectory()) {
|
|
122156
122810
|
copyDirRecursiveSync(srcPath, destPath);
|
|
122157
122811
|
continue;
|
|
@@ -122165,7 +122819,7 @@ function copyDirRecursiveSync(srcDir, destDir) {
|
|
|
122165
122819
|
}
|
|
122166
122820
|
}
|
|
122167
122821
|
function writeBundledSkillMarker(skillDir, info) {
|
|
122168
|
-
const markerPath =
|
|
122822
|
+
const markerPath = join28(skillDir, BUNDLED_SKILL_MARKER_FILENAME);
|
|
122169
122823
|
writeFileSync7(markerPath, JSON.stringify({
|
|
122170
122824
|
managed_by: "opencode-swarm-plugin",
|
|
122171
122825
|
version: info.version,
|
|
@@ -122182,9 +122836,9 @@ function syncBundledSkillsToGlobal({
|
|
|
122182
122836
|
const updated = [];
|
|
122183
122837
|
const skipped = [];
|
|
122184
122838
|
for (const name of bundledSkills) {
|
|
122185
|
-
const srcSkillDir =
|
|
122186
|
-
const destSkillDir =
|
|
122187
|
-
const markerPath =
|
|
122839
|
+
const srcSkillDir = join28(bundledSkillsPath, name);
|
|
122840
|
+
const destSkillDir = join28(globalSkillsPath, name);
|
|
122841
|
+
const markerPath = join28(destSkillDir, BUNDLED_SKILL_MARKER_FILENAME);
|
|
122188
122842
|
if (!existsSync20(destSkillDir)) {
|
|
122189
122843
|
copyDirRecursiveSync(srcSkillDir, destSkillDir);
|
|
122190
122844
|
writeBundledSkillMarker(destSkillDir, { version: version4 });
|
|
@@ -122213,7 +122867,7 @@ function backupFileWithTimestamp(filePath) {
|
|
|
122213
122867
|
const dir = dirname9(filePath);
|
|
122214
122868
|
const base = basename3(filePath);
|
|
122215
122869
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "").replace(/Z$/, "Z");
|
|
122216
|
-
const backupPath =
|
|
122870
|
+
const backupPath = join28(dir, `${base}.swarm-backup-${timestamp}`);
|
|
122217
122871
|
copyFileSync(filePath, backupPath);
|
|
122218
122872
|
return backupPath;
|
|
122219
122873
|
} catch {
|
|
@@ -122600,7 +123254,7 @@ function updateAgentsMdFile({
|
|
|
122600
123254
|
return { changed: true, backupPath, changes };
|
|
122601
123255
|
}
|
|
122602
123256
|
function getPluginWrapper() {
|
|
122603
|
-
const templatePath =
|
|
123257
|
+
const templatePath = join28(__dirname2, "..", "examples", "plugin-wrapper-template.ts");
|
|
122604
123258
|
try {
|
|
122605
123259
|
return readFileSync16(templatePath, "utf-8");
|
|
122606
123260
|
} catch (error54) {
|
|
@@ -123035,9 +123689,9 @@ async function doctor(debug = false) {
|
|
|
123035
123689
|
const requiredMissing = required4.filter((r) => !r.available);
|
|
123036
123690
|
const optionalMissing = optional4.filter((r) => !r.available);
|
|
123037
123691
|
p.log.step("Skills:");
|
|
123038
|
-
const configDir =
|
|
123039
|
-
const globalSkillsPath =
|
|
123040
|
-
const bundledSkillsPath =
|
|
123692
|
+
const configDir = join28(homedir10(), ".config", "opencode");
|
|
123693
|
+
const globalSkillsPath = join28(configDir, "skills");
|
|
123694
|
+
const bundledSkillsPath = join28(__dirname2, "..", "global-skills");
|
|
123041
123695
|
if (existsSync20(globalSkillsPath)) {
|
|
123042
123696
|
try {
|
|
123043
123697
|
const { readdirSync: readdirSync3 } = __require("fs");
|
|
@@ -123111,9 +123765,9 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123111
123765
|
p.log.success(`Bun v${bunCheck.version} detected`);
|
|
123112
123766
|
const cwd = process.cwd();
|
|
123113
123767
|
const tempDirName = getLibSQLProjectTempDirName(cwd);
|
|
123114
|
-
const tempDir =
|
|
123115
|
-
const pglitePath =
|
|
123116
|
-
const libsqlPath =
|
|
123768
|
+
const tempDir = join28(tmpdir3(), tempDirName);
|
|
123769
|
+
const pglitePath = join28(tempDir, "streams");
|
|
123770
|
+
const libsqlPath = join28(tempDir, "streams.db");
|
|
123117
123771
|
if (pgliteExists(pglitePath)) {
|
|
123118
123772
|
const migrateSpinner = p.spinner();
|
|
123119
123773
|
migrateSpinner.start("Migrating...");
|
|
@@ -123140,19 +123794,19 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123140
123794
|
}
|
|
123141
123795
|
let isReinstall = false;
|
|
123142
123796
|
p.log.step("Checking existing configuration...");
|
|
123143
|
-
const configDir =
|
|
123144
|
-
const pluginDir =
|
|
123145
|
-
const commandDir =
|
|
123146
|
-
const agentDir =
|
|
123147
|
-
const pluginPath =
|
|
123148
|
-
const commandPath =
|
|
123149
|
-
const plannerAgentPath =
|
|
123150
|
-
const workerAgentPath =
|
|
123151
|
-
const researcherAgentPath =
|
|
123152
|
-
const swarmAgentDir =
|
|
123153
|
-
const legacyPlannerPath =
|
|
123154
|
-
const legacyWorkerPath =
|
|
123155
|
-
const legacyResearcherPath =
|
|
123797
|
+
const configDir = join28(homedir10(), ".config", "opencode");
|
|
123798
|
+
const pluginDir = join28(configDir, "plugin");
|
|
123799
|
+
const commandDir = join28(configDir, "command");
|
|
123800
|
+
const agentDir = join28(configDir, "agent");
|
|
123801
|
+
const pluginPath = join28(pluginDir, "swarm.ts");
|
|
123802
|
+
const commandPath = join28(commandDir, "swarm.md");
|
|
123803
|
+
const plannerAgentPath = join28(agentDir, "swarm-planner.md");
|
|
123804
|
+
const workerAgentPath = join28(agentDir, "swarm-worker.md");
|
|
123805
|
+
const researcherAgentPath = join28(agentDir, "swarm-researcher.md");
|
|
123806
|
+
const swarmAgentDir = join28(agentDir, "swarm");
|
|
123807
|
+
const legacyPlannerPath = join28(swarmAgentDir, "planner.md");
|
|
123808
|
+
const legacyWorkerPath = join28(swarmAgentDir, "worker.md");
|
|
123809
|
+
const legacyResearcherPath = join28(swarmAgentDir, "researcher.md");
|
|
123156
123810
|
const existingFiles = [
|
|
123157
123811
|
pluginPath,
|
|
123158
123812
|
commandPath,
|
|
@@ -123386,7 +124040,7 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123386
124040
|
p.log.message(dim(" No legacy .beads directory found"));
|
|
123387
124041
|
}
|
|
123388
124042
|
p.log.step("Checking for legacy MCP servers...");
|
|
123389
|
-
const opencodeConfigPath =
|
|
124043
|
+
const opencodeConfigPath = join28(configDir, "config.json");
|
|
123390
124044
|
if (existsSync20(opencodeConfigPath)) {
|
|
123391
124045
|
try {
|
|
123392
124046
|
const opencodeConfig = JSON.parse(readFileSync16(opencodeConfigPath, "utf-8"));
|
|
@@ -123418,6 +124072,66 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123418
124072
|
} else {
|
|
123419
124073
|
p.log.message(dim(" No OpenCode config found (skipping MCP check)"));
|
|
123420
124074
|
}
|
|
124075
|
+
p.log.step("Checking for stray databases...");
|
|
124076
|
+
const globalDbPath = getGlobalDbPath2();
|
|
124077
|
+
try {
|
|
124078
|
+
const report = await consolidateDatabases(cwd, globalDbPath, {
|
|
124079
|
+
yes: nonInteractive,
|
|
124080
|
+
interactive: !nonInteractive
|
|
124081
|
+
});
|
|
124082
|
+
if (report.straysFound > 0) {
|
|
124083
|
+
if (report.totalRowsMigrated > 0) {
|
|
124084
|
+
p.log.success(`Migrated ${report.totalRowsMigrated} records from ${report.straysMigrated} stray database(s)`);
|
|
124085
|
+
for (const migration of report.migrations) {
|
|
124086
|
+
const { migrated, skipped } = migration.result;
|
|
124087
|
+
if (migrated > 0 || skipped > 0) {
|
|
124088
|
+
p.log.message(dim(` ${migration.path}: ${migrated} migrated, ${skipped} skipped`));
|
|
124089
|
+
}
|
|
124090
|
+
}
|
|
124091
|
+
} else {
|
|
124092
|
+
p.log.message(dim(" All data already in global database (no migration needed)"));
|
|
124093
|
+
}
|
|
124094
|
+
} else {
|
|
124095
|
+
p.log.message(dim(" No stray databases found"));
|
|
124096
|
+
}
|
|
124097
|
+
if (report.errors.length > 0) {
|
|
124098
|
+
p.log.warn(`${report.errors.length} error(s) during consolidation`);
|
|
124099
|
+
for (const error54 of report.errors) {
|
|
124100
|
+
p.log.message(dim(` ${error54}`));
|
|
124101
|
+
}
|
|
124102
|
+
}
|
|
124103
|
+
} catch (error54) {
|
|
124104
|
+
p.log.warn("Database consolidation check failed");
|
|
124105
|
+
if (error54 instanceof Error) {
|
|
124106
|
+
p.log.message(dim(` ${error54.message}`));
|
|
124107
|
+
}
|
|
124108
|
+
}
|
|
124109
|
+
p.log.step("Running database integrity check...");
|
|
124110
|
+
try {
|
|
124111
|
+
const repairResult = await runDbRepair({ dryRun: false });
|
|
124112
|
+
if (repairResult.totalCleaned === 0) {
|
|
124113
|
+
p.log.success("Database integrity verified - no issues found");
|
|
124114
|
+
} else {
|
|
124115
|
+
p.log.success(`Cleaned ${repairResult.totalCleaned} orphaned/invalid records`);
|
|
124116
|
+
if (repairResult.nullBeads > 0) {
|
|
124117
|
+
p.log.message(dim(` - ${repairResult.nullBeads} beads with NULL IDs`));
|
|
124118
|
+
}
|
|
124119
|
+
if (repairResult.orphanedRecipients > 0) {
|
|
124120
|
+
p.log.message(dim(` - ${repairResult.orphanedRecipients} orphaned message recipients`));
|
|
124121
|
+
}
|
|
124122
|
+
if (repairResult.messagesWithoutRecipients > 0) {
|
|
124123
|
+
p.log.message(dim(` - ${repairResult.messagesWithoutRecipients} messages without recipients`));
|
|
124124
|
+
}
|
|
124125
|
+
if (repairResult.expiredReservations > 0) {
|
|
124126
|
+
p.log.message(dim(` - ${repairResult.expiredReservations} expired reservations`));
|
|
124127
|
+
}
|
|
124128
|
+
}
|
|
124129
|
+
} catch (error54) {
|
|
124130
|
+
p.log.warn("Database repair check failed (non-critical)");
|
|
124131
|
+
if (error54 instanceof Error) {
|
|
124132
|
+
p.log.message(dim(` ${error54.message}`));
|
|
124133
|
+
}
|
|
124134
|
+
}
|
|
123421
124135
|
const DEFAULT_COORDINATOR = "anthropic/claude-opus-4-5";
|
|
123422
124136
|
const DEFAULT_WORKER = "anthropic/claude-sonnet-4-5";
|
|
123423
124137
|
const DEFAULT_LITE = "anthropic/claude-haiku-4-5";
|
|
@@ -123565,8 +124279,8 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123565
124279
|
p.log.message(dim(` Lite: ${liteModel}`));
|
|
123566
124280
|
p.log.step("Setting up OpenCode integration...");
|
|
123567
124281
|
const stats = { created: 0, updated: 0, unchanged: 0 };
|
|
123568
|
-
const legacySkillsDir =
|
|
123569
|
-
const skillsDir =
|
|
124282
|
+
const legacySkillsDir = join28(configDir, "skills");
|
|
124283
|
+
const skillsDir = join28(configDir, "skill");
|
|
123570
124284
|
if (existsSync20(legacySkillsDir) && !existsSync20(skillsDir)) {
|
|
123571
124285
|
p.log.step("Migrating skills directory...");
|
|
123572
124286
|
try {
|
|
@@ -123600,7 +124314,7 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123600
124314
|
} catch {}
|
|
123601
124315
|
}
|
|
123602
124316
|
p.log.message(dim(` Skills directory: ${skillsDir}`));
|
|
123603
|
-
const bundledSkillsPath =
|
|
124317
|
+
const bundledSkillsPath = join28(__dirname2, "..", "global-skills");
|
|
123604
124318
|
const bundledSkills = listDirectoryNames(bundledSkillsPath);
|
|
123605
124319
|
if (existsSync20(bundledSkillsPath)) {
|
|
123606
124320
|
if (bundledSkills.length > 0) {
|
|
@@ -123609,7 +124323,7 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123609
124323
|
}
|
|
123610
124324
|
if (bundledSkills.length > 0) {
|
|
123611
124325
|
const globalSkills = listDirectoryNames(skillsDir);
|
|
123612
|
-
const managedBundled = globalSkills.filter((name) => existsSync20(
|
|
124326
|
+
const managedBundled = globalSkills.filter((name) => existsSync20(join28(skillsDir, name, BUNDLED_SKILL_MARKER_FILENAME)));
|
|
123613
124327
|
const missingBundled = bundledSkills.filter((name) => !globalSkills.includes(name));
|
|
123614
124328
|
if (missingBundled.length > 0 || managedBundled.length > 0) {
|
|
123615
124329
|
{
|
|
@@ -123639,7 +124353,7 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123639
124353
|
}
|
|
123640
124354
|
}
|
|
123641
124355
|
}
|
|
123642
|
-
const agentsPath =
|
|
124356
|
+
const agentsPath = join28(configDir, "AGENTS.md");
|
|
123643
124357
|
if (existsSync20(agentsPath)) {
|
|
123644
124358
|
{
|
|
123645
124359
|
const s2 = p.spinner();
|
|
@@ -123806,14 +124520,14 @@ async function version4() {
|
|
|
123806
124520
|
showUpdateNotification(updateInfo3);
|
|
123807
124521
|
}
|
|
123808
124522
|
function config4() {
|
|
123809
|
-
const configDir =
|
|
123810
|
-
const pluginPath =
|
|
123811
|
-
const commandPath =
|
|
123812
|
-
const agentDir =
|
|
123813
|
-
const plannerAgentPath =
|
|
123814
|
-
const workerAgentPath =
|
|
123815
|
-
const researcherAgentPath =
|
|
123816
|
-
const globalSkillsPath =
|
|
124523
|
+
const configDir = join28(homedir10(), ".config", "opencode");
|
|
124524
|
+
const pluginPath = join28(configDir, "plugin", "swarm.ts");
|
|
124525
|
+
const commandPath = join28(configDir, "command", "swarm.md");
|
|
124526
|
+
const agentDir = join28(configDir, "agent");
|
|
124527
|
+
const plannerAgentPath = join28(agentDir, "swarm-planner.md");
|
|
124528
|
+
const workerAgentPath = join28(agentDir, "swarm-worker.md");
|
|
124529
|
+
const researcherAgentPath = join28(agentDir, "swarm-researcher.md");
|
|
124530
|
+
const globalSkillsPath = join28(configDir, "skills");
|
|
123817
124531
|
console.log(yellow(BANNER));
|
|
123818
124532
|
console.log(dim(" " + TAGLINE + " v" + VERSION));
|
|
123819
124533
|
console.log();
|
|
@@ -123856,7 +124570,7 @@ function config4() {
|
|
|
123856
124570
|
console.log(` ${dim(".claude/skills/")}`);
|
|
123857
124571
|
console.log(` ${dim("skill/")}`);
|
|
123858
124572
|
console.log();
|
|
123859
|
-
const bundledSkillsPath =
|
|
124573
|
+
const bundledSkillsPath = join28(__dirname2, "..", "global-skills");
|
|
123860
124574
|
if (existsSync20(bundledSkillsPath)) {
|
|
123861
124575
|
try {
|
|
123862
124576
|
const { readdirSync: readdirSync3 } = __require("fs");
|
|
@@ -124285,6 +124999,7 @@ ${cyan("Stats & History:")}
|
|
|
124285
124999
|
swarm stats Show swarm health metrics powered by swarm-insights (last 7 days)
|
|
124286
125000
|
swarm stats --since 24h Show stats for custom time period
|
|
124287
125001
|
swarm stats --regressions Show eval regressions (>10% score drops)
|
|
125002
|
+
swarm stats --rejections Show rejection reason analytics
|
|
124288
125003
|
swarm stats --json Output as JSON for scripting
|
|
124289
125004
|
swarm o11y Show observability health dashboard (hook coverage, events, sessions)
|
|
124290
125005
|
swarm o11y --since 7d Custom time period for event stats (default: 7 days)
|
|
@@ -124426,7 +125141,7 @@ async function listTools() {
|
|
|
124426
125141
|
}
|
|
124427
125142
|
async function agents(nonInteractive = false) {
|
|
124428
125143
|
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
124429
|
-
const agentsPath =
|
|
125144
|
+
const agentsPath = join28(home, ".config", "opencode", "AGENTS.md");
|
|
124430
125145
|
p.intro(yellow(BANNER));
|
|
124431
125146
|
if (!existsSync20(agentsPath)) {
|
|
124432
125147
|
p.log.warn("No AGENTS.md found at " + agentsPath);
|
|
@@ -124500,9 +125215,9 @@ async function migrate() {
|
|
|
124500
125215
|
p.intro("swarm migrate v" + VERSION);
|
|
124501
125216
|
const projectPath = process.cwd();
|
|
124502
125217
|
const tempDirName = getLibSQLProjectTempDirName(projectPath);
|
|
124503
|
-
const tempDir =
|
|
124504
|
-
const pglitePath =
|
|
124505
|
-
const libsqlPath =
|
|
125218
|
+
const tempDir = join28(tmpdir3(), tempDirName);
|
|
125219
|
+
const pglitePath = join28(tempDir, "streams");
|
|
125220
|
+
const libsqlPath = join28(tempDir, "streams.db");
|
|
124506
125221
|
if (!pgliteExists(pglitePath)) {
|
|
124507
125222
|
p.log.success("No PGlite database found - nothing to migrate!");
|
|
124508
125223
|
p.outro("Done");
|
|
@@ -124611,7 +125326,7 @@ function listSessionFiles(dir) {
|
|
|
124611
125326
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".jsonl"));
|
|
124612
125327
|
const sessions = [];
|
|
124613
125328
|
for (const file4 of files) {
|
|
124614
|
-
const filePath =
|
|
125329
|
+
const filePath = join28(dir, file4);
|
|
124615
125330
|
try {
|
|
124616
125331
|
const events = parseSessionFile(filePath);
|
|
124617
125332
|
if (events.length === 0)
|
|
@@ -124661,7 +125376,7 @@ function formatEvent(event, useColor = true) {
|
|
|
124661
125376
|
}
|
|
124662
125377
|
async function logSessions() {
|
|
124663
125378
|
const args3 = process.argv.slice(4);
|
|
124664
|
-
const sessionsDir =
|
|
125379
|
+
const sessionsDir = join28(homedir10(), ".config", "swarm-tools", "sessions");
|
|
124665
125380
|
let sessionId = null;
|
|
124666
125381
|
let latest = false;
|
|
124667
125382
|
let jsonOutput = false;
|
|
@@ -124865,7 +125580,7 @@ function readLogFiles(dir) {
|
|
|
124865
125580
|
if (!existsSync20(dir))
|
|
124866
125581
|
return [];
|
|
124867
125582
|
const allFiles = readdirSync2(dir);
|
|
124868
|
-
const logFiles = allFiles.filter((f) => /\.\d+log$/.test(f) || /\.log$/.test(f)).sort().map((f) =>
|
|
125583
|
+
const logFiles = allFiles.filter((f) => /\.\d+log$/.test(f) || /\.log$/.test(f)).sort().map((f) => join28(dir, f));
|
|
124869
125584
|
const entries2 = [];
|
|
124870
125585
|
for (const file4 of logFiles) {
|
|
124871
125586
|
try {
|
|
@@ -125050,7 +125765,7 @@ async function logs() {
|
|
|
125050
125765
|
moduleFilter = arg;
|
|
125051
125766
|
}
|
|
125052
125767
|
}
|
|
125053
|
-
const logsDir =
|
|
125768
|
+
const logsDir = join28(homedir10(), ".config", "swarm-tools", "logs");
|
|
125054
125769
|
if (!existsSync20(logsDir)) {
|
|
125055
125770
|
if (!jsonOutput) {
|
|
125056
125771
|
p.log.warn("No logs directory found");
|
|
@@ -125088,7 +125803,7 @@ async function logs() {
|
|
|
125088
125803
|
return;
|
|
125089
125804
|
const files = readdirSync2(logsDir).filter((f) => /\.\d+log$/.test(f) || /\.log$/.test(f));
|
|
125090
125805
|
for (const file4 of files) {
|
|
125091
|
-
const filePath =
|
|
125806
|
+
const filePath = join28(logsDir, file4);
|
|
125092
125807
|
try {
|
|
125093
125808
|
const stats = statSync2(filePath);
|
|
125094
125809
|
filePositions.set(filePath, stats.size);
|
|
@@ -125126,7 +125841,7 @@ async function logs() {
|
|
|
125126
125841
|
return;
|
|
125127
125842
|
const files = readdirSync2(logsDir).filter((f) => /\.\d+log$/.test(f) || /\.log$/.test(f));
|
|
125128
125843
|
for (const file4 of files) {
|
|
125129
|
-
const filePath =
|
|
125844
|
+
const filePath = join28(logsDir, file4);
|
|
125130
125845
|
const newLines = readNewLines(filePath);
|
|
125131
125846
|
for (const line of newLines) {
|
|
125132
125847
|
const parsed = parseLogLine(line, filePath);
|
|
@@ -125177,7 +125892,112 @@ async function logs() {
|
|
|
125177
125892
|
console.log();
|
|
125178
125893
|
}
|
|
125179
125894
|
}
|
|
125895
|
+
async function runDbRepair(options2) {
|
|
125896
|
+
const { dryRun } = options2;
|
|
125897
|
+
const globalDbPath = getGlobalDbPath2();
|
|
125898
|
+
const swarmMail = await getSwarmMailLibSQL19(globalDbPath);
|
|
125899
|
+
const db = await swarmMail.getDatabase();
|
|
125900
|
+
const nullBeadsResult = await db.query("SELECT COUNT(*) as count FROM beads WHERE id IS NULL");
|
|
125901
|
+
const nullBeads = Number(nullBeadsResult[0]?.count ?? 0);
|
|
125902
|
+
const orphanedRecipientsResult = await db.query("SELECT COUNT(*) as count FROM message_recipients WHERE NOT EXISTS (SELECT 1 FROM agents WHERE agents.name = message_recipients.agent_name)");
|
|
125903
|
+
const orphanedRecipients = Number(orphanedRecipientsResult[0]?.count ?? 0);
|
|
125904
|
+
const messagesWithoutRecipientsResult = await db.query("SELECT COUNT(*) as count FROM messages WHERE NOT EXISTS (SELECT 1 FROM message_recipients WHERE message_recipients.message_id = messages.id)");
|
|
125905
|
+
const messagesWithoutRecipients = Number(messagesWithoutRecipientsResult[0]?.count ?? 0);
|
|
125906
|
+
const expiredReservationsResult = await db.query("SELECT COUNT(*) as count FROM reservations WHERE released_at IS NULL AND expires_at < strftime('%s', 'now') * 1000");
|
|
125907
|
+
const expiredReservations = Number(expiredReservationsResult[0]?.count ?? 0);
|
|
125908
|
+
const totalCleaned = nullBeads + orphanedRecipients + messagesWithoutRecipients + expiredReservations;
|
|
125909
|
+
if (dryRun || totalCleaned === 0) {
|
|
125910
|
+
return {
|
|
125911
|
+
nullBeads,
|
|
125912
|
+
orphanedRecipients,
|
|
125913
|
+
messagesWithoutRecipients,
|
|
125914
|
+
expiredReservations,
|
|
125915
|
+
totalCleaned
|
|
125916
|
+
};
|
|
125917
|
+
}
|
|
125918
|
+
if (nullBeads > 0) {
|
|
125919
|
+
await db.query("DELETE FROM beads WHERE id IS NULL");
|
|
125920
|
+
}
|
|
125921
|
+
if (orphanedRecipients > 0) {
|
|
125922
|
+
await db.query("DELETE FROM message_recipients WHERE NOT EXISTS (SELECT 1 FROM agents WHERE agents.name = message_recipients.agent_name)");
|
|
125923
|
+
}
|
|
125924
|
+
if (messagesWithoutRecipients > 0) {
|
|
125925
|
+
await db.query("DELETE FROM messages WHERE NOT EXISTS (SELECT 1 FROM message_recipients WHERE message_recipients.message_id = messages.id)");
|
|
125926
|
+
}
|
|
125927
|
+
if (expiredReservations > 0) {
|
|
125928
|
+
await db.query("UPDATE reservations SET released_at = strftime('%s', 'now') * 1000 WHERE released_at IS NULL AND expires_at < strftime('%s', 'now') * 1000");
|
|
125929
|
+
}
|
|
125930
|
+
return {
|
|
125931
|
+
nullBeads,
|
|
125932
|
+
orphanedRecipients,
|
|
125933
|
+
messagesWithoutRecipients,
|
|
125934
|
+
expiredReservations,
|
|
125935
|
+
totalCleaned
|
|
125936
|
+
};
|
|
125937
|
+
}
|
|
125938
|
+
async function dbRepair() {
|
|
125939
|
+
const args3 = process.argv.slice(4);
|
|
125940
|
+
let dryRun = false;
|
|
125941
|
+
for (const arg of args3) {
|
|
125942
|
+
if (arg === "--dry-run") {
|
|
125943
|
+
dryRun = true;
|
|
125944
|
+
}
|
|
125945
|
+
}
|
|
125946
|
+
p.intro(dryRun ? "swarm db repair (DRY RUN)" : "swarm db repair");
|
|
125947
|
+
const s = p.spinner();
|
|
125948
|
+
s.start("Analyzing database...");
|
|
125949
|
+
try {
|
|
125950
|
+
const result = await runDbRepair({ dryRun: true });
|
|
125951
|
+
s.stop("Analysis complete");
|
|
125952
|
+
p.log.step(dryRun ? "Would delete:" : "Deleting:");
|
|
125953
|
+
if (result.nullBeads > 0) {
|
|
125954
|
+
p.log.message(` - ${result.nullBeads} beads with NULL IDs`);
|
|
125955
|
+
}
|
|
125956
|
+
if (result.orphanedRecipients > 0) {
|
|
125957
|
+
p.log.message(` - ${result.orphanedRecipients} orphaned message_recipients`);
|
|
125958
|
+
}
|
|
125959
|
+
if (result.messagesWithoutRecipients > 0) {
|
|
125960
|
+
p.log.message(` - ${result.messagesWithoutRecipients} messages without recipients`);
|
|
125961
|
+
}
|
|
125962
|
+
if (result.expiredReservations > 0) {
|
|
125963
|
+
p.log.message(` - ${result.expiredReservations} expired unreleased reservations`);
|
|
125964
|
+
}
|
|
125965
|
+
if (result.totalCleaned === 0) {
|
|
125966
|
+
p.outro(green("\u2713 Database is clean! No records to delete."));
|
|
125967
|
+
return;
|
|
125968
|
+
}
|
|
125969
|
+
console.log();
|
|
125970
|
+
p.log.message(dim(`Total: ${result.totalCleaned} records ${dryRun ? "would be" : "will be"} cleaned`));
|
|
125971
|
+
console.log();
|
|
125972
|
+
if (dryRun) {
|
|
125973
|
+
p.outro(dim("Run without --dry-run to execute cleanup"));
|
|
125974
|
+
return;
|
|
125975
|
+
}
|
|
125976
|
+
const confirmed = await p.confirm({
|
|
125977
|
+
message: `Delete ${result.totalCleaned} records?`,
|
|
125978
|
+
initialValue: false
|
|
125979
|
+
});
|
|
125980
|
+
if (p.isCancel(confirmed) || !confirmed) {
|
|
125981
|
+
p.cancel("Cleanup cancelled");
|
|
125982
|
+
return;
|
|
125983
|
+
}
|
|
125984
|
+
const cleanupSpinner = p.spinner();
|
|
125985
|
+
cleanupSpinner.start("Cleaning database...");
|
|
125986
|
+
await runDbRepair({ dryRun: false });
|
|
125987
|
+
cleanupSpinner.stop("Cleanup complete");
|
|
125988
|
+
p.outro(green(`\u2713 Successfully cleaned ${result.totalCleaned} records`));
|
|
125989
|
+
} catch (error54) {
|
|
125990
|
+
s.stop("Error");
|
|
125991
|
+
p.log.error(error54 instanceof Error ? error54.message : String(error54));
|
|
125992
|
+
process.exit(1);
|
|
125993
|
+
}
|
|
125994
|
+
}
|
|
125180
125995
|
async function db() {
|
|
125996
|
+
const args3 = process.argv.slice(3);
|
|
125997
|
+
if (args3[0] === "repair") {
|
|
125998
|
+
await dbRepair();
|
|
125999
|
+
return;
|
|
126000
|
+
}
|
|
125181
126001
|
const projectPath = process.cwd();
|
|
125182
126002
|
const projectName = basename3(projectPath);
|
|
125183
126003
|
const hash5 = hashLibSQLProjectPath(projectPath);
|
|
@@ -125238,7 +126058,7 @@ async function db() {
|
|
|
125238
126058
|
console.log(dim(" Will be created on first use"));
|
|
125239
126059
|
}
|
|
125240
126060
|
console.log();
|
|
125241
|
-
const pglitePath =
|
|
126061
|
+
const pglitePath = join28(dbDir, "streams");
|
|
125242
126062
|
if (existsSync20(pglitePath)) {
|
|
125243
126063
|
console.log(` \x1B[33m!\x1B[0m Legacy PGLite directory exists`);
|
|
125244
126064
|
console.log(dim(` ${pglitePath}`));
|
|
@@ -125349,6 +126169,7 @@ async function stats() {
|
|
|
125349
126169
|
let period = "7d";
|
|
125350
126170
|
let format5 = "text";
|
|
125351
126171
|
let showRegressions = false;
|
|
126172
|
+
let showRejections = false;
|
|
125352
126173
|
for (let i = 0;i < args3.length; i++) {
|
|
125353
126174
|
if (args3[i] === "--since" || args3[i] === "-s") {
|
|
125354
126175
|
period = args3[i + 1] || "7d";
|
|
@@ -125357,6 +126178,8 @@ async function stats() {
|
|
|
125357
126178
|
format5 = "json";
|
|
125358
126179
|
} else if (args3[i] === "--regressions") {
|
|
125359
126180
|
showRegressions = true;
|
|
126181
|
+
} else if (args3[i] === "--rejections") {
|
|
126182
|
+
showRejections = true;
|
|
125360
126183
|
}
|
|
125361
126184
|
}
|
|
125362
126185
|
try {
|
|
@@ -125385,21 +126208,21 @@ async function stats() {
|
|
|
125385
126208
|
strategy: row.strategy,
|
|
125386
126209
|
success: row.success === "true"
|
|
125387
126210
|
})));
|
|
125388
|
-
const sessionsPath =
|
|
126211
|
+
const sessionsPath = join28(homedir10(), ".config", "swarm-tools", "sessions");
|
|
125389
126212
|
let coordinatorStats = {
|
|
125390
126213
|
violationRate: 0,
|
|
125391
126214
|
spawnEfficiency: 0,
|
|
125392
126215
|
reviewThoroughness: 0
|
|
125393
126216
|
};
|
|
125394
126217
|
if (existsSync20(sessionsPath)) {
|
|
125395
|
-
const sessionFiles = readdirSync2(sessionsPath).filter((f) => f.endsWith(".jsonl") && statSync2(
|
|
126218
|
+
const sessionFiles = readdirSync2(sessionsPath).filter((f) => f.endsWith(".jsonl") && statSync2(join28(sessionsPath, f)).mtimeMs >= since);
|
|
125396
126219
|
let totalViolations = 0;
|
|
125397
126220
|
let totalSpawns = 0;
|
|
125398
126221
|
let totalReviews = 0;
|
|
125399
126222
|
let totalSwarms = 0;
|
|
125400
126223
|
for (const file4 of sessionFiles) {
|
|
125401
126224
|
try {
|
|
125402
|
-
const content = readFileSync16(
|
|
126225
|
+
const content = readFileSync16(join28(sessionsPath, file4), "utf-8");
|
|
125403
126226
|
const lines = content.trim().split(`
|
|
125404
126227
|
`);
|
|
125405
126228
|
let violations = 0;
|
|
@@ -125464,6 +126287,34 @@ async function stats() {
|
|
|
125464
126287
|
`);
|
|
125465
126288
|
}
|
|
125466
126289
|
}
|
|
126290
|
+
} else if (showRejections) {
|
|
126291
|
+
const rejectionAnalytics = await getRejectionAnalytics2(swarmMail);
|
|
126292
|
+
if (format5 === "json") {
|
|
126293
|
+
console.log(JSON.stringify(rejectionAnalytics, null, 2));
|
|
126294
|
+
} else {
|
|
126295
|
+
console.log();
|
|
126296
|
+
const boxWidth = 61;
|
|
126297
|
+
const pad = (text2) => text2 + " ".repeat(Math.max(0, boxWidth - text2.length));
|
|
126298
|
+
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
126299
|
+
console.log("\u2502" + pad(" REJECTION ANALYSIS (last " + period + ")") + "\u2502");
|
|
126300
|
+
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
126301
|
+
console.log("\u2502" + pad(" Total Reviews: " + rejectionAnalytics.totalReviews) + "\u2502");
|
|
126302
|
+
const rejectionRate = rejectionAnalytics.totalReviews > 0 ? (100 - rejectionAnalytics.approvalRate).toFixed(0) : "0";
|
|
126303
|
+
console.log("\u2502" + pad(" Approved: " + rejectionAnalytics.approved + " (" + rejectionAnalytics.approvalRate.toFixed(0) + "%)") + "\u2502");
|
|
126304
|
+
console.log("\u2502" + pad(" Rejected: " + rejectionAnalytics.rejected + " (" + rejectionRate + "%)") + "\u2502");
|
|
126305
|
+
console.log("\u2502" + pad("") + "\u2502");
|
|
126306
|
+
if (rejectionAnalytics.topReasons.length > 0) {
|
|
126307
|
+
console.log("\u2502" + pad(" Top Rejection Reasons:") + "\u2502");
|
|
126308
|
+
for (const reason of rejectionAnalytics.topReasons) {
|
|
126309
|
+
const line = " \u251C\u2500\u2500 " + reason.category + ": " + reason.count + " (" + reason.percentage.toFixed(0) + "%)";
|
|
126310
|
+
console.log("\u2502" + pad(line) + "\u2502");
|
|
126311
|
+
}
|
|
126312
|
+
} else {
|
|
126313
|
+
console.log("\u2502" + pad(" No rejections in this period") + "\u2502");
|
|
126314
|
+
}
|
|
126315
|
+
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
126316
|
+
console.log();
|
|
126317
|
+
}
|
|
125467
126318
|
} else {
|
|
125468
126319
|
if (format5 === "json") {
|
|
125469
126320
|
console.log(JSON.stringify(stats2, null, 2));
|
|
@@ -125689,7 +126540,7 @@ async function evalRun() {
|
|
|
125689
126540
|
}
|
|
125690
126541
|
}
|
|
125691
126542
|
if (ciMode) {
|
|
125692
|
-
const resultsPath =
|
|
126543
|
+
const resultsPath = join28(projectPath, ".hive", "eval-results.json");
|
|
125693
126544
|
ensureHiveDirectory(projectPath);
|
|
125694
126545
|
writeFileSync7(resultsPath, JSON.stringify(results, null, 2));
|
|
125695
126546
|
console.log(`
|
|
@@ -125877,11 +126728,11 @@ async function memory() {
|
|
|
125877
126728
|
try {
|
|
125878
126729
|
const { getDb: getDb2 } = await import("swarm-mail");
|
|
125879
126730
|
const tempDirName = getLibSQLProjectTempDirName(projectPath);
|
|
125880
|
-
const tempDir =
|
|
126731
|
+
const tempDir = join28(tmpdir3(), tempDirName);
|
|
125881
126732
|
if (!existsSync20(tempDir)) {
|
|
125882
126733
|
mkdirSync11(tempDir, { recursive: true });
|
|
125883
126734
|
}
|
|
125884
|
-
const dbPath =
|
|
126735
|
+
const dbPath = join28(tempDir, "streams.db");
|
|
125885
126736
|
const dbUrl = `file://${dbPath}`;
|
|
125886
126737
|
const db2 = await getDb2(dbUrl);
|
|
125887
126738
|
const { createMemoryAdapter: createMemoryAdapter3 } = await import("swarm-mail");
|