opencode-swarm-plugin 0.44.2 → 0.45.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 +277 -54
- package/bin/swarm.ts +1 -1
- package/dist/decision-trace-integration.d.ts +204 -0
- package/dist/decision-trace-integration.d.ts.map +1 -0
- package/dist/hive.d.ts.map +1 -1
- package/dist/hive.js +9 -9
- package/dist/index.d.ts +32 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +535 -27
- package/dist/plugin.js +295 -27
- package/dist/query-tools.d.ts +20 -12
- package/dist/query-tools.d.ts.map +1 -1
- package/dist/swarm-decompose.d.ts +4 -4
- package/dist/swarm-decompose.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-prompts.js +220 -22
- package/dist/swarm-review.d.ts.map +1 -1
- package/dist/swarm-signature.d.ts +106 -0
- package/dist/swarm-signature.d.ts.map +1 -0
- package/dist/swarm-strategies.d.ts +16 -3
- package/dist/swarm-strategies.d.ts.map +1 -1
- package/dist/swarm.d.ts +4 -2
- package/dist/swarm.d.ts.map +1 -1
- package/examples/commands/swarm.md +745 -0
- package/examples/plugin-wrapper-template.ts +2611 -0
- package/examples/skills/hive-workflow/SKILL.md +212 -0
- package/examples/skills/skill-creator/SKILL.md +223 -0
- package/examples/skills/swarm-coordination/SKILL.md +292 -0
- package/global-skills/cli-builder/SKILL.md +344 -0
- package/global-skills/cli-builder/references/advanced-patterns.md +244 -0
- package/global-skills/learning-systems/SKILL.md +644 -0
- package/global-skills/skill-creator/LICENSE.txt +202 -0
- package/global-skills/skill-creator/SKILL.md +352 -0
- package/global-skills/skill-creator/references/output-patterns.md +82 -0
- package/global-skills/skill-creator/references/workflows.md +28 -0
- package/global-skills/swarm-coordination/SKILL.md +995 -0
- package/global-skills/swarm-coordination/references/coordinator-patterns.md +235 -0
- package/global-skills/swarm-coordination/references/strategies.md +138 -0
- package/global-skills/system-design/SKILL.md +213 -0
- package/global-skills/testing-patterns/SKILL.md +430 -0
- package/global-skills/testing-patterns/references/dependency-breaking-catalog.md +586 -0
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -22560,7 +22560,7 @@ __export(exports_swarm_strategies, {
|
|
|
22560
22560
|
NEGATIVE_MARKERS: () => NEGATIVE_MARKERS,
|
|
22561
22561
|
DecompositionStrategySchema: () => DecompositionStrategySchema
|
|
22562
22562
|
});
|
|
22563
|
-
function selectStrategy(task) {
|
|
22563
|
+
async function selectStrategy(task, projectKey) {
|
|
22564
22564
|
const taskLower = task.toLowerCase();
|
|
22565
22565
|
const scores = {
|
|
22566
22566
|
"file-based": 0,
|
|
@@ -22588,7 +22588,8 @@ function selectStrategy(task) {
|
|
|
22588
22588
|
const [winner, winnerScore] = entries[0];
|
|
22589
22589
|
const [, runnerUpScore] = entries[1] || [null, 0];
|
|
22590
22590
|
const totalScore = entries.reduce((sum, [, score]) => sum + score, 0);
|
|
22591
|
-
|
|
22591
|
+
let confidence = totalScore > 0 ? Math.min(0.95, 0.5 + (winnerScore - runnerUpScore) / totalScore) : 0.5;
|
|
22592
|
+
const finalStrategy = winnerScore === 0 ? "feature-based" : winner;
|
|
22592
22593
|
let reasoning;
|
|
22593
22594
|
if (winnerScore === 0) {
|
|
22594
22595
|
reasoning = `No strong keyword signals. Defaulting to feature-based as it's most versatile.`;
|
|
@@ -22596,12 +22597,73 @@ function selectStrategy(task) {
|
|
|
22596
22597
|
const matchedKeywords = STRATEGIES[winner].keywords.filter((k) => taskLower.includes(k));
|
|
22597
22598
|
reasoning = `Matched keywords: ${matchedKeywords.join(", ")}. ${STRATEGIES[winner].description}`;
|
|
22598
22599
|
}
|
|
22599
|
-
|
|
22600
|
+
let precedent;
|
|
22601
|
+
if (projectKey) {
|
|
22602
|
+
try {
|
|
22603
|
+
const {
|
|
22604
|
+
createLibSQLAdapter,
|
|
22605
|
+
getDatabasePath,
|
|
22606
|
+
findSimilarDecisions,
|
|
22607
|
+
getStrategySuccessRates
|
|
22608
|
+
} = await import("swarm-mail");
|
|
22609
|
+
const dbPath = getDatabasePath(projectKey);
|
|
22610
|
+
const db = await createLibSQLAdapter({ url: `file:${dbPath}` });
|
|
22611
|
+
const similarDecisions = await findSimilarDecisions(db, task, 5);
|
|
22612
|
+
const successRates = await getStrategySuccessRates(db);
|
|
22613
|
+
precedent = {
|
|
22614
|
+
similar_decisions: similarDecisions.length
|
|
22615
|
+
};
|
|
22616
|
+
if (similarDecisions.length > 0) {
|
|
22617
|
+
const epicIds = [];
|
|
22618
|
+
for (const decision of similarDecisions) {
|
|
22619
|
+
try {
|
|
22620
|
+
const decisionData = typeof decision.decision === "string" ? JSON.parse(decision.decision) : decision.decision;
|
|
22621
|
+
if (decisionData.epic_id) {
|
|
22622
|
+
epicIds.push(decisionData.epic_id);
|
|
22623
|
+
}
|
|
22624
|
+
} catch {}
|
|
22625
|
+
}
|
|
22626
|
+
if (epicIds.length > 0) {
|
|
22627
|
+
precedent.cited_epics = epicIds;
|
|
22628
|
+
}
|
|
22629
|
+
const precedentStrategies = similarDecisions.map((d) => {
|
|
22630
|
+
try {
|
|
22631
|
+
const data = typeof d.decision === "string" ? JSON.parse(d.decision) : d.decision;
|
|
22632
|
+
return data.strategy;
|
|
22633
|
+
} catch {
|
|
22634
|
+
return null;
|
|
22635
|
+
}
|
|
22636
|
+
}).filter(Boolean);
|
|
22637
|
+
const agreesWithKeywords = precedentStrategies.includes(finalStrategy);
|
|
22638
|
+
if (agreesWithKeywords) {
|
|
22639
|
+
confidence = Math.min(0.95, confidence + 0.1);
|
|
22640
|
+
reasoning += ` Precedent confirms: ${precedent.similar_decisions} similar decision(s) also chose ${finalStrategy}.`;
|
|
22641
|
+
}
|
|
22642
|
+
}
|
|
22643
|
+
const strategyRate = successRates.find((r) => r.strategy === finalStrategy);
|
|
22644
|
+
if (strategyRate) {
|
|
22645
|
+
precedent.strategy_success_rate = strategyRate.success_rate;
|
|
22646
|
+
if (strategyRate.success_rate >= 0.7) {
|
|
22647
|
+
confidence = Math.min(0.95, confidence + 0.05);
|
|
22648
|
+
reasoning += ` ${finalStrategy} has ${Math.round(strategyRate.success_rate * 100)}% success rate.`;
|
|
22649
|
+
} else if (strategyRate.success_rate < 0.3) {
|
|
22650
|
+
confidence = Math.max(0.1, confidence - 0.1);
|
|
22651
|
+
reasoning += ` Warning: ${finalStrategy} has low success rate (${Math.round(strategyRate.success_rate * 100)}%).`;
|
|
22652
|
+
}
|
|
22653
|
+
}
|
|
22654
|
+
if (db.close) {
|
|
22655
|
+
await db.close();
|
|
22656
|
+
}
|
|
22657
|
+
} catch (error45) {
|
|
22658
|
+
console.warn("Failed to query precedent data:", error45);
|
|
22659
|
+
}
|
|
22660
|
+
}
|
|
22600
22661
|
return {
|
|
22601
22662
|
strategy: finalStrategy,
|
|
22602
22663
|
confidence,
|
|
22603
22664
|
reasoning,
|
|
22604
|
-
alternatives: entries.filter(([s]) => s !== finalStrategy).map(([strategy, score]) => ({ strategy, score }))
|
|
22665
|
+
alternatives: entries.filter(([s]) => s !== finalStrategy).map(([strategy, score]) => ({ strategy, score })),
|
|
22666
|
+
precedent
|
|
22605
22667
|
};
|
|
22606
22668
|
}
|
|
22607
22669
|
function formatStrategyGuidelines(strategy) {
|
|
@@ -22810,13 +22872,14 @@ var init_swarm_strategies = __esm(() => {
|
|
|
22810
22872
|
}
|
|
22811
22873
|
};
|
|
22812
22874
|
swarm_select_strategy = tool({
|
|
22813
|
-
description: "Analyze task and recommend decomposition strategy (file-based, feature-based, or risk-based)",
|
|
22875
|
+
description: "Analyze task and recommend decomposition strategy (file-based, feature-based, or risk-based) with optional precedent data",
|
|
22814
22876
|
args: {
|
|
22815
22877
|
task: tool.schema.string().min(1).describe("Task description to analyze"),
|
|
22816
|
-
codebase_context: tool.schema.string().optional().describe("Optional codebase context (file structure, tech stack, etc.)")
|
|
22878
|
+
codebase_context: tool.schema.string().optional().describe("Optional codebase context (file structure, tech stack, etc.)"),
|
|
22879
|
+
projectKey: tool.schema.string().optional().describe("Optional project path for precedent-aware strategy selection")
|
|
22817
22880
|
},
|
|
22818
22881
|
async execute(args) {
|
|
22819
|
-
const result = selectStrategy(args.task);
|
|
22882
|
+
const result = await selectStrategy(args.task, args.projectKey);
|
|
22820
22883
|
let enhancedReasoning = result.reasoning;
|
|
22821
22884
|
if (args.codebase_context) {
|
|
22822
22885
|
enhancedReasoning += `
|
|
@@ -22834,7 +22897,8 @@ Codebase context considered: ${args.codebase_context.slice(0, 200)}...`;
|
|
|
22834
22897
|
strategy: alt.strategy,
|
|
22835
22898
|
description: STRATEGIES[alt.strategy].description,
|
|
22836
22899
|
score: alt.score
|
|
22837
|
-
}))
|
|
22900
|
+
})),
|
|
22901
|
+
precedent: result.precedent
|
|
22838
22902
|
}, null, 2);
|
|
22839
22903
|
}
|
|
22840
22904
|
});
|
|
@@ -39017,7 +39081,8 @@ import {
|
|
|
39017
39081
|
importFromJSONL,
|
|
39018
39082
|
syncMemories,
|
|
39019
39083
|
getSwarmMailLibSQL,
|
|
39020
|
-
resolvePartialId
|
|
39084
|
+
resolvePartialId,
|
|
39085
|
+
findCellsByPartialId
|
|
39021
39086
|
} from "swarm-mail";
|
|
39022
39087
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
39023
39088
|
import { join as join2 } from "node:path";
|
|
@@ -40408,13 +40473,12 @@ PREFER THIS OVER hive_query when you need to:
|
|
|
40408
40473
|
const adapter = await getHiveAdapter(projectKey);
|
|
40409
40474
|
try {
|
|
40410
40475
|
if (args.id) {
|
|
40411
|
-
const
|
|
40412
|
-
|
|
40413
|
-
if (!cell) {
|
|
40476
|
+
const matchingCells = await findCellsByPartialId(adapter, projectKey, args.id);
|
|
40477
|
+
if (matchingCells.length === 0) {
|
|
40414
40478
|
throw new HiveError(`No cell found matching ID '${args.id}'`, "hive_cells");
|
|
40415
40479
|
}
|
|
40416
|
-
const formatted2 = formatCellForOutput(
|
|
40417
|
-
return JSON.stringify(
|
|
40480
|
+
const formatted2 = matchingCells.map((c) => formatCellForOutput(c));
|
|
40481
|
+
return JSON.stringify(formatted2, null, 2);
|
|
40418
40482
|
}
|
|
40419
40483
|
if (args.ready) {
|
|
40420
40484
|
const ready = await adapter.getNextReadyCell(projectKey);
|
|
@@ -40433,10 +40497,10 @@ PREFER THIS OVER hive_query when you need to:
|
|
|
40433
40497
|
const formatted = cells.map((c) => formatCellForOutput(c));
|
|
40434
40498
|
return JSON.stringify(formatted, null, 2);
|
|
40435
40499
|
} catch (error45) {
|
|
40436
|
-
|
|
40437
|
-
|
|
40438
|
-
throw new HiveError(`Ambiguous ID '${args.id}': multiple cells match. Please provide more characters.`, "hive_cells");
|
|
40500
|
+
if (error45 instanceof HiveError) {
|
|
40501
|
+
throw error45;
|
|
40439
40502
|
}
|
|
40503
|
+
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
40440
40504
|
if (message.includes("Bead not found") || message.includes("Cell not found")) {
|
|
40441
40505
|
throw new HiveError(`No cell found matching ID '${args.id || "unknown"}'`, "hive_cells");
|
|
40442
40506
|
}
|
|
@@ -42883,6 +42947,139 @@ init_dist();
|
|
|
42883
42947
|
init_zod();
|
|
42884
42948
|
init_swarm_strategies();
|
|
42885
42949
|
init_eval_capture();
|
|
42950
|
+
|
|
42951
|
+
// src/decision-trace-integration.ts
|
|
42952
|
+
import {
|
|
42953
|
+
createDecisionTrace,
|
|
42954
|
+
createEntityLink
|
|
42955
|
+
} from "swarm-mail";
|
|
42956
|
+
import { createLibSQLAdapter } from "swarm-mail";
|
|
42957
|
+
import { getDatabasePath } from "swarm-mail";
|
|
42958
|
+
async function getTraceDb(projectPath) {
|
|
42959
|
+
const dbPath = getDatabasePath(projectPath);
|
|
42960
|
+
return createLibSQLAdapter({ url: `file:${dbPath}` });
|
|
42961
|
+
}
|
|
42962
|
+
function extractMemoryIds(precedentCited) {
|
|
42963
|
+
if (!precedentCited) {
|
|
42964
|
+
return [];
|
|
42965
|
+
}
|
|
42966
|
+
if (precedentCited.memoryIds && Array.isArray(precedentCited.memoryIds)) {
|
|
42967
|
+
return precedentCited.memoryIds;
|
|
42968
|
+
}
|
|
42969
|
+
if (precedentCited.memoryId) {
|
|
42970
|
+
return [precedentCited.memoryId];
|
|
42971
|
+
}
|
|
42972
|
+
return [];
|
|
42973
|
+
}
|
|
42974
|
+
async function traceStrategySelection(input) {
|
|
42975
|
+
try {
|
|
42976
|
+
const db = await getTraceDb(input.projectKey);
|
|
42977
|
+
const trace = await createDecisionTrace(db, {
|
|
42978
|
+
decision_type: "strategy_selection",
|
|
42979
|
+
epic_id: input.epicId,
|
|
42980
|
+
bead_id: input.beadId,
|
|
42981
|
+
agent_name: input.agentName,
|
|
42982
|
+
project_key: input.projectKey,
|
|
42983
|
+
decision: {
|
|
42984
|
+
strategy: input.strategy,
|
|
42985
|
+
confidence: input.confidence,
|
|
42986
|
+
task_preview: input.taskPreview
|
|
42987
|
+
},
|
|
42988
|
+
rationale: input.reasoning,
|
|
42989
|
+
inputs_gathered: input.inputsGathered,
|
|
42990
|
+
alternatives: input.alternatives,
|
|
42991
|
+
precedent_cited: input.precedentCited
|
|
42992
|
+
});
|
|
42993
|
+
const memoryIds = extractMemoryIds(input.precedentCited);
|
|
42994
|
+
for (const memoryId of memoryIds) {
|
|
42995
|
+
await createEntityLink(db, {
|
|
42996
|
+
source_decision_id: trace.id,
|
|
42997
|
+
target_entity_type: "memory",
|
|
42998
|
+
target_entity_id: memoryId,
|
|
42999
|
+
link_type: "cites_precedent",
|
|
43000
|
+
strength: input.precedentCited?.similarity ?? 1,
|
|
43001
|
+
context: "Cited as precedent for strategy selection"
|
|
43002
|
+
});
|
|
43003
|
+
}
|
|
43004
|
+
await db.close?.();
|
|
43005
|
+
return trace.id;
|
|
43006
|
+
} catch (error45) {
|
|
43007
|
+
console.warn("[decision-trace] Failed to trace strategy_selection:", error45);
|
|
43008
|
+
return "";
|
|
43009
|
+
}
|
|
43010
|
+
}
|
|
43011
|
+
async function traceWorkerSpawn(input) {
|
|
43012
|
+
try {
|
|
43013
|
+
const db = await getTraceDb(input.projectKey);
|
|
43014
|
+
const trace = await createDecisionTrace(db, {
|
|
43015
|
+
decision_type: "worker_spawn",
|
|
43016
|
+
epic_id: input.epicId,
|
|
43017
|
+
bead_id: input.beadId,
|
|
43018
|
+
agent_name: input.agentName,
|
|
43019
|
+
project_key: input.projectKey,
|
|
43020
|
+
decision: {
|
|
43021
|
+
worker: input.workerName || "worker",
|
|
43022
|
+
subtask_title: input.subtaskTitle,
|
|
43023
|
+
files: input.files,
|
|
43024
|
+
model: input.model,
|
|
43025
|
+
spawn_order: input.spawnOrder,
|
|
43026
|
+
is_parallel: input.isParallel
|
|
43027
|
+
},
|
|
43028
|
+
rationale: input.rationale || `Spawning worker for: ${input.subtaskTitle}`
|
|
43029
|
+
});
|
|
43030
|
+
for (const file2 of input.files) {
|
|
43031
|
+
await createEntityLink(db, {
|
|
43032
|
+
source_decision_id: trace.id,
|
|
43033
|
+
target_entity_type: "file",
|
|
43034
|
+
target_entity_id: file2,
|
|
43035
|
+
link_type: "assigns_file",
|
|
43036
|
+
strength: 1,
|
|
43037
|
+
context: `File assigned to worker ${input.workerName || "worker"}`
|
|
43038
|
+
});
|
|
43039
|
+
}
|
|
43040
|
+
await db.close?.();
|
|
43041
|
+
return trace.id;
|
|
43042
|
+
} catch (error45) {
|
|
43043
|
+
console.warn("[decision-trace] Failed to trace worker_spawn:", error45);
|
|
43044
|
+
return "";
|
|
43045
|
+
}
|
|
43046
|
+
}
|
|
43047
|
+
async function traceReviewDecision(input) {
|
|
43048
|
+
try {
|
|
43049
|
+
const db = await getTraceDb(input.projectKey);
|
|
43050
|
+
const trace = await createDecisionTrace(db, {
|
|
43051
|
+
decision_type: "review_decision",
|
|
43052
|
+
epic_id: input.epicId,
|
|
43053
|
+
bead_id: input.beadId,
|
|
43054
|
+
agent_name: input.agentName,
|
|
43055
|
+
project_key: input.projectKey,
|
|
43056
|
+
decision: {
|
|
43057
|
+
status: input.status,
|
|
43058
|
+
worker_id: input.workerId,
|
|
43059
|
+
issues_count: input.issues?.length || 0,
|
|
43060
|
+
attempt_number: input.attemptNumber,
|
|
43061
|
+
remaining_attempts: input.remainingAttempts
|
|
43062
|
+
},
|
|
43063
|
+
rationale: input.rationale || input.summary || `Review ${input.status}`,
|
|
43064
|
+
inputs_gathered: input.issues ? [{ source: "code_review", issues: input.issues }] : undefined
|
|
43065
|
+
});
|
|
43066
|
+
await createEntityLink(db, {
|
|
43067
|
+
source_decision_id: trace.id,
|
|
43068
|
+
target_entity_type: "agent",
|
|
43069
|
+
target_entity_id: input.workerId,
|
|
43070
|
+
link_type: "reviewed_work_by",
|
|
43071
|
+
strength: 1,
|
|
43072
|
+
context: `Review ${input.status} for ${input.workerId}`
|
|
43073
|
+
});
|
|
43074
|
+
await db.close?.();
|
|
43075
|
+
return trace.id;
|
|
43076
|
+
} catch (error45) {
|
|
43077
|
+
console.warn("[decision-trace] Failed to trace review_decision:", error45);
|
|
43078
|
+
return "";
|
|
43079
|
+
}
|
|
43080
|
+
}
|
|
43081
|
+
|
|
43082
|
+
// src/swarm-decompose.ts
|
|
42886
43083
|
var DECOMPOSITION_PROMPT = `You are decomposing a task into parallelizable subtasks for a swarm of agents.
|
|
42887
43084
|
|
|
42888
43085
|
## Task
|
|
@@ -43314,7 +43511,7 @@ var swarm_delegate_planning = tool({
|
|
|
43314
43511
|
selectedStrategy = args.strategy;
|
|
43315
43512
|
strategyReasoning = `User-specified strategy: ${selectedStrategy}`;
|
|
43316
43513
|
} else {
|
|
43317
|
-
const selection = selectStrategy2(args.task);
|
|
43514
|
+
const selection = await selectStrategy2(args.task);
|
|
43318
43515
|
selectedStrategy = selection.strategy;
|
|
43319
43516
|
strategyReasoning = selection.reasoning;
|
|
43320
43517
|
}
|
|
@@ -43356,6 +43553,27 @@ var swarm_delegate_planning = tool({
|
|
|
43356
43553
|
} else {
|
|
43357
43554
|
cassResultInfo = { queried: false, reason: "disabled" };
|
|
43358
43555
|
}
|
|
43556
|
+
try {
|
|
43557
|
+
await traceStrategySelection({
|
|
43558
|
+
projectKey: args.context?.includes("/") ? args.context.split(" ")[0] : process.cwd(),
|
|
43559
|
+
agentName: "coordinator",
|
|
43560
|
+
epicId: undefined,
|
|
43561
|
+
strategy: selectedStrategy,
|
|
43562
|
+
reasoning: strategyReasoning,
|
|
43563
|
+
confidence: undefined,
|
|
43564
|
+
taskPreview: args.task.slice(0, 200),
|
|
43565
|
+
inputsGathered: cassResultInfo.queried ? [
|
|
43566
|
+
{
|
|
43567
|
+
source: "cass",
|
|
43568
|
+
query: args.task,
|
|
43569
|
+
results: cassResultInfo.results_found ?? 0
|
|
43570
|
+
}
|
|
43571
|
+
] : undefined,
|
|
43572
|
+
alternatives: undefined
|
|
43573
|
+
});
|
|
43574
|
+
} catch (error45) {
|
|
43575
|
+
console.warn("[swarm_delegate_planning] Failed to trace strategy_selection:", error45);
|
|
43576
|
+
}
|
|
43359
43577
|
let skillsContext = "";
|
|
43360
43578
|
let skillsInfo = {
|
|
43361
43579
|
included: false
|
|
@@ -43493,7 +43711,7 @@ Limit: ${memoryQuery.limit}`;
|
|
|
43493
43711
|
}
|
|
43494
43712
|
} catch (error45) {}
|
|
43495
43713
|
if (mode === "fast") {
|
|
43496
|
-
const strategyResult = selectStrategy2(args.task);
|
|
43714
|
+
const strategyResult = await selectStrategy2(args.task);
|
|
43497
43715
|
const guidelines = formatStrategyGuidelines2(strategyResult.strategy);
|
|
43498
43716
|
const output = {
|
|
43499
43717
|
mode: "fast",
|
|
@@ -43512,7 +43730,7 @@ ${guidelines}`
|
|
|
43512
43730
|
return JSON.stringify(output, null, 2);
|
|
43513
43731
|
}
|
|
43514
43732
|
if (mode === "auto") {
|
|
43515
|
-
const strategyResult = selectStrategy2(args.task);
|
|
43733
|
+
const strategyResult = await selectStrategy2(args.task);
|
|
43516
43734
|
const output = {
|
|
43517
43735
|
mode: "auto",
|
|
43518
43736
|
phase: "ready",
|
|
@@ -43607,7 +43825,7 @@ ${guidelines}`
|
|
|
43607
43825
|
return JSON.stringify(output, null, 2);
|
|
43608
43826
|
}
|
|
43609
43827
|
if (currentPhase === "alternatives") {
|
|
43610
|
-
const strategyResult = selectStrategy2(args.task);
|
|
43828
|
+
const strategyResult = await selectStrategy2(args.task);
|
|
43611
43829
|
const alternatives = [];
|
|
43612
43830
|
alternatives.push({
|
|
43613
43831
|
name: strategyResult.strategy,
|
|
@@ -43634,7 +43852,7 @@ ${guidelines}`
|
|
|
43634
43852
|
return JSON.stringify(output, null, 2);
|
|
43635
43853
|
}
|
|
43636
43854
|
if (currentPhase === "recommendation") {
|
|
43637
|
-
const strategyResult = selectStrategy2(args.task);
|
|
43855
|
+
const strategyResult = await selectStrategy2(args.task);
|
|
43638
43856
|
const guidelines = formatStrategyGuidelines2(strategyResult.strategy);
|
|
43639
43857
|
const output = {
|
|
43640
43858
|
mode: "socratic",
|
|
@@ -45705,6 +45923,22 @@ var swarm_review_feedback = tool({
|
|
|
45705
45923
|
} catch (error45) {
|
|
45706
45924
|
console.warn("[swarm_review_feedback] Failed to capture review_completed:", error45);
|
|
45707
45925
|
}
|
|
45926
|
+
try {
|
|
45927
|
+
await traceReviewDecision({
|
|
45928
|
+
projectKey: args.project_key,
|
|
45929
|
+
agentName: "coordinator",
|
|
45930
|
+
epicId,
|
|
45931
|
+
beadId: args.task_id,
|
|
45932
|
+
workerId: args.worker_id,
|
|
45933
|
+
status: "approved",
|
|
45934
|
+
summary: args.summary,
|
|
45935
|
+
attemptNumber: 1,
|
|
45936
|
+
remainingAttempts: MAX_REVIEW_ATTEMPTS,
|
|
45937
|
+
rationale: args.summary || "Review approved"
|
|
45938
|
+
});
|
|
45939
|
+
} catch (error45) {
|
|
45940
|
+
console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
|
|
45941
|
+
}
|
|
45708
45942
|
try {
|
|
45709
45943
|
const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
|
|
45710
45944
|
const attempt = getReviewStatus(args.task_id).attempt_count || 1;
|
|
@@ -45759,6 +45993,23 @@ You may now complete the task with \`swarm_complete\`.`,
|
|
|
45759
45993
|
} catch (error45) {
|
|
45760
45994
|
console.warn("[swarm_review_feedback] Failed to capture review_completed:", error45);
|
|
45761
45995
|
}
|
|
45996
|
+
try {
|
|
45997
|
+
await traceReviewDecision({
|
|
45998
|
+
projectKey: args.project_key,
|
|
45999
|
+
agentName: "coordinator",
|
|
46000
|
+
epicId,
|
|
46001
|
+
beadId: args.task_id,
|
|
46002
|
+
workerId: args.worker_id,
|
|
46003
|
+
status: "needs_changes",
|
|
46004
|
+
summary: args.summary,
|
|
46005
|
+
issues: parsedIssues,
|
|
46006
|
+
attemptNumber,
|
|
46007
|
+
remainingAttempts: remaining,
|
|
46008
|
+
rationale: args.summary || `Review rejected: ${parsedIssues.length} issue(s) found`
|
|
46009
|
+
});
|
|
46010
|
+
} catch (error45) {
|
|
46011
|
+
console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
|
|
46012
|
+
}
|
|
45762
46013
|
try {
|
|
45763
46014
|
const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
|
|
45764
46015
|
const status = remaining <= 0 ? "blocked" : "needs_changes";
|
|
@@ -61939,9 +62190,9 @@ async function getPromptInsights(options2) {
|
|
|
61939
62190
|
}
|
|
61940
62191
|
async function getCoordinatorInsights(project_key) {
|
|
61941
62192
|
try {
|
|
61942
|
-
const { createLibSQLAdapter, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
|
|
62193
|
+
const { createLibSQLAdapter: createLibSQLAdapter2, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
|
|
61943
62194
|
const { getStrategyInsights: getStrategyInsights2, getPatternInsights: getPatternInsights2, formatInsightsForPrompt: formatInsightsForPrompt2 } = await Promise.resolve().then(() => (init_swarm_insights(), exports_swarm_insights));
|
|
61944
|
-
const dbAdapter = await
|
|
62195
|
+
const dbAdapter = await createLibSQLAdapter2({ url: "file:./.swarm-mail/streams.db" });
|
|
61945
62196
|
const adapter = createSwarmMailAdapter2(dbAdapter, project_key || "default");
|
|
61946
62197
|
const [strategies, patterns] = await Promise.all([
|
|
61947
62198
|
getStrategyInsights2(adapter, ""),
|
|
@@ -61969,7 +62220,7 @@ ${formatted}
|
|
|
61969
62220
|
}
|
|
61970
62221
|
async function getWorkerInsights(files, domain2) {
|
|
61971
62222
|
try {
|
|
61972
|
-
const { createLibSQLAdapter, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
|
|
62223
|
+
const { createLibSQLAdapter: createLibSQLAdapter2, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
|
|
61973
62224
|
const { getFileInsights: getFileInsights2, formatInsightsForPrompt: formatInsightsForPrompt2 } = await Promise.resolve().then(() => (init_swarm_insights(), exports_swarm_insights));
|
|
61974
62225
|
const memoryAdapter = await getMemoryAdapter();
|
|
61975
62226
|
let query = "";
|
|
@@ -61986,7 +62237,7 @@ async function getWorkerInsights(files, domain2) {
|
|
|
61986
62237
|
if (!files || files.length === 0)
|
|
61987
62238
|
return [];
|
|
61988
62239
|
try {
|
|
61989
|
-
const dbAdapter = await
|
|
62240
|
+
const dbAdapter = await createLibSQLAdapter2({ url: "file:./.swarm-mail/streams.db" });
|
|
61990
62241
|
const swarmMail = createSwarmMailAdapter2(dbAdapter, "default");
|
|
61991
62242
|
return await getFileInsights2(swarmMail, files);
|
|
61992
62243
|
} catch (e) {
|
|
@@ -62195,6 +62446,23 @@ var swarm_spawn_subtask = tool({
|
|
|
62195
62446
|
} catch (error45) {
|
|
62196
62447
|
console.warn("[swarm_spawn_subtask] Failed to capture worker_spawned:", error45);
|
|
62197
62448
|
}
|
|
62449
|
+
try {
|
|
62450
|
+
await traceWorkerSpawn({
|
|
62451
|
+
projectKey: args2.project_path || process.cwd(),
|
|
62452
|
+
agentName: "coordinator",
|
|
62453
|
+
epicId: args2.epic_id,
|
|
62454
|
+
beadId: args2.bead_id,
|
|
62455
|
+
workerName: "worker",
|
|
62456
|
+
subtaskTitle: args2.subtask_title,
|
|
62457
|
+
files: args2.files,
|
|
62458
|
+
model: selectedModel,
|
|
62459
|
+
spawnOrder: 0,
|
|
62460
|
+
isParallel: false,
|
|
62461
|
+
rationale: args2.subtask_description || `Spawning worker for: ${args2.subtask_title}`
|
|
62462
|
+
});
|
|
62463
|
+
} catch (error45) {
|
|
62464
|
+
console.warn("[swarm_spawn_subtask] Failed to trace worker_spawn:", error45);
|
|
62465
|
+
}
|
|
62198
62466
|
if (args2.project_path) {
|
|
62199
62467
|
try {
|
|
62200
62468
|
const { createEvent: createEvent3, appendEvent: appendEvent3 } = await import("swarm-mail");
|
|
@@ -62424,7 +62692,7 @@ var swarm_plan_prompt = tool({
|
|
|
62424
62692
|
selectedStrategy = args2.strategy;
|
|
62425
62693
|
strategyReasoning = `User-specified strategy: ${selectedStrategy}`;
|
|
62426
62694
|
} else {
|
|
62427
|
-
const selection = selectStrategy2(args2.task);
|
|
62695
|
+
const selection = await selectStrategy2(args2.task);
|
|
62428
62696
|
selectedStrategy = selection.strategy;
|
|
62429
62697
|
strategyReasoning = selection.reasoning;
|
|
62430
62698
|
}
|
|
@@ -66530,6 +66798,242 @@ async function resetStorage() {
|
|
|
66530
66798
|
// src/index.ts
|
|
66531
66799
|
init_skills();
|
|
66532
66800
|
init_swarm_validation();
|
|
66801
|
+
|
|
66802
|
+
// src/swarm-signature.ts
|
|
66803
|
+
function projectSwarmState(events) {
|
|
66804
|
+
const state = {
|
|
66805
|
+
isSwarm: false,
|
|
66806
|
+
subtasks: new Map,
|
|
66807
|
+
counts: {
|
|
66808
|
+
total: 0,
|
|
66809
|
+
created: 0,
|
|
66810
|
+
spawned: 0,
|
|
66811
|
+
inProgress: 0,
|
|
66812
|
+
completed: 0,
|
|
66813
|
+
closed: 0
|
|
66814
|
+
}
|
|
66815
|
+
};
|
|
66816
|
+
let hasEpic = false;
|
|
66817
|
+
let hasSpawn = false;
|
|
66818
|
+
for (const event of events) {
|
|
66819
|
+
state.lastEventAt = event.timestamp;
|
|
66820
|
+
switch (event.tool) {
|
|
66821
|
+
case "hive_create_epic": {
|
|
66822
|
+
const epicId = parseEpicId(event.output);
|
|
66823
|
+
const epicTitle = typeof event.input.epic_title === "string" ? event.input.epic_title : undefined;
|
|
66824
|
+
if (epicId) {
|
|
66825
|
+
state.epic = {
|
|
66826
|
+
id: epicId,
|
|
66827
|
+
title: epicTitle || "Unknown Epic",
|
|
66828
|
+
status: "open",
|
|
66829
|
+
createdAt: event.timestamp
|
|
66830
|
+
};
|
|
66831
|
+
hasEpic = true;
|
|
66832
|
+
const subtasks = event.input.subtasks;
|
|
66833
|
+
if (Array.isArray(subtasks)) {
|
|
66834
|
+
for (const subtask of subtasks) {
|
|
66835
|
+
if (typeof subtask === "object" && subtask !== null) {
|
|
66836
|
+
const st = subtask;
|
|
66837
|
+
const title = typeof st.title === "string" ? st.title : "Unknown";
|
|
66838
|
+
const files = Array.isArray(st.files) ? st.files : [];
|
|
66839
|
+
state.counts.created++;
|
|
66840
|
+
state.counts.total++;
|
|
66841
|
+
}
|
|
66842
|
+
}
|
|
66843
|
+
}
|
|
66844
|
+
const subtaskIds = parseSubtaskIds(event.output);
|
|
66845
|
+
for (const id of subtaskIds) {
|
|
66846
|
+
if (!state.subtasks.has(id)) {
|
|
66847
|
+
state.subtasks.set(id, {
|
|
66848
|
+
id,
|
|
66849
|
+
title: "Unknown",
|
|
66850
|
+
status: "created",
|
|
66851
|
+
files: []
|
|
66852
|
+
});
|
|
66853
|
+
state.counts.total++;
|
|
66854
|
+
state.counts.created++;
|
|
66855
|
+
}
|
|
66856
|
+
}
|
|
66857
|
+
}
|
|
66858
|
+
break;
|
|
66859
|
+
}
|
|
66860
|
+
case "swarm_spawn_subtask": {
|
|
66861
|
+
const beadId = typeof event.input.bead_id === "string" ? event.input.bead_id : undefined;
|
|
66862
|
+
const epicId = typeof event.input.epic_id === "string" ? event.input.epic_id : undefined;
|
|
66863
|
+
const title = typeof event.input.subtask_title === "string" ? event.input.subtask_title : "Unknown";
|
|
66864
|
+
const files = Array.isArray(event.input.files) ? event.input.files : [];
|
|
66865
|
+
if (beadId) {
|
|
66866
|
+
hasSpawn = true;
|
|
66867
|
+
const existing = state.subtasks.get(beadId);
|
|
66868
|
+
if (existing) {
|
|
66869
|
+
if (existing.status === "created") {
|
|
66870
|
+
state.counts.created--;
|
|
66871
|
+
state.counts.spawned++;
|
|
66872
|
+
}
|
|
66873
|
+
existing.status = "spawned";
|
|
66874
|
+
existing.title = title;
|
|
66875
|
+
existing.files = files;
|
|
66876
|
+
existing.spawnedAt = event.timestamp;
|
|
66877
|
+
} else {
|
|
66878
|
+
state.subtasks.set(beadId, {
|
|
66879
|
+
id: beadId,
|
|
66880
|
+
title,
|
|
66881
|
+
status: "spawned",
|
|
66882
|
+
files,
|
|
66883
|
+
spawnedAt: event.timestamp
|
|
66884
|
+
});
|
|
66885
|
+
state.counts.total++;
|
|
66886
|
+
state.counts.spawned++;
|
|
66887
|
+
}
|
|
66888
|
+
if (epicId && !state.epic) {
|
|
66889
|
+
state.epic = {
|
|
66890
|
+
id: epicId,
|
|
66891
|
+
title: "Unknown Epic",
|
|
66892
|
+
status: "in_progress",
|
|
66893
|
+
createdAt: event.timestamp
|
|
66894
|
+
};
|
|
66895
|
+
}
|
|
66896
|
+
}
|
|
66897
|
+
break;
|
|
66898
|
+
}
|
|
66899
|
+
case "hive_start": {
|
|
66900
|
+
const id = typeof event.input.id === "string" ? event.input.id : undefined;
|
|
66901
|
+
if (id) {
|
|
66902
|
+
const subtask = state.subtasks.get(id);
|
|
66903
|
+
if (subtask && subtask.status !== "completed" && subtask.status !== "closed") {
|
|
66904
|
+
if (subtask.status === "created")
|
|
66905
|
+
state.counts.created--;
|
|
66906
|
+
else if (subtask.status === "spawned")
|
|
66907
|
+
state.counts.spawned--;
|
|
66908
|
+
subtask.status = "in_progress";
|
|
66909
|
+
state.counts.inProgress++;
|
|
66910
|
+
}
|
|
66911
|
+
if (state.epic && state.epic.id === id) {
|
|
66912
|
+
state.epic.status = "in_progress";
|
|
66913
|
+
}
|
|
66914
|
+
}
|
|
66915
|
+
break;
|
|
66916
|
+
}
|
|
66917
|
+
case "swarm_complete": {
|
|
66918
|
+
const beadId = typeof event.input.bead_id === "string" ? event.input.bead_id : undefined;
|
|
66919
|
+
if (beadId) {
|
|
66920
|
+
const subtask = state.subtasks.get(beadId);
|
|
66921
|
+
if (subtask && subtask.status !== "closed") {
|
|
66922
|
+
if (subtask.status === "created")
|
|
66923
|
+
state.counts.created--;
|
|
66924
|
+
else if (subtask.status === "spawned")
|
|
66925
|
+
state.counts.spawned--;
|
|
66926
|
+
else if (subtask.status === "in_progress")
|
|
66927
|
+
state.counts.inProgress--;
|
|
66928
|
+
subtask.status = "completed";
|
|
66929
|
+
subtask.completedAt = event.timestamp;
|
|
66930
|
+
state.counts.completed++;
|
|
66931
|
+
}
|
|
66932
|
+
}
|
|
66933
|
+
break;
|
|
66934
|
+
}
|
|
66935
|
+
case "hive_close": {
|
|
66936
|
+
const id = typeof event.input.id === "string" ? event.input.id : undefined;
|
|
66937
|
+
if (id) {
|
|
66938
|
+
const subtask = state.subtasks.get(id);
|
|
66939
|
+
if (subtask) {
|
|
66940
|
+
if (subtask.status === "created")
|
|
66941
|
+
state.counts.created--;
|
|
66942
|
+
else if (subtask.status === "spawned")
|
|
66943
|
+
state.counts.spawned--;
|
|
66944
|
+
else if (subtask.status === "in_progress")
|
|
66945
|
+
state.counts.inProgress--;
|
|
66946
|
+
else if (subtask.status === "completed")
|
|
66947
|
+
state.counts.completed--;
|
|
66948
|
+
subtask.status = "closed";
|
|
66949
|
+
state.counts.closed++;
|
|
66950
|
+
}
|
|
66951
|
+
if (state.epic && state.epic.id === id) {
|
|
66952
|
+
state.epic.status = "closed";
|
|
66953
|
+
}
|
|
66954
|
+
}
|
|
66955
|
+
break;
|
|
66956
|
+
}
|
|
66957
|
+
case "swarmmail_init": {
|
|
66958
|
+
try {
|
|
66959
|
+
const parsed = JSON.parse(event.output);
|
|
66960
|
+
if (parsed.agent_name) {
|
|
66961
|
+
state.coordinatorName = parsed.agent_name;
|
|
66962
|
+
}
|
|
66963
|
+
if (parsed.project_key) {
|
|
66964
|
+
state.projectPath = parsed.project_key;
|
|
66965
|
+
}
|
|
66966
|
+
} catch {}
|
|
66967
|
+
break;
|
|
66968
|
+
}
|
|
66969
|
+
}
|
|
66970
|
+
}
|
|
66971
|
+
state.isSwarm = hasEpic && hasSpawn;
|
|
66972
|
+
return state;
|
|
66973
|
+
}
|
|
66974
|
+
function parseEpicId(output) {
|
|
66975
|
+
try {
|
|
66976
|
+
const parsed = JSON.parse(output);
|
|
66977
|
+
return parsed.epic?.id || parsed.id;
|
|
66978
|
+
} catch {
|
|
66979
|
+
return;
|
|
66980
|
+
}
|
|
66981
|
+
}
|
|
66982
|
+
function parseSubtaskIds(output) {
|
|
66983
|
+
try {
|
|
66984
|
+
const parsed = JSON.parse(output);
|
|
66985
|
+
const subtasks = parsed.subtasks || parsed.epic?.subtasks || [];
|
|
66986
|
+
return subtasks.map((s) => {
|
|
66987
|
+
if (typeof s === "object" && s !== null && "id" in s) {
|
|
66988
|
+
return s.id;
|
|
66989
|
+
}
|
|
66990
|
+
return;
|
|
66991
|
+
}).filter((id) => typeof id === "string");
|
|
66992
|
+
} catch {
|
|
66993
|
+
return [];
|
|
66994
|
+
}
|
|
66995
|
+
}
|
|
66996
|
+
function hasSwarmSignature(events) {
|
|
66997
|
+
let hasEpic = false;
|
|
66998
|
+
let hasSpawn = false;
|
|
66999
|
+
for (const event of events) {
|
|
67000
|
+
if (event.tool === "hive_create_epic") {
|
|
67001
|
+
hasEpic = true;
|
|
67002
|
+
} else if (event.tool === "swarm_spawn_subtask") {
|
|
67003
|
+
hasSpawn = true;
|
|
67004
|
+
}
|
|
67005
|
+
if (hasEpic && hasSpawn) {
|
|
67006
|
+
return true;
|
|
67007
|
+
}
|
|
67008
|
+
}
|
|
67009
|
+
return false;
|
|
67010
|
+
}
|
|
67011
|
+
function isSwarmActive(projection) {
|
|
67012
|
+
if (!projection.isSwarm) {
|
|
67013
|
+
return false;
|
|
67014
|
+
}
|
|
67015
|
+
return projection.counts.created > 0 || projection.counts.spawned > 0 || projection.counts.inProgress > 0 || projection.counts.completed > 0;
|
|
67016
|
+
}
|
|
67017
|
+
function getSwarmSummary(projection) {
|
|
67018
|
+
if (!projection.isSwarm) {
|
|
67019
|
+
return "No swarm detected";
|
|
67020
|
+
}
|
|
67021
|
+
const { counts, epic } = projection;
|
|
67022
|
+
const parts2 = [];
|
|
67023
|
+
if (epic) {
|
|
67024
|
+
parts2.push(`Epic: ${epic.id} - ${epic.title} [${epic.status}]`);
|
|
67025
|
+
}
|
|
67026
|
+
parts2.push(`Subtasks: ${counts.total} total (${counts.spawned} spawned, ${counts.inProgress} in_progress, ${counts.completed} completed, ${counts.closed} closed)`);
|
|
67027
|
+
if (isSwarmActive(projection)) {
|
|
67028
|
+
parts2.push("Status: ACTIVE - has pending work");
|
|
67029
|
+
} else {
|
|
67030
|
+
parts2.push("Status: COMPLETE - all work closed");
|
|
67031
|
+
}
|
|
67032
|
+
return parts2.join(`
|
|
67033
|
+
`);
|
|
67034
|
+
}
|
|
67035
|
+
|
|
67036
|
+
// src/index.ts
|
|
66533
67037
|
var SwarmPlugin = async (input) => {
|
|
66534
67038
|
const { $, directory, client } = input;
|
|
66535
67039
|
setHiveWorkingDirectory(directory);
|
|
@@ -66722,6 +67226,7 @@ export {
|
|
|
66722
67226
|
recordPatternSkipped,
|
|
66723
67227
|
recordPatternExtracted,
|
|
66724
67228
|
recordEvalRun,
|
|
67229
|
+
projectSwarmState,
|
|
66725
67230
|
parseFrontmatter,
|
|
66726
67231
|
migrateBeadsToHive,
|
|
66727
67232
|
mergeHistoricBeads,
|
|
@@ -66732,6 +67237,7 @@ export {
|
|
|
66732
67237
|
logger,
|
|
66733
67238
|
listSkills,
|
|
66734
67239
|
isToolAvailable,
|
|
67240
|
+
isSwarmActive,
|
|
66735
67241
|
isStateTransitionEvent,
|
|
66736
67242
|
isSemanticMemoryAvailable,
|
|
66737
67243
|
isProjectNotFoundError,
|
|
@@ -66754,9 +67260,11 @@ export {
|
|
|
66754
67260
|
hive_close,
|
|
66755
67261
|
hive_cells,
|
|
66756
67262
|
hiveTools,
|
|
67263
|
+
hasSwarmSignature,
|
|
66757
67264
|
guardrailOutput,
|
|
66758
67265
|
groupByTransition,
|
|
66759
67266
|
getToolAvailability,
|
|
67267
|
+
getSwarmSummary,
|
|
66760
67268
|
getSwarmMailProjectDirectory,
|
|
66761
67269
|
getStorage,
|
|
66762
67270
|
getStatusChanges,
|