opencode-swarm-plugin 0.48.0 → 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 +1055 -188
- 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 +386 -18
- package/dist/memory.d.ts.map +1 -1
- package/dist/plugin.js +383 -18
- 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-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +1 -1
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-prompts.js +345 -18
- 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", {
|
|
@@ -77826,12 +78300,18 @@ This will be recorded as a negative learning signal.`;
|
|
|
77826
78300
|
memoryError = `Failed to store memory: ${error452 instanceof Error ? error452.message : String(error452)}`;
|
|
77827
78301
|
console.warn(`[swarm_complete] ${memoryError}`);
|
|
77828
78302
|
}
|
|
78303
|
+
let reservationsReleased = false;
|
|
78304
|
+
let reservationsReleasedCount = 0;
|
|
78305
|
+
let reservationsReleaseError;
|
|
77829
78306
|
try {
|
|
77830
|
-
await releaseSwarmFiles({
|
|
78307
|
+
const releaseResult = await releaseSwarmFiles({
|
|
77831
78308
|
projectPath: args.project_key,
|
|
77832
78309
|
agentName: args.agent_name
|
|
77833
78310
|
});
|
|
78311
|
+
reservationsReleased = true;
|
|
78312
|
+
reservationsReleasedCount = releaseResult.released;
|
|
77834
78313
|
} catch (error452) {
|
|
78314
|
+
reservationsReleaseError = error452 instanceof Error ? error452.message : String(error452);
|
|
77835
78315
|
console.warn(`[swarm] Failed to release file reservations for ${args.agent_name}:`, error452);
|
|
77836
78316
|
}
|
|
77837
78317
|
const epicId2 = args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id;
|
|
@@ -77867,7 +78347,9 @@ This will be recorded as a negative learning signal.`;
|
|
|
77867
78347
|
success: true,
|
|
77868
78348
|
bead_id: args.bead_id,
|
|
77869
78349
|
closed: true,
|
|
77870
|
-
reservations_released:
|
|
78350
|
+
reservations_released: reservationsReleased,
|
|
78351
|
+
reservations_released_count: reservationsReleasedCount,
|
|
78352
|
+
reservations_release_error: reservationsReleaseError,
|
|
77871
78353
|
synced: syncSuccess,
|
|
77872
78354
|
sync_error: syncError,
|
|
77873
78355
|
message_sent: messageSent,
|
|
@@ -91816,14 +92298,14 @@ async function maybeAutoMigrate(db) {
|
|
|
91816
92298
|
if (memoryCount > 0) {
|
|
91817
92299
|
return;
|
|
91818
92300
|
}
|
|
91819
|
-
console.
|
|
92301
|
+
console.error("[memory] Legacy database detected, starting auto-migration...");
|
|
91820
92302
|
const result = await migrateLegacyMemories({
|
|
91821
92303
|
targetDb: db,
|
|
91822
92304
|
dryRun: false,
|
|
91823
|
-
onProgress: console.
|
|
92305
|
+
onProgress: (msg) => console.error(msg)
|
|
91824
92306
|
});
|
|
91825
92307
|
if (result.migrated > 0) {
|
|
91826
|
-
console.
|
|
92308
|
+
console.error(`[memory] Auto-migrated ${result.migrated} memories from legacy database`);
|
|
91827
92309
|
}
|
|
91828
92310
|
if (result.failed > 0) {
|
|
91829
92311
|
console.warn(`[memory] ${result.failed} memories failed to migrate. See errors above.`);
|
|
@@ -91892,6 +92374,7 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
91892
92374
|
async find(args2) {
|
|
91893
92375
|
const limit = args2.limit ?? 10;
|
|
91894
92376
|
let results;
|
|
92377
|
+
let usedFallback = false;
|
|
91895
92378
|
if (args2.fts) {
|
|
91896
92379
|
results = await store.ftsSearch(args2.query, {
|
|
91897
92380
|
limit,
|
|
@@ -91902,14 +92385,23 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
91902
92385
|
const ollama = yield* Ollama;
|
|
91903
92386
|
return yield* ollama.embed(args2.query);
|
|
91904
92387
|
});
|
|
91905
|
-
|
|
91906
|
-
|
|
91907
|
-
|
|
91908
|
-
|
|
91909
|
-
|
|
91910
|
-
|
|
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
|
+
}
|
|
91911
92403
|
}
|
|
91912
|
-
|
|
92404
|
+
const response = {
|
|
91913
92405
|
results: results.map((r) => ({
|
|
91914
92406
|
id: r.memory.id,
|
|
91915
92407
|
content: args2.expand ? r.memory.content : truncateContent(r.memory.content),
|
|
@@ -91920,6 +92412,10 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
91920
92412
|
})),
|
|
91921
92413
|
count: results.length
|
|
91922
92414
|
};
|
|
92415
|
+
if (usedFallback) {
|
|
92416
|
+
response.fallback_used = true;
|
|
92417
|
+
}
|
|
92418
|
+
return response;
|
|
91923
92419
|
},
|
|
91924
92420
|
async get(args2) {
|
|
91925
92421
|
return store.get(args2.id);
|
|
@@ -92738,6 +93234,74 @@ Your role is **ONLY** to:
|
|
|
92738
93234
|
|
|
92739
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.
|
|
92740
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
|
+
|
|
92741
93305
|
### Why This Matters
|
|
92742
93306
|
|
|
92743
93307
|
| Coordinator Work | Worker Work | Consequence of Mixing |
|
|
@@ -93822,15 +94386,15 @@ import {
|
|
|
93822
94386
|
createHiveAdapter as createHiveAdapter4,
|
|
93823
94387
|
resolvePartialId as resolvePartialId4,
|
|
93824
94388
|
createDurableStreamAdapter,
|
|
93825
|
-
createDurableStreamServer
|
|
94389
|
+
createDurableStreamServer,
|
|
94390
|
+
consolidateDatabases,
|
|
94391
|
+
getGlobalDbPath as getGlobalDbPath2
|
|
93826
94392
|
} from "swarm-mail";
|
|
93827
94393
|
import { execSync, spawn } from "child_process";
|
|
93828
94394
|
import { tmpdir as tmpdir3 } from "os";
|
|
93829
94395
|
|
|
93830
94396
|
// src/query-tools.ts
|
|
93831
|
-
import { createLibSQLAdapter as createLibSQLAdapter2 } from "swarm-mail";
|
|
93832
|
-
import { join as join7 } from "node:path";
|
|
93833
|
-
import { homedir as homedir3 } from "node:os";
|
|
94397
|
+
import { createLibSQLAdapter as createLibSQLAdapter2, getGlobalDbPath } from "swarm-mail";
|
|
93834
94398
|
var presetQueries = {
|
|
93835
94399
|
failed_decompositions: `
|
|
93836
94400
|
SELECT
|
|
@@ -93981,8 +94545,7 @@ var presetQueries = {
|
|
|
93981
94545
|
`
|
|
93982
94546
|
};
|
|
93983
94547
|
function getDbPath() {
|
|
93984
|
-
|
|
93985
|
-
return join7(home, ".swarm-tools", "swarm-mail.db");
|
|
94548
|
+
return getGlobalDbPath();
|
|
93986
94549
|
}
|
|
93987
94550
|
async function createDbAdapter() {
|
|
93988
94551
|
const dbPath = getDbPath();
|
|
@@ -95192,8 +95755,8 @@ function detectRegressions(projectPath, threshold = 0.1) {
|
|
|
95192
95755
|
}
|
|
95193
95756
|
|
|
95194
95757
|
// src/observability-health.ts
|
|
95195
|
-
import { homedir as
|
|
95196
|
-
import { join as
|
|
95758
|
+
import { homedir as homedir3 } from "node:os";
|
|
95759
|
+
import { join as join9 } from "node:path";
|
|
95197
95760
|
import { existsSync as existsSync8, readdirSync, readFileSync as readFileSync8, statSync } from "node:fs";
|
|
95198
95761
|
var EXPECTED_HOOKS = [
|
|
95199
95762
|
"tool.execute.after",
|
|
@@ -95290,16 +95853,16 @@ function calculateSessionQuality(input) {
|
|
|
95290
95853
|
};
|
|
95291
95854
|
}
|
|
95292
95855
|
function querySessionQuality(options2) {
|
|
95293
|
-
const sessionsPath =
|
|
95856
|
+
const sessionsPath = join9(homedir3(), ".config", "swarm-tools", "sessions");
|
|
95294
95857
|
if (!existsSync8(sessionsPath)) {
|
|
95295
95858
|
return { totalSessions: 0, qualitySessions: 0 };
|
|
95296
95859
|
}
|
|
95297
95860
|
const since = Date.now() - options2.days * 24 * 60 * 60 * 1000;
|
|
95298
|
-
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);
|
|
95299
95862
|
let qualityCount = 0;
|
|
95300
95863
|
for (const file4 of sessionFiles) {
|
|
95301
95864
|
try {
|
|
95302
|
-
const content = readFileSync8(
|
|
95865
|
+
const content = readFileSync8(join9(sessionsPath, file4), "utf-8");
|
|
95303
95866
|
const lines = content.trim().split(`
|
|
95304
95867
|
`);
|
|
95305
95868
|
let hasDecisions = false;
|
|
@@ -95409,6 +95972,90 @@ async function getObservabilityHealth(projectPath, options2 = {}) {
|
|
|
95409
95972
|
};
|
|
95410
95973
|
}
|
|
95411
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
|
+
|
|
95412
96059
|
// src/eval-history.ts
|
|
95413
96060
|
import * as fs5 from "node:fs";
|
|
95414
96061
|
import * as path6 from "node:path";
|
|
@@ -95806,7 +96453,7 @@ import {
|
|
|
95806
96453
|
findCellsByPartialId as findCellsByPartialId3
|
|
95807
96454
|
} from "swarm-mail";
|
|
95808
96455
|
import { existsSync as existsSync13, readFileSync as readFileSync13 } from "node:fs";
|
|
95809
|
-
import { join as
|
|
96456
|
+
import { join as join13 } from "node:path";
|
|
95810
96457
|
|
|
95811
96458
|
// src/schemas/cell.ts
|
|
95812
96459
|
init_zod3();
|
|
@@ -95884,7 +96531,8 @@ var CellTreeSchema3 = exports_external3.object({
|
|
|
95884
96531
|
title: exports_external3.string().min(1),
|
|
95885
96532
|
description: exports_external3.string().optional().default("")
|
|
95886
96533
|
}),
|
|
95887
|
-
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.")
|
|
95888
96536
|
});
|
|
95889
96537
|
var EpicCreateArgsSchema3 = exports_external3.object({
|
|
95890
96538
|
epic_title: exports_external3.string().min(1),
|
|
@@ -96404,7 +97052,7 @@ class HiveError3 extends Error {
|
|
|
96404
97052
|
}
|
|
96405
97053
|
}
|
|
96406
97054
|
function ensureHiveDirectory3(projectPath) {
|
|
96407
|
-
const hiveDir =
|
|
97055
|
+
const hiveDir = join13(projectPath, ".hive");
|
|
96408
97056
|
if (!existsSync13(hiveDir)) {
|
|
96409
97057
|
const { mkdirSync: mkdirSync7 } = __require("node:fs");
|
|
96410
97058
|
mkdirSync7(hiveDir, { recursive: true });
|
|
@@ -96461,7 +97109,7 @@ async function getHiveAdapter3(projectKey) {
|
|
|
96461
97109
|
return adapter;
|
|
96462
97110
|
}
|
|
96463
97111
|
async function autoMigrateFromJSONL3(adapter, projectKey) {
|
|
96464
|
-
const jsonlPath =
|
|
97112
|
+
const jsonlPath = join13(projectKey, ".hive", "issues.jsonl");
|
|
96465
97113
|
if (!existsSync13(jsonlPath)) {
|
|
96466
97114
|
return;
|
|
96467
97115
|
}
|
|
@@ -96475,13 +97123,13 @@ async function autoMigrateFromJSONL3(adapter, projectKey) {
|
|
|
96475
97123
|
skipExisting: true
|
|
96476
97124
|
});
|
|
96477
97125
|
if (result.created > 0 || result.updated > 0) {
|
|
96478
|
-
console.
|
|
97126
|
+
console.error(`[hive] Auto-migrated ${result.created} cells from ${jsonlPath} (${result.skipped} skipped, ${result.errors.length} errors)`);
|
|
96479
97127
|
}
|
|
96480
97128
|
if (result.errors.length > 0) {
|
|
96481
|
-
console.
|
|
97129
|
+
console.error(`[hive] Migration errors:`, result.errors.slice(0, 5).map((e) => `${e.cellId}: ${e.error}`));
|
|
96482
97130
|
}
|
|
96483
97131
|
} catch (error54) {
|
|
96484
|
-
console.
|
|
97132
|
+
console.error(`[hive] Failed to auto-migrate from ${jsonlPath}:`, error54 instanceof Error ? error54.message : String(error54));
|
|
96485
97133
|
}
|
|
96486
97134
|
}
|
|
96487
97135
|
function formatCellForOutput3(adapterCell) {
|
|
@@ -97082,7 +97730,7 @@ var hive_sync3 = tool3({
|
|
|
97082
97730
|
const flushResult = await withTimeout(flushManager.flush(), TIMEOUT_MS, "flush hive");
|
|
97083
97731
|
const swarmMail = await getSwarmMailLibSQL12(projectKey);
|
|
97084
97732
|
const db = await swarmMail.getDatabase();
|
|
97085
|
-
const hivePath =
|
|
97733
|
+
const hivePath = join13(projectKey, ".hive");
|
|
97086
97734
|
let memoriesSynced = 0;
|
|
97087
97735
|
try {
|
|
97088
97736
|
const memoryResult = await syncMemories3(db, hivePath);
|
|
@@ -97586,8 +98234,8 @@ function formatToolAvailability2(availability) {
|
|
|
97586
98234
|
// src/rate-limiter.ts
|
|
97587
98235
|
var import_ioredis = __toESM(require_built3(), 1);
|
|
97588
98236
|
import { mkdirSync as mkdirSync7, existsSync as existsSync14 } from "node:fs";
|
|
97589
|
-
import { dirname as dirname7, join as
|
|
97590
|
-
import { homedir as
|
|
98237
|
+
import { dirname as dirname7, join as join14 } from "node:path";
|
|
98238
|
+
import { homedir as homedir6 } from "node:os";
|
|
97591
98239
|
var sqliteAvailable = false;
|
|
97592
98240
|
var createDatabase = null;
|
|
97593
98241
|
try {
|
|
@@ -97847,7 +98495,7 @@ async function createRateLimiter(options2) {
|
|
|
97847
98495
|
const {
|
|
97848
98496
|
backend,
|
|
97849
98497
|
redisUrl = process.env.OPENCODE_RATE_LIMIT_REDIS_URL || "redis://localhost:6379",
|
|
97850
|
-
sqlitePath = process.env.OPENCODE_RATE_LIMIT_SQLITE_PATH ||
|
|
98498
|
+
sqlitePath = process.env.OPENCODE_RATE_LIMIT_SQLITE_PATH || join14(homedir6(), ".config", "opencode", "rate-limits.db")
|
|
97851
98499
|
} = options2 || {};
|
|
97852
98500
|
if (backend === "memory") {
|
|
97853
98501
|
return new InMemoryRateLimiter;
|
|
@@ -97913,7 +98561,7 @@ import {
|
|
|
97913
98561
|
writeFileSync as writeFileSync5,
|
|
97914
98562
|
unlinkSync
|
|
97915
98563
|
} from "fs";
|
|
97916
|
-
import { join as
|
|
98564
|
+
import { join as join15 } from "path";
|
|
97917
98565
|
import { tmpdir } from "os";
|
|
97918
98566
|
var AGENT_MAIL_URL = "http://127.0.0.1:8765";
|
|
97919
98567
|
var DEFAULT_TTL_SECONDS = 3600;
|
|
@@ -97934,10 +98582,10 @@ var RECOVERY_CONFIG = {
|
|
|
97934
98582
|
restartCooldownMs: 1e4,
|
|
97935
98583
|
enabled: process.env.OPENCODE_AGENT_MAIL_AUTO_RESTART !== "false"
|
|
97936
98584
|
};
|
|
97937
|
-
var SESSION_STATE_DIR = process.env.SWARM_STATE_DIR ||
|
|
98585
|
+
var SESSION_STATE_DIR = process.env.SWARM_STATE_DIR || join15(tmpdir(), "swarm-sessions");
|
|
97938
98586
|
function getSessionStatePath(sessionID) {
|
|
97939
98587
|
const safeID = sessionID.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
97940
|
-
return
|
|
98588
|
+
return join15(SESSION_STATE_DIR, `${safeID}.json`);
|
|
97941
98589
|
}
|
|
97942
98590
|
function loadSessionState(sessionID) {
|
|
97943
98591
|
const path4 = getSessionStatePath(sessionID);
|
|
@@ -98647,17 +99295,17 @@ import {
|
|
|
98647
99295
|
writeFileSync as writeFileSync6,
|
|
98648
99296
|
unlinkSync as unlinkSync2
|
|
98649
99297
|
} from "node:fs";
|
|
98650
|
-
import { join as
|
|
99298
|
+
import { join as join16 } from "node:path";
|
|
98651
99299
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
98652
99300
|
var MAX_INBOX_LIMIT2 = 5;
|
|
98653
99301
|
var swarmMailProjectDirectory = null;
|
|
98654
99302
|
function getSwarmMailProjectDirectory() {
|
|
98655
99303
|
return swarmMailProjectDirectory ?? undefined;
|
|
98656
99304
|
}
|
|
98657
|
-
var SESSION_STATE_DIR2 = process.env.SWARM_STATE_DIR ||
|
|
99305
|
+
var SESSION_STATE_DIR2 = process.env.SWARM_STATE_DIR || join16(tmpdir2(), "swarm-sessions");
|
|
98658
99306
|
function getSessionStatePath2(sessionID) {
|
|
98659
99307
|
const safeID = sessionID.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
98660
|
-
return
|
|
99308
|
+
return join16(SESSION_STATE_DIR2, `${safeID}.json`);
|
|
98661
99309
|
}
|
|
98662
99310
|
function loadSessionState2(sessionID) {
|
|
98663
99311
|
const path4 = getSessionStatePath2(sessionID);
|
|
@@ -101804,12 +102452,12 @@ init_skills2();
|
|
|
101804
102452
|
// src/swarm-worktree.ts
|
|
101805
102453
|
init_dist2();
|
|
101806
102454
|
init_zod3();
|
|
101807
|
-
import { join as
|
|
102455
|
+
import { join as join18 } from "node:path";
|
|
101808
102456
|
import { existsSync as existsSync17 } from "node:fs";
|
|
101809
102457
|
var WORKTREE_DIR2 = ".swarm/worktrees";
|
|
101810
102458
|
function getWorktreePath2(projectPath, taskId) {
|
|
101811
102459
|
const safeTaskId = taskId.replace(/[^a-zA-Z0-9.-]/g, "_");
|
|
101812
|
-
return
|
|
102460
|
+
return join18(projectPath, WORKTREE_DIR2, safeTaskId);
|
|
101813
102461
|
}
|
|
101814
102462
|
function parseTaskIdFromPath2(worktreePath) {
|
|
101815
102463
|
const parts2 = worktreePath.split("/");
|
|
@@ -101843,7 +102491,7 @@ async function getWorktreeCommits2(worktreePath, startCommit) {
|
|
|
101843
102491
|
`).filter((c) => c.length > 0);
|
|
101844
102492
|
}
|
|
101845
102493
|
async function ensureWorktreeDir2(projectPath) {
|
|
101846
|
-
const worktreeDir =
|
|
102494
|
+
const worktreeDir = join18(projectPath, WORKTREE_DIR2);
|
|
101847
102495
|
await Bun.$`mkdir -p ${worktreeDir}`.quiet().nothrow();
|
|
101848
102496
|
}
|
|
101849
102497
|
var swarm_worktree_create2 = tool3({
|
|
@@ -101980,7 +102628,7 @@ var swarm_worktree_cleanup2 = tool3({
|
|
|
101980
102628
|
return JSON.stringify(result3, null, 2);
|
|
101981
102629
|
}
|
|
101982
102630
|
const output = listResult.stdout.toString();
|
|
101983
|
-
const worktreeDir =
|
|
102631
|
+
const worktreeDir = join18(args2.project_path, WORKTREE_DIR2);
|
|
101984
102632
|
const worktrees = output.split(`
|
|
101985
102633
|
|
|
101986
102634
|
`).filter((block) => block.includes(worktreeDir)).map((block) => {
|
|
@@ -102045,7 +102693,7 @@ var swarm_worktree_list2 = tool3({
|
|
|
102045
102693
|
}, null, 2);
|
|
102046
102694
|
}
|
|
102047
102695
|
const output = listResult.stdout.toString();
|
|
102048
|
-
const worktreeDir =
|
|
102696
|
+
const worktreeDir = join18(args2.project_path, WORKTREE_DIR2);
|
|
102049
102697
|
const worktrees = [];
|
|
102050
102698
|
const blocks = output.split(`
|
|
102051
102699
|
|
|
@@ -103106,7 +103754,7 @@ var swarm_complete2 = tool3({
|
|
|
103106
103754
|
files_touched: tool3.schema.array(tool3.schema.string()).optional().describe("Files modified - will be verified (typecheck, tests)"),
|
|
103107
103755
|
skip_verification: tool3.schema.boolean().optional().describe("Skip ALL verification (typecheck, tests). Use sparingly! (default: false)"),
|
|
103108
103756
|
planned_files: tool3.schema.array(tool3.schema.string()).optional().describe("Files that were originally planned to be modified"),
|
|
103109
|
-
start_time: tool3.schema.number().
|
|
103757
|
+
start_time: tool3.schema.number().describe("Task start timestamp (Unix ms) for duration calculation - REQUIRED for accurate analytics"),
|
|
103110
103758
|
error_count: tool3.schema.number().optional().describe("Number of errors encountered during task"),
|
|
103111
103759
|
retry_count: tool3.schema.number().optional().describe("Number of retry attempts during task"),
|
|
103112
103760
|
skip_review: tool3.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review.")
|
|
@@ -103310,7 +103958,7 @@ This will be recorded as a negative learning signal.`;
|
|
|
103310
103958
|
syncError = error54 instanceof Error ? error54.message : String(error54);
|
|
103311
103959
|
console.warn(`[swarm_complete] Auto-sync failed (non-fatal): ${syncError}`);
|
|
103312
103960
|
}
|
|
103313
|
-
const completionDurationMs =
|
|
103961
|
+
const completionDurationMs = Date.now() - args2.start_time;
|
|
103314
103962
|
const eventEpicId = cell.parent_id || (args2.bead_id.includes(".") ? args2.bead_id.split(".")[0] : args2.bead_id);
|
|
103315
103963
|
try {
|
|
103316
103964
|
const event = createEvent8("subtask_outcome", {
|
|
@@ -103366,12 +104014,18 @@ This will be recorded as a negative learning signal.`;
|
|
|
103366
104014
|
memoryError = `Failed to store memory: ${error54 instanceof Error ? error54.message : String(error54)}`;
|
|
103367
104015
|
console.warn(`[swarm_complete] ${memoryError}`);
|
|
103368
104016
|
}
|
|
104017
|
+
let reservationsReleased = false;
|
|
104018
|
+
let reservationsReleasedCount = 0;
|
|
104019
|
+
let reservationsReleaseError;
|
|
103369
104020
|
try {
|
|
103370
|
-
await releaseSwarmFiles3({
|
|
104021
|
+
const releaseResult = await releaseSwarmFiles3({
|
|
103371
104022
|
projectPath: args2.project_key,
|
|
103372
104023
|
agentName: args2.agent_name
|
|
103373
104024
|
});
|
|
104025
|
+
reservationsReleased = true;
|
|
104026
|
+
reservationsReleasedCount = releaseResult.released;
|
|
103374
104027
|
} catch (error54) {
|
|
104028
|
+
reservationsReleaseError = error54 instanceof Error ? error54.message : String(error54);
|
|
103375
104029
|
console.warn(`[swarm] Failed to release file reservations for ${args2.agent_name}:`, error54);
|
|
103376
104030
|
}
|
|
103377
104031
|
const epicId2 = args2.bead_id.includes(".") ? args2.bead_id.split(".")[0] : args2.bead_id;
|
|
@@ -103407,7 +104061,9 @@ This will be recorded as a negative learning signal.`;
|
|
|
103407
104061
|
success: true,
|
|
103408
104062
|
bead_id: args2.bead_id,
|
|
103409
104063
|
closed: true,
|
|
103410
|
-
reservations_released:
|
|
104064
|
+
reservations_released: reservationsReleased,
|
|
104065
|
+
reservations_released_count: reservationsReleasedCount,
|
|
104066
|
+
reservations_release_error: reservationsReleaseError,
|
|
103411
104067
|
synced: syncSuccess,
|
|
103412
104068
|
sync_error: syncError,
|
|
103413
104069
|
message_sent: messageSent,
|
|
@@ -105238,7 +105894,7 @@ var dedupeWith2 = /* @__PURE__ */ dual2(2, (self, isEquivalent) => {
|
|
|
105238
105894
|
return [];
|
|
105239
105895
|
});
|
|
105240
105896
|
var dedupe2 = (self) => dedupeWith2(self, equivalence2());
|
|
105241
|
-
var
|
|
105897
|
+
var join19 = /* @__PURE__ */ dual2(2, (self, sep4) => fromIterable8(self).join(sep4));
|
|
105242
105898
|
|
|
105243
105899
|
// ../../node_modules/.bun/effect@3.19.12/node_modules/effect/dist/esm/Number.js
|
|
105244
105900
|
var Order3 = number10;
|
|
@@ -109789,7 +110445,7 @@ var InvalidData2 = (path4, message, options2 = {
|
|
|
109789
110445
|
Object.defineProperty(error54, "toString", {
|
|
109790
110446
|
enumerable: false,
|
|
109791
110447
|
value() {
|
|
109792
|
-
const path10 = pipe4(this.path,
|
|
110448
|
+
const path10 = pipe4(this.path, join19(options2.pathDelim));
|
|
109793
110449
|
return `(Invalid data at ${path10}: "${this.message}")`;
|
|
109794
110450
|
}
|
|
109795
110451
|
});
|
|
@@ -109805,7 +110461,7 @@ var MissingData2 = (path4, message, options2 = {
|
|
|
109805
110461
|
Object.defineProperty(error54, "toString", {
|
|
109806
110462
|
enumerable: false,
|
|
109807
110463
|
value() {
|
|
109808
|
-
const path10 = pipe4(this.path,
|
|
110464
|
+
const path10 = pipe4(this.path, join19(options2.pathDelim));
|
|
109809
110465
|
return `(Missing data at ${path10}: "${this.message}")`;
|
|
109810
110466
|
}
|
|
109811
110467
|
});
|
|
@@ -109822,7 +110478,7 @@ var SourceUnavailable2 = (path4, message, cause3, options2 = {
|
|
|
109822
110478
|
Object.defineProperty(error54, "toString", {
|
|
109823
110479
|
enumerable: false,
|
|
109824
110480
|
value() {
|
|
109825
|
-
const path10 = pipe4(this.path,
|
|
110481
|
+
const path10 = pipe4(this.path, join19(options2.pathDelim));
|
|
109826
110482
|
return `(Source unavailable at ${path10}: "${this.message}")`;
|
|
109827
110483
|
}
|
|
109828
110484
|
});
|
|
@@ -109838,7 +110494,7 @@ var Unsupported2 = (path4, message, options2 = {
|
|
|
109838
110494
|
Object.defineProperty(error54, "toString", {
|
|
109839
110495
|
enumerable: false,
|
|
109840
110496
|
value() {
|
|
109841
|
-
const path10 = pipe4(this.path,
|
|
110497
|
+
const path10 = pipe4(this.path, join19(options2.pathDelim));
|
|
109842
110498
|
return `(Unsupported operation at ${path10}: "${this.message}")`;
|
|
109843
110499
|
}
|
|
109844
110500
|
});
|
|
@@ -109958,7 +110614,7 @@ var fromEnv2 = (options2) => {
|
|
|
109958
110614
|
pathDelim: "_",
|
|
109959
110615
|
seqDelim: ","
|
|
109960
110616
|
}, options2);
|
|
109961
|
-
const makePathString = (path4) => pipe4(path4,
|
|
110617
|
+
const makePathString = (path4) => pipe4(path4, join19(pathDelim));
|
|
109962
110618
|
const unmakePathString = (pathString) => pathString.split(pathDelim);
|
|
109963
110619
|
const getEnv = () => typeof process !== "undefined" && ("env" in process) && typeof process.env === "object" ? process.env : {};
|
|
109964
110620
|
const load = (path4, primitive, split = true) => {
|
|
@@ -110082,7 +110738,7 @@ var fromFlatLoop2 = (flat, prefix, config4, split) => {
|
|
|
110082
110738
|
return fail5(right4.left);
|
|
110083
110739
|
}
|
|
110084
110740
|
if (isRight5(left4) && isRight5(right4)) {
|
|
110085
|
-
const path4 = pipe4(prefix,
|
|
110741
|
+
const path4 = pipe4(prefix, join19("."));
|
|
110086
110742
|
const fail6 = fromFlatLoopFail2(prefix, path4);
|
|
110087
110743
|
const [lefts, rights] = extend4(fail6, fail6, pipe4(left4.right, map8(right5)), pipe4(right4.right, map8(right5)));
|
|
110088
110744
|
return pipe4(lefts, zip3(rights), forEachSequential2(([left6, right6]) => pipe4(zip5(left6, right6), map18(([left7, right7]) => op.zip(left7, right7)))));
|
|
@@ -112256,11 +112912,11 @@ var interruptAllAs2 = /* @__PURE__ */ dual2(2, /* @__PURE__ */ fnUntraced3(funct
|
|
|
112256
112912
|
}
|
|
112257
112913
|
}));
|
|
112258
112914
|
var interruptAsFork2 = /* @__PURE__ */ dual2(2, (self, fiberId4) => self.interruptAsFork(fiberId4));
|
|
112259
|
-
var
|
|
112915
|
+
var join20 = (self) => zipLeft3(flatten11(self.await), self.inheritAll);
|
|
112260
112916
|
var _never4 = {
|
|
112261
112917
|
...CommitPrototype3,
|
|
112262
112918
|
commit() {
|
|
112263
|
-
return
|
|
112919
|
+
return join20(this);
|
|
112264
112920
|
},
|
|
112265
112921
|
...fiberProto2,
|
|
112266
112922
|
id: () => none14,
|
|
@@ -113507,7 +114163,7 @@ class FiberRuntime2 extends Class4 {
|
|
|
113507
114163
|
this.refreshRefCache();
|
|
113508
114164
|
}
|
|
113509
114165
|
commit() {
|
|
113510
|
-
return
|
|
114166
|
+
return join20(this);
|
|
113511
114167
|
}
|
|
113512
114168
|
id() {
|
|
113513
114169
|
return this._fiberId;
|
|
@@ -114522,7 +115178,7 @@ var forEachConcurrentDiscard2 = (self, f, batching, processAll, n) => uninterrup
|
|
|
114522
115178
|
next();
|
|
114523
115179
|
}
|
|
114524
115180
|
}));
|
|
114525
|
-
return asVoid4(onExit4(flatten11(restore(
|
|
115181
|
+
return asVoid4(onExit4(flatten11(restore(join20(processingFiber))), exitMatch2({
|
|
114526
115182
|
onFailure: (cause4) => {
|
|
114527
115183
|
onInterruptSignal();
|
|
114528
115184
|
const target2 = residual.length + 1;
|
|
@@ -114844,7 +115500,7 @@ var fiberAll2 = (fibers) => {
|
|
|
114844
115500
|
const _fiberAll = {
|
|
114845
115501
|
...CommitPrototype5,
|
|
114846
115502
|
commit() {
|
|
114847
|
-
return
|
|
115503
|
+
return join20(this);
|
|
114848
115504
|
},
|
|
114849
115505
|
[FiberTypeId2]: fiberVariance5,
|
|
114850
115506
|
id: () => fromIterable8(fibers).reduce((id, fiber) => combine12(id, fiber.id()), none14),
|
|
@@ -114897,14 +115553,14 @@ var raceWith3 = /* @__PURE__ */ dual2(3, (self, other, options2) => raceFibersWi
|
|
|
114897
115553
|
}
|
|
114898
115554
|
})
|
|
114899
115555
|
}));
|
|
114900
|
-
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)))))));
|
|
114901
115557
|
var race3 = /* @__PURE__ */ dual2(2, (self, that) => fiberIdWith3((parentFiberId) => raceWith3(self, that, {
|
|
114902
115558
|
onSelfDone: (exit4, right4) => exitMatchEffect2(exit4, {
|
|
114903
|
-
onFailure: (cause4) => pipe4(
|
|
115559
|
+
onFailure: (cause4) => pipe4(join20(right4), mapErrorCause3((cause22) => parallel4(cause4, cause22))),
|
|
114904
115560
|
onSuccess: (value) => pipe4(right4, interruptAsFiber2(parentFiberId), as3(value))
|
|
114905
115561
|
}),
|
|
114906
115562
|
onOtherDone: (exit4, left4) => exitMatchEffect2(exit4, {
|
|
114907
|
-
onFailure: (cause4) => pipe4(
|
|
115563
|
+
onFailure: (cause4) => pipe4(join20(left4), mapErrorCause3((cause22) => parallel4(cause22, cause4))),
|
|
114908
115564
|
onSuccess: (value) => pipe4(left4, interruptAsFiber2(parentFiberId), as3(value))
|
|
114909
115565
|
})
|
|
114910
115566
|
})));
|
|
@@ -116058,8 +116714,8 @@ var forkIn3 = /* @__PURE__ */ dual2(2, (self, scope4) => withFiberRuntime3((pare
|
|
|
116058
116714
|
return succeed5(fiber);
|
|
116059
116715
|
}));
|
|
116060
116716
|
var forkScoped3 = (self) => scopeWith3((scope4) => forkIn3(self, scope4));
|
|
116061
|
-
var fromFiber3 = (fiber) =>
|
|
116062
|
-
var fromFiberEffect3 = (fiber) => suspend4(() => flatMap15(fiber,
|
|
116717
|
+
var fromFiber3 = (fiber) => join20(fiber);
|
|
116718
|
+
var fromFiberEffect3 = (fiber) => suspend4(() => flatMap15(fiber, join20));
|
|
116063
116719
|
var memoKeySymbol2 = /* @__PURE__ */ Symbol.for("effect/Effect/memoizeFunction.key");
|
|
116064
116720
|
|
|
116065
116721
|
class Key2 {
|
|
@@ -117643,14 +118299,14 @@ async function maybeAutoMigrate2(db) {
|
|
|
117643
118299
|
if (memoryCount > 0) {
|
|
117644
118300
|
return;
|
|
117645
118301
|
}
|
|
117646
|
-
console.
|
|
118302
|
+
console.error("[memory] Legacy database detected, starting auto-migration...");
|
|
117647
118303
|
const result = await migrateLegacyMemories2({
|
|
117648
118304
|
targetDb: db,
|
|
117649
118305
|
dryRun: false,
|
|
117650
|
-
onProgress: console.
|
|
118306
|
+
onProgress: (msg) => console.error(msg)
|
|
117651
118307
|
});
|
|
117652
118308
|
if (result.migrated > 0) {
|
|
117653
|
-
console.
|
|
118309
|
+
console.error(`[memory] Auto-migrated ${result.migrated} memories from legacy database`);
|
|
117654
118310
|
}
|
|
117655
118311
|
if (result.failed > 0) {
|
|
117656
118312
|
console.warn(`[memory] ${result.failed} memories failed to migrate. See errors above.`);
|
|
@@ -117719,6 +118375,7 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
117719
118375
|
async find(args3) {
|
|
117720
118376
|
const limit = args3.limit ?? 10;
|
|
117721
118377
|
let results;
|
|
118378
|
+
let usedFallback = false;
|
|
117722
118379
|
if (args3.fts) {
|
|
117723
118380
|
results = await store.ftsSearch(args3.query, {
|
|
117724
118381
|
limit,
|
|
@@ -117729,14 +118386,23 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
117729
118386
|
const ollama = yield* Ollama2;
|
|
117730
118387
|
return yield* ollama.embed(args3.query);
|
|
117731
118388
|
});
|
|
117732
|
-
|
|
117733
|
-
|
|
117734
|
-
|
|
117735
|
-
|
|
117736
|
-
|
|
117737
|
-
|
|
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
|
+
}
|
|
117738
118404
|
}
|
|
117739
|
-
|
|
118405
|
+
const response = {
|
|
117740
118406
|
results: results.map((r) => ({
|
|
117741
118407
|
id: r.memory.id,
|
|
117742
118408
|
content: args3.expand ? r.memory.content : truncateContent(r.memory.content),
|
|
@@ -117747,6 +118413,10 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
|
|
|
117747
118413
|
})),
|
|
117748
118414
|
count: results.length
|
|
117749
118415
|
};
|
|
118416
|
+
if (usedFallback) {
|
|
118417
|
+
response.fallback_used = true;
|
|
118418
|
+
}
|
|
118419
|
+
return response;
|
|
117750
118420
|
},
|
|
117751
118421
|
async get(args3) {
|
|
117752
118422
|
return store.get(args3.id);
|
|
@@ -119285,7 +119955,7 @@ var promptTools2 = {
|
|
|
119285
119955
|
init_dist2();
|
|
119286
119956
|
import { existsSync as existsSync18 } from "node:fs";
|
|
119287
119957
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
119288
|
-
import { join as
|
|
119958
|
+
import { join as join21 } from "node:path";
|
|
119289
119959
|
|
|
119290
119960
|
// ../../node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/index.js
|
|
119291
119961
|
var composer = require_composer();
|
|
@@ -119463,20 +120133,20 @@ async function parsePackageJson(packageJsonPath, packages) {
|
|
|
119463
120133
|
}
|
|
119464
120134
|
}
|
|
119465
120135
|
async function getInstalledVersions(projectPath, packages, checkUpgrades = false) {
|
|
119466
|
-
const npmLock =
|
|
120136
|
+
const npmLock = join21(projectPath, "package-lock.json");
|
|
119467
120137
|
let versions2 = [];
|
|
119468
120138
|
if (existsSync18(npmLock)) {
|
|
119469
120139
|
versions2 = await parseNpmLockfile(npmLock, packages);
|
|
119470
120140
|
} else {
|
|
119471
|
-
const pnpmLock =
|
|
120141
|
+
const pnpmLock = join21(projectPath, "pnpm-lock.yaml");
|
|
119472
120142
|
if (existsSync18(pnpmLock)) {
|
|
119473
120143
|
versions2 = await parsePnpmLockfile(pnpmLock, packages);
|
|
119474
120144
|
} else {
|
|
119475
|
-
const yarnLock =
|
|
120145
|
+
const yarnLock = join21(projectPath, "yarn.lock");
|
|
119476
120146
|
if (existsSync18(yarnLock)) {
|
|
119477
120147
|
versions2 = await parseYarnLockfile(yarnLock, packages);
|
|
119478
120148
|
} else {
|
|
119479
|
-
const packageJson =
|
|
120149
|
+
const packageJson = join21(projectPath, "package.json");
|
|
119480
120150
|
if (existsSync18(packageJson)) {
|
|
119481
120151
|
versions2 = await parsePackageJson(packageJson, packages);
|
|
119482
120152
|
}
|
|
@@ -120628,7 +121298,7 @@ import {
|
|
|
120628
121298
|
} from "swarm-mail";
|
|
120629
121299
|
import * as os5 from "node:os";
|
|
120630
121300
|
import * as path10 from "node:path";
|
|
120631
|
-
import { join as
|
|
121301
|
+
import { join as join25 } from "node:path";
|
|
120632
121302
|
var cachedAdapter3 = null;
|
|
120633
121303
|
var cachedIndexer = null;
|
|
120634
121304
|
var cachedProjectPath3 = null;
|
|
@@ -120835,7 +121505,7 @@ var hivemind_sync = tool3({
|
|
|
120835
121505
|
const projectPath = cachedProjectPath3 || process.cwd();
|
|
120836
121506
|
const swarmMail = await getSwarmMailLibSQL16(projectPath);
|
|
120837
121507
|
const dbAdapter = await swarmMail.getDatabase();
|
|
120838
|
-
const hiveDir =
|
|
121508
|
+
const hiveDir = join25(projectPath, ".hive");
|
|
120839
121509
|
const result = await syncMemories4(dbAdapter, hiveDir);
|
|
120840
121510
|
await emitEvent("memories_synced", {
|
|
120841
121511
|
imported: result.imported.created,
|
|
@@ -121370,9 +122040,9 @@ import { checkSwarmHealth as checkSwarmHealth4 } from "swarm-mail";
|
|
|
121370
122040
|
// src/logger.ts
|
|
121371
122041
|
var import_pino = __toESM(require_pino(), 1);
|
|
121372
122042
|
import { mkdirSync as mkdirSync10, existsSync as existsSync19 } from "node:fs";
|
|
121373
|
-
import { join as
|
|
121374
|
-
import { homedir as
|
|
121375
|
-
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");
|
|
121376
122046
|
function ensureLogDir(logDir) {
|
|
121377
122047
|
if (!existsSync19(logDir)) {
|
|
121378
122048
|
mkdirSync10(logDir, { recursive: true });
|
|
@@ -121391,7 +122061,7 @@ function getLogger(logDir = DEFAULT_LOG_DIR) {
|
|
|
121391
122061
|
let logger;
|
|
121392
122062
|
if (process.env.SWARM_LOG_FILE === "1") {
|
|
121393
122063
|
ensureLogDir(logDir);
|
|
121394
|
-
const logPath =
|
|
122064
|
+
const logPath = join26(logDir, "swarm.log");
|
|
121395
122065
|
logger = import_pino.default(baseConfig, import_pino.default.destination({ dest: logPath, sync: false }));
|
|
121396
122066
|
} else {
|
|
121397
122067
|
logger = import_pino.default(baseConfig);
|
|
@@ -121795,7 +122465,7 @@ var allTools = {
|
|
|
121795
122465
|
|
|
121796
122466
|
// bin/swarm.ts
|
|
121797
122467
|
var __dirname2 = dirname9(fileURLToPath3(import.meta.url));
|
|
121798
|
-
var pkgPath =
|
|
122468
|
+
var pkgPath = existsSync20(join28(__dirname2, "..", "package.json")) ? join28(__dirname2, "..", "package.json") : join28(__dirname2, "..", "..", "package.json");
|
|
121799
122469
|
var pkg = JSON.parse(readFileSync16(pkgPath, "utf-8"));
|
|
121800
122470
|
var VERSION = pkg.version;
|
|
121801
122471
|
var BEE = `
|
|
@@ -122134,8 +122804,8 @@ function copyDirRecursiveSync(srcDir, destDir) {
|
|
|
122134
122804
|
mkdirSync11(destDir, { recursive: true });
|
|
122135
122805
|
const entries2 = readdirSync2(srcDir, { withFileTypes: true });
|
|
122136
122806
|
for (const entry of entries2) {
|
|
122137
|
-
const srcPath =
|
|
122138
|
-
const destPath =
|
|
122807
|
+
const srcPath = join28(srcDir, entry.name);
|
|
122808
|
+
const destPath = join28(destDir, entry.name);
|
|
122139
122809
|
if (entry.isDirectory()) {
|
|
122140
122810
|
copyDirRecursiveSync(srcPath, destPath);
|
|
122141
122811
|
continue;
|
|
@@ -122149,7 +122819,7 @@ function copyDirRecursiveSync(srcDir, destDir) {
|
|
|
122149
122819
|
}
|
|
122150
122820
|
}
|
|
122151
122821
|
function writeBundledSkillMarker(skillDir, info) {
|
|
122152
|
-
const markerPath =
|
|
122822
|
+
const markerPath = join28(skillDir, BUNDLED_SKILL_MARKER_FILENAME);
|
|
122153
122823
|
writeFileSync7(markerPath, JSON.stringify({
|
|
122154
122824
|
managed_by: "opencode-swarm-plugin",
|
|
122155
122825
|
version: info.version,
|
|
@@ -122166,9 +122836,9 @@ function syncBundledSkillsToGlobal({
|
|
|
122166
122836
|
const updated = [];
|
|
122167
122837
|
const skipped = [];
|
|
122168
122838
|
for (const name of bundledSkills) {
|
|
122169
|
-
const srcSkillDir =
|
|
122170
|
-
const destSkillDir =
|
|
122171
|
-
const markerPath =
|
|
122839
|
+
const srcSkillDir = join28(bundledSkillsPath, name);
|
|
122840
|
+
const destSkillDir = join28(globalSkillsPath, name);
|
|
122841
|
+
const markerPath = join28(destSkillDir, BUNDLED_SKILL_MARKER_FILENAME);
|
|
122172
122842
|
if (!existsSync20(destSkillDir)) {
|
|
122173
122843
|
copyDirRecursiveSync(srcSkillDir, destSkillDir);
|
|
122174
122844
|
writeBundledSkillMarker(destSkillDir, { version: version4 });
|
|
@@ -122197,7 +122867,7 @@ function backupFileWithTimestamp(filePath) {
|
|
|
122197
122867
|
const dir = dirname9(filePath);
|
|
122198
122868
|
const base = basename3(filePath);
|
|
122199
122869
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "").replace(/Z$/, "Z");
|
|
122200
|
-
const backupPath =
|
|
122870
|
+
const backupPath = join28(dir, `${base}.swarm-backup-${timestamp}`);
|
|
122201
122871
|
copyFileSync(filePath, backupPath);
|
|
122202
122872
|
return backupPath;
|
|
122203
122873
|
} catch {
|
|
@@ -122584,7 +123254,7 @@ function updateAgentsMdFile({
|
|
|
122584
123254
|
return { changed: true, backupPath, changes };
|
|
122585
123255
|
}
|
|
122586
123256
|
function getPluginWrapper() {
|
|
122587
|
-
const templatePath =
|
|
123257
|
+
const templatePath = join28(__dirname2, "..", "examples", "plugin-wrapper-template.ts");
|
|
122588
123258
|
try {
|
|
122589
123259
|
return readFileSync16(templatePath, "utf-8");
|
|
122590
123260
|
} catch (error54) {
|
|
@@ -123019,9 +123689,9 @@ async function doctor(debug = false) {
|
|
|
123019
123689
|
const requiredMissing = required4.filter((r) => !r.available);
|
|
123020
123690
|
const optionalMissing = optional4.filter((r) => !r.available);
|
|
123021
123691
|
p.log.step("Skills:");
|
|
123022
|
-
const configDir =
|
|
123023
|
-
const globalSkillsPath =
|
|
123024
|
-
const bundledSkillsPath =
|
|
123692
|
+
const configDir = join28(homedir10(), ".config", "opencode");
|
|
123693
|
+
const globalSkillsPath = join28(configDir, "skills");
|
|
123694
|
+
const bundledSkillsPath = join28(__dirname2, "..", "global-skills");
|
|
123025
123695
|
if (existsSync20(globalSkillsPath)) {
|
|
123026
123696
|
try {
|
|
123027
123697
|
const { readdirSync: readdirSync3 } = __require("fs");
|
|
@@ -123095,9 +123765,9 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123095
123765
|
p.log.success(`Bun v${bunCheck.version} detected`);
|
|
123096
123766
|
const cwd = process.cwd();
|
|
123097
123767
|
const tempDirName = getLibSQLProjectTempDirName(cwd);
|
|
123098
|
-
const tempDir =
|
|
123099
|
-
const pglitePath =
|
|
123100
|
-
const libsqlPath =
|
|
123768
|
+
const tempDir = join28(tmpdir3(), tempDirName);
|
|
123769
|
+
const pglitePath = join28(tempDir, "streams");
|
|
123770
|
+
const libsqlPath = join28(tempDir, "streams.db");
|
|
123101
123771
|
if (pgliteExists(pglitePath)) {
|
|
123102
123772
|
const migrateSpinner = p.spinner();
|
|
123103
123773
|
migrateSpinner.start("Migrating...");
|
|
@@ -123124,19 +123794,19 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123124
123794
|
}
|
|
123125
123795
|
let isReinstall = false;
|
|
123126
123796
|
p.log.step("Checking existing configuration...");
|
|
123127
|
-
const configDir =
|
|
123128
|
-
const pluginDir =
|
|
123129
|
-
const commandDir =
|
|
123130
|
-
const agentDir =
|
|
123131
|
-
const pluginPath =
|
|
123132
|
-
const commandPath =
|
|
123133
|
-
const plannerAgentPath =
|
|
123134
|
-
const workerAgentPath =
|
|
123135
|
-
const researcherAgentPath =
|
|
123136
|
-
const swarmAgentDir =
|
|
123137
|
-
const legacyPlannerPath =
|
|
123138
|
-
const legacyWorkerPath =
|
|
123139
|
-
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");
|
|
123140
123810
|
const existingFiles = [
|
|
123141
123811
|
pluginPath,
|
|
123142
123812
|
commandPath,
|
|
@@ -123370,7 +124040,7 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123370
124040
|
p.log.message(dim(" No legacy .beads directory found"));
|
|
123371
124041
|
}
|
|
123372
124042
|
p.log.step("Checking for legacy MCP servers...");
|
|
123373
|
-
const opencodeConfigPath =
|
|
124043
|
+
const opencodeConfigPath = join28(configDir, "config.json");
|
|
123374
124044
|
if (existsSync20(opencodeConfigPath)) {
|
|
123375
124045
|
try {
|
|
123376
124046
|
const opencodeConfig = JSON.parse(readFileSync16(opencodeConfigPath, "utf-8"));
|
|
@@ -123402,6 +124072,66 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123402
124072
|
} else {
|
|
123403
124073
|
p.log.message(dim(" No OpenCode config found (skipping MCP check)"));
|
|
123404
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
|
+
}
|
|
123405
124135
|
const DEFAULT_COORDINATOR = "anthropic/claude-opus-4-5";
|
|
123406
124136
|
const DEFAULT_WORKER = "anthropic/claude-sonnet-4-5";
|
|
123407
124137
|
const DEFAULT_LITE = "anthropic/claude-haiku-4-5";
|
|
@@ -123549,8 +124279,8 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123549
124279
|
p.log.message(dim(` Lite: ${liteModel}`));
|
|
123550
124280
|
p.log.step("Setting up OpenCode integration...");
|
|
123551
124281
|
const stats = { created: 0, updated: 0, unchanged: 0 };
|
|
123552
|
-
const legacySkillsDir =
|
|
123553
|
-
const skillsDir =
|
|
124282
|
+
const legacySkillsDir = join28(configDir, "skills");
|
|
124283
|
+
const skillsDir = join28(configDir, "skill");
|
|
123554
124284
|
if (existsSync20(legacySkillsDir) && !existsSync20(skillsDir)) {
|
|
123555
124285
|
p.log.step("Migrating skills directory...");
|
|
123556
124286
|
try {
|
|
@@ -123584,7 +124314,7 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123584
124314
|
} catch {}
|
|
123585
124315
|
}
|
|
123586
124316
|
p.log.message(dim(` Skills directory: ${skillsDir}`));
|
|
123587
|
-
const bundledSkillsPath =
|
|
124317
|
+
const bundledSkillsPath = join28(__dirname2, "..", "global-skills");
|
|
123588
124318
|
const bundledSkills = listDirectoryNames(bundledSkillsPath);
|
|
123589
124319
|
if (existsSync20(bundledSkillsPath)) {
|
|
123590
124320
|
if (bundledSkills.length > 0) {
|
|
@@ -123593,7 +124323,7 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123593
124323
|
}
|
|
123594
124324
|
if (bundledSkills.length > 0) {
|
|
123595
124325
|
const globalSkills = listDirectoryNames(skillsDir);
|
|
123596
|
-
const managedBundled = globalSkills.filter((name) => existsSync20(
|
|
124326
|
+
const managedBundled = globalSkills.filter((name) => existsSync20(join28(skillsDir, name, BUNDLED_SKILL_MARKER_FILENAME)));
|
|
123597
124327
|
const missingBundled = bundledSkills.filter((name) => !globalSkills.includes(name));
|
|
123598
124328
|
if (missingBundled.length > 0 || managedBundled.length > 0) {
|
|
123599
124329
|
{
|
|
@@ -123623,7 +124353,7 @@ async function setup(forceReinstall = false, nonInteractive = false) {
|
|
|
123623
124353
|
}
|
|
123624
124354
|
}
|
|
123625
124355
|
}
|
|
123626
|
-
const agentsPath =
|
|
124356
|
+
const agentsPath = join28(configDir, "AGENTS.md");
|
|
123627
124357
|
if (existsSync20(agentsPath)) {
|
|
123628
124358
|
{
|
|
123629
124359
|
const s2 = p.spinner();
|
|
@@ -123790,14 +124520,14 @@ async function version4() {
|
|
|
123790
124520
|
showUpdateNotification(updateInfo3);
|
|
123791
124521
|
}
|
|
123792
124522
|
function config4() {
|
|
123793
|
-
const configDir =
|
|
123794
|
-
const pluginPath =
|
|
123795
|
-
const commandPath =
|
|
123796
|
-
const agentDir =
|
|
123797
|
-
const plannerAgentPath =
|
|
123798
|
-
const workerAgentPath =
|
|
123799
|
-
const researcherAgentPath =
|
|
123800
|
-
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");
|
|
123801
124531
|
console.log(yellow(BANNER));
|
|
123802
124532
|
console.log(dim(" " + TAGLINE + " v" + VERSION));
|
|
123803
124533
|
console.log();
|
|
@@ -123840,7 +124570,7 @@ function config4() {
|
|
|
123840
124570
|
console.log(` ${dim(".claude/skills/")}`);
|
|
123841
124571
|
console.log(` ${dim("skill/")}`);
|
|
123842
124572
|
console.log();
|
|
123843
|
-
const bundledSkillsPath =
|
|
124573
|
+
const bundledSkillsPath = join28(__dirname2, "..", "global-skills");
|
|
123844
124574
|
if (existsSync20(bundledSkillsPath)) {
|
|
123845
124575
|
try {
|
|
123846
124576
|
const { readdirSync: readdirSync3 } = __require("fs");
|
|
@@ -124269,6 +124999,7 @@ ${cyan("Stats & History:")}
|
|
|
124269
124999
|
swarm stats Show swarm health metrics powered by swarm-insights (last 7 days)
|
|
124270
125000
|
swarm stats --since 24h Show stats for custom time period
|
|
124271
125001
|
swarm stats --regressions Show eval regressions (>10% score drops)
|
|
125002
|
+
swarm stats --rejections Show rejection reason analytics
|
|
124272
125003
|
swarm stats --json Output as JSON for scripting
|
|
124273
125004
|
swarm o11y Show observability health dashboard (hook coverage, events, sessions)
|
|
124274
125005
|
swarm o11y --since 7d Custom time period for event stats (default: 7 days)
|
|
@@ -124410,7 +125141,7 @@ async function listTools() {
|
|
|
124410
125141
|
}
|
|
124411
125142
|
async function agents(nonInteractive = false) {
|
|
124412
125143
|
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
124413
|
-
const agentsPath =
|
|
125144
|
+
const agentsPath = join28(home, ".config", "opencode", "AGENTS.md");
|
|
124414
125145
|
p.intro(yellow(BANNER));
|
|
124415
125146
|
if (!existsSync20(agentsPath)) {
|
|
124416
125147
|
p.log.warn("No AGENTS.md found at " + agentsPath);
|
|
@@ -124484,9 +125215,9 @@ async function migrate() {
|
|
|
124484
125215
|
p.intro("swarm migrate v" + VERSION);
|
|
124485
125216
|
const projectPath = process.cwd();
|
|
124486
125217
|
const tempDirName = getLibSQLProjectTempDirName(projectPath);
|
|
124487
|
-
const tempDir =
|
|
124488
|
-
const pglitePath =
|
|
124489
|
-
const libsqlPath =
|
|
125218
|
+
const tempDir = join28(tmpdir3(), tempDirName);
|
|
125219
|
+
const pglitePath = join28(tempDir, "streams");
|
|
125220
|
+
const libsqlPath = join28(tempDir, "streams.db");
|
|
124490
125221
|
if (!pgliteExists(pglitePath)) {
|
|
124491
125222
|
p.log.success("No PGlite database found - nothing to migrate!");
|
|
124492
125223
|
p.outro("Done");
|
|
@@ -124595,7 +125326,7 @@ function listSessionFiles(dir) {
|
|
|
124595
125326
|
const files = readdirSync2(dir).filter((f) => f.endsWith(".jsonl"));
|
|
124596
125327
|
const sessions = [];
|
|
124597
125328
|
for (const file4 of files) {
|
|
124598
|
-
const filePath =
|
|
125329
|
+
const filePath = join28(dir, file4);
|
|
124599
125330
|
try {
|
|
124600
125331
|
const events = parseSessionFile(filePath);
|
|
124601
125332
|
if (events.length === 0)
|
|
@@ -124645,7 +125376,7 @@ function formatEvent(event, useColor = true) {
|
|
|
124645
125376
|
}
|
|
124646
125377
|
async function logSessions() {
|
|
124647
125378
|
const args3 = process.argv.slice(4);
|
|
124648
|
-
const sessionsDir =
|
|
125379
|
+
const sessionsDir = join28(homedir10(), ".config", "swarm-tools", "sessions");
|
|
124649
125380
|
let sessionId = null;
|
|
124650
125381
|
let latest = false;
|
|
124651
125382
|
let jsonOutput = false;
|
|
@@ -124849,7 +125580,7 @@ function readLogFiles(dir) {
|
|
|
124849
125580
|
if (!existsSync20(dir))
|
|
124850
125581
|
return [];
|
|
124851
125582
|
const allFiles = readdirSync2(dir);
|
|
124852
|
-
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));
|
|
124853
125584
|
const entries2 = [];
|
|
124854
125585
|
for (const file4 of logFiles) {
|
|
124855
125586
|
try {
|
|
@@ -125034,7 +125765,7 @@ async function logs() {
|
|
|
125034
125765
|
moduleFilter = arg;
|
|
125035
125766
|
}
|
|
125036
125767
|
}
|
|
125037
|
-
const logsDir =
|
|
125768
|
+
const logsDir = join28(homedir10(), ".config", "swarm-tools", "logs");
|
|
125038
125769
|
if (!existsSync20(logsDir)) {
|
|
125039
125770
|
if (!jsonOutput) {
|
|
125040
125771
|
p.log.warn("No logs directory found");
|
|
@@ -125072,7 +125803,7 @@ async function logs() {
|
|
|
125072
125803
|
return;
|
|
125073
125804
|
const files = readdirSync2(logsDir).filter((f) => /\.\d+log$/.test(f) || /\.log$/.test(f));
|
|
125074
125805
|
for (const file4 of files) {
|
|
125075
|
-
const filePath =
|
|
125806
|
+
const filePath = join28(logsDir, file4);
|
|
125076
125807
|
try {
|
|
125077
125808
|
const stats = statSync2(filePath);
|
|
125078
125809
|
filePositions.set(filePath, stats.size);
|
|
@@ -125110,7 +125841,7 @@ async function logs() {
|
|
|
125110
125841
|
return;
|
|
125111
125842
|
const files = readdirSync2(logsDir).filter((f) => /\.\d+log$/.test(f) || /\.log$/.test(f));
|
|
125112
125843
|
for (const file4 of files) {
|
|
125113
|
-
const filePath =
|
|
125844
|
+
const filePath = join28(logsDir, file4);
|
|
125114
125845
|
const newLines = readNewLines(filePath);
|
|
125115
125846
|
for (const line of newLines) {
|
|
125116
125847
|
const parsed = parseLogLine(line, filePath);
|
|
@@ -125161,7 +125892,112 @@ async function logs() {
|
|
|
125161
125892
|
console.log();
|
|
125162
125893
|
}
|
|
125163
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
|
+
}
|
|
125164
125995
|
async function db() {
|
|
125996
|
+
const args3 = process.argv.slice(3);
|
|
125997
|
+
if (args3[0] === "repair") {
|
|
125998
|
+
await dbRepair();
|
|
125999
|
+
return;
|
|
126000
|
+
}
|
|
125165
126001
|
const projectPath = process.cwd();
|
|
125166
126002
|
const projectName = basename3(projectPath);
|
|
125167
126003
|
const hash5 = hashLibSQLProjectPath(projectPath);
|
|
@@ -125222,7 +126058,7 @@ async function db() {
|
|
|
125222
126058
|
console.log(dim(" Will be created on first use"));
|
|
125223
126059
|
}
|
|
125224
126060
|
console.log();
|
|
125225
|
-
const pglitePath =
|
|
126061
|
+
const pglitePath = join28(dbDir, "streams");
|
|
125226
126062
|
if (existsSync20(pglitePath)) {
|
|
125227
126063
|
console.log(` \x1B[33m!\x1B[0m Legacy PGLite directory exists`);
|
|
125228
126064
|
console.log(dim(` ${pglitePath}`));
|
|
@@ -125333,6 +126169,7 @@ async function stats() {
|
|
|
125333
126169
|
let period = "7d";
|
|
125334
126170
|
let format5 = "text";
|
|
125335
126171
|
let showRegressions = false;
|
|
126172
|
+
let showRejections = false;
|
|
125336
126173
|
for (let i = 0;i < args3.length; i++) {
|
|
125337
126174
|
if (args3[i] === "--since" || args3[i] === "-s") {
|
|
125338
126175
|
period = args3[i + 1] || "7d";
|
|
@@ -125341,6 +126178,8 @@ async function stats() {
|
|
|
125341
126178
|
format5 = "json";
|
|
125342
126179
|
} else if (args3[i] === "--regressions") {
|
|
125343
126180
|
showRegressions = true;
|
|
126181
|
+
} else if (args3[i] === "--rejections") {
|
|
126182
|
+
showRejections = true;
|
|
125344
126183
|
}
|
|
125345
126184
|
}
|
|
125346
126185
|
try {
|
|
@@ -125369,21 +126208,21 @@ async function stats() {
|
|
|
125369
126208
|
strategy: row.strategy,
|
|
125370
126209
|
success: row.success === "true"
|
|
125371
126210
|
})));
|
|
125372
|
-
const sessionsPath =
|
|
126211
|
+
const sessionsPath = join28(homedir10(), ".config", "swarm-tools", "sessions");
|
|
125373
126212
|
let coordinatorStats = {
|
|
125374
126213
|
violationRate: 0,
|
|
125375
126214
|
spawnEfficiency: 0,
|
|
125376
126215
|
reviewThoroughness: 0
|
|
125377
126216
|
};
|
|
125378
126217
|
if (existsSync20(sessionsPath)) {
|
|
125379
|
-
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);
|
|
125380
126219
|
let totalViolations = 0;
|
|
125381
126220
|
let totalSpawns = 0;
|
|
125382
126221
|
let totalReviews = 0;
|
|
125383
126222
|
let totalSwarms = 0;
|
|
125384
126223
|
for (const file4 of sessionFiles) {
|
|
125385
126224
|
try {
|
|
125386
|
-
const content = readFileSync16(
|
|
126225
|
+
const content = readFileSync16(join28(sessionsPath, file4), "utf-8");
|
|
125387
126226
|
const lines = content.trim().split(`
|
|
125388
126227
|
`);
|
|
125389
126228
|
let violations = 0;
|
|
@@ -125448,6 +126287,34 @@ async function stats() {
|
|
|
125448
126287
|
`);
|
|
125449
126288
|
}
|
|
125450
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
|
+
}
|
|
125451
126318
|
} else {
|
|
125452
126319
|
if (format5 === "json") {
|
|
125453
126320
|
console.log(JSON.stringify(stats2, null, 2));
|
|
@@ -125673,7 +126540,7 @@ async function evalRun() {
|
|
|
125673
126540
|
}
|
|
125674
126541
|
}
|
|
125675
126542
|
if (ciMode) {
|
|
125676
|
-
const resultsPath =
|
|
126543
|
+
const resultsPath = join28(projectPath, ".hive", "eval-results.json");
|
|
125677
126544
|
ensureHiveDirectory(projectPath);
|
|
125678
126545
|
writeFileSync7(resultsPath, JSON.stringify(results, null, 2));
|
|
125679
126546
|
console.log(`
|
|
@@ -125861,11 +126728,11 @@ async function memory() {
|
|
|
125861
126728
|
try {
|
|
125862
126729
|
const { getDb: getDb2 } = await import("swarm-mail");
|
|
125863
126730
|
const tempDirName = getLibSQLProjectTempDirName(projectPath);
|
|
125864
|
-
const tempDir =
|
|
126731
|
+
const tempDir = join28(tmpdir3(), tempDirName);
|
|
125865
126732
|
if (!existsSync20(tempDir)) {
|
|
125866
126733
|
mkdirSync11(tempDir, { recursive: true });
|
|
125867
126734
|
}
|
|
125868
|
-
const dbPath =
|
|
126735
|
+
const dbPath = join28(tempDir, "streams.db");
|
|
125869
126736
|
const dbUrl = `file://${dbPath}`;
|
|
125870
126737
|
const db2 = await getDb2(dbUrl);
|
|
125871
126738
|
const { createMemoryAdapter: createMemoryAdapter3 } = await import("swarm-mail");
|