opencode-swarm-plugin 0.44.1 → 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 +3 -3
- 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 +14834 -0
- package/dist/index.d.ts +50 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +640 -27
- package/dist/plugin.js +395 -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 +39605 -0
- 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-validation.d.ts +127 -0
- package/dist/swarm-validation.d.ts.map +1 -0
- package/dist/swarm.d.ts +4 -2
- package/dist/swarm.d.ts.map +1 -1
- package/dist/validators/index.d.ts +7 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/schema-validator.d.ts +58 -0
- package/dist/validators/schema-validator.d.ts.map +1 -0
- 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 +6 -3
package/dist/index.js
CHANGED
|
@@ -13177,6 +13177,74 @@ var init_eval_capture = __esm(() => {
|
|
|
13177
13177
|
inProgressRecords = new Map;
|
|
13178
13178
|
});
|
|
13179
13179
|
|
|
13180
|
+
// src/swarm-validation.ts
|
|
13181
|
+
var exports_swarm_validation = {};
|
|
13182
|
+
__export(exports_swarm_validation, {
|
|
13183
|
+
runPostSwarmValidation: () => runPostSwarmValidation,
|
|
13184
|
+
reportIssue: () => reportIssue,
|
|
13185
|
+
ValidationIssueSeverity: () => ValidationIssueSeverity,
|
|
13186
|
+
ValidationIssueSchema: () => ValidationIssueSchema,
|
|
13187
|
+
ValidationIssueCategory: () => ValidationIssueCategory
|
|
13188
|
+
});
|
|
13189
|
+
async function runPostSwarmValidation(ctx, events) {
|
|
13190
|
+
const startTime = Date.now();
|
|
13191
|
+
const issues = [];
|
|
13192
|
+
await ctx.emit({
|
|
13193
|
+
type: "validation_started",
|
|
13194
|
+
project_key: ctx.project_key,
|
|
13195
|
+
timestamp: startTime,
|
|
13196
|
+
epic_id: ctx.epic_id,
|
|
13197
|
+
swarm_id: ctx.swarm_id,
|
|
13198
|
+
started_at: ctx.started_at.getTime()
|
|
13199
|
+
});
|
|
13200
|
+
const duration_ms = Date.now() - startTime;
|
|
13201
|
+
await ctx.emit({
|
|
13202
|
+
type: "validation_completed",
|
|
13203
|
+
project_key: ctx.project_key,
|
|
13204
|
+
timestamp: Date.now(),
|
|
13205
|
+
epic_id: ctx.epic_id,
|
|
13206
|
+
swarm_id: ctx.swarm_id,
|
|
13207
|
+
passed: issues.length === 0,
|
|
13208
|
+
issue_count: issues.length,
|
|
13209
|
+
duration_ms
|
|
13210
|
+
});
|
|
13211
|
+
return { passed: issues.length === 0, issues };
|
|
13212
|
+
}
|
|
13213
|
+
async function reportIssue(ctx, issue2) {
|
|
13214
|
+
await ctx.emit({
|
|
13215
|
+
type: "validation_issue",
|
|
13216
|
+
project_key: ctx.project_key,
|
|
13217
|
+
timestamp: new Date().toISOString(),
|
|
13218
|
+
epic_id: ctx.epic_id,
|
|
13219
|
+
severity: issue2.severity,
|
|
13220
|
+
category: issue2.category,
|
|
13221
|
+
message: issue2.message,
|
|
13222
|
+
location: issue2.location
|
|
13223
|
+
});
|
|
13224
|
+
}
|
|
13225
|
+
var ValidationIssueSeverity, ValidationIssueCategory, ValidationIssueSchema;
|
|
13226
|
+
var init_swarm_validation = __esm(() => {
|
|
13227
|
+
init_zod();
|
|
13228
|
+
ValidationIssueSeverity = exports_external.enum(["error", "warning", "info"]);
|
|
13229
|
+
ValidationIssueCategory = exports_external.enum([
|
|
13230
|
+
"schema_mismatch",
|
|
13231
|
+
"missing_event",
|
|
13232
|
+
"undefined_value",
|
|
13233
|
+
"dashboard_render",
|
|
13234
|
+
"websocket_delivery"
|
|
13235
|
+
]);
|
|
13236
|
+
ValidationIssueSchema = exports_external.object({
|
|
13237
|
+
severity: ValidationIssueSeverity,
|
|
13238
|
+
category: ValidationIssueCategory,
|
|
13239
|
+
message: exports_external.string(),
|
|
13240
|
+
location: exports_external.object({
|
|
13241
|
+
event_type: exports_external.string().optional(),
|
|
13242
|
+
field: exports_external.string().optional(),
|
|
13243
|
+
component: exports_external.string().optional()
|
|
13244
|
+
}).optional()
|
|
13245
|
+
});
|
|
13246
|
+
});
|
|
13247
|
+
|
|
13180
13248
|
// ../../node_modules/.bun/@ioredis+commands@1.4.0/node_modules/@ioredis/commands/built/commands.json
|
|
13181
13249
|
var require_commands = __commonJS((exports, module) => {
|
|
13182
13250
|
module.exports = {
|
|
@@ -22492,7 +22560,7 @@ __export(exports_swarm_strategies, {
|
|
|
22492
22560
|
NEGATIVE_MARKERS: () => NEGATIVE_MARKERS,
|
|
22493
22561
|
DecompositionStrategySchema: () => DecompositionStrategySchema
|
|
22494
22562
|
});
|
|
22495
|
-
function selectStrategy(task) {
|
|
22563
|
+
async function selectStrategy(task, projectKey) {
|
|
22496
22564
|
const taskLower = task.toLowerCase();
|
|
22497
22565
|
const scores = {
|
|
22498
22566
|
"file-based": 0,
|
|
@@ -22520,7 +22588,8 @@ function selectStrategy(task) {
|
|
|
22520
22588
|
const [winner, winnerScore] = entries[0];
|
|
22521
22589
|
const [, runnerUpScore] = entries[1] || [null, 0];
|
|
22522
22590
|
const totalScore = entries.reduce((sum, [, score]) => sum + score, 0);
|
|
22523
|
-
|
|
22591
|
+
let confidence = totalScore > 0 ? Math.min(0.95, 0.5 + (winnerScore - runnerUpScore) / totalScore) : 0.5;
|
|
22592
|
+
const finalStrategy = winnerScore === 0 ? "feature-based" : winner;
|
|
22524
22593
|
let reasoning;
|
|
22525
22594
|
if (winnerScore === 0) {
|
|
22526
22595
|
reasoning = `No strong keyword signals. Defaulting to feature-based as it's most versatile.`;
|
|
@@ -22528,12 +22597,73 @@ function selectStrategy(task) {
|
|
|
22528
22597
|
const matchedKeywords = STRATEGIES[winner].keywords.filter((k) => taskLower.includes(k));
|
|
22529
22598
|
reasoning = `Matched keywords: ${matchedKeywords.join(", ")}. ${STRATEGIES[winner].description}`;
|
|
22530
22599
|
}
|
|
22531
|
-
|
|
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
|
+
}
|
|
22532
22661
|
return {
|
|
22533
22662
|
strategy: finalStrategy,
|
|
22534
22663
|
confidence,
|
|
22535
22664
|
reasoning,
|
|
22536
|
-
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
|
|
22537
22667
|
};
|
|
22538
22668
|
}
|
|
22539
22669
|
function formatStrategyGuidelines(strategy) {
|
|
@@ -22742,13 +22872,14 @@ var init_swarm_strategies = __esm(() => {
|
|
|
22742
22872
|
}
|
|
22743
22873
|
};
|
|
22744
22874
|
swarm_select_strategy = tool({
|
|
22745
|
-
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",
|
|
22746
22876
|
args: {
|
|
22747
22877
|
task: tool.schema.string().min(1).describe("Task description to analyze"),
|
|
22748
|
-
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")
|
|
22749
22880
|
},
|
|
22750
22881
|
async execute(args) {
|
|
22751
|
-
const result = selectStrategy(args.task);
|
|
22882
|
+
const result = await selectStrategy(args.task, args.projectKey);
|
|
22752
22883
|
let enhancedReasoning = result.reasoning;
|
|
22753
22884
|
if (args.codebase_context) {
|
|
22754
22885
|
enhancedReasoning += `
|
|
@@ -22766,7 +22897,8 @@ Codebase context considered: ${args.codebase_context.slice(0, 200)}...`;
|
|
|
22766
22897
|
strategy: alt.strategy,
|
|
22767
22898
|
description: STRATEGIES[alt.strategy].description,
|
|
22768
22899
|
score: alt.score
|
|
22769
|
-
}))
|
|
22900
|
+
})),
|
|
22901
|
+
precedent: result.precedent
|
|
22770
22902
|
}, null, 2);
|
|
22771
22903
|
}
|
|
22772
22904
|
});
|
|
@@ -38949,7 +39081,8 @@ import {
|
|
|
38949
39081
|
importFromJSONL,
|
|
38950
39082
|
syncMemories,
|
|
38951
39083
|
getSwarmMailLibSQL,
|
|
38952
|
-
resolvePartialId
|
|
39084
|
+
resolvePartialId,
|
|
39085
|
+
findCellsByPartialId
|
|
38953
39086
|
} from "swarm-mail";
|
|
38954
39087
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
38955
39088
|
import { join as join2 } from "node:path";
|
|
@@ -40216,6 +40349,37 @@ var hive_close = tool({
|
|
|
40216
40349
|
total_files_touched: totalFilesTouched
|
|
40217
40350
|
});
|
|
40218
40351
|
await appendEvent2(swarmCompletedEvent, projectKey);
|
|
40352
|
+
try {
|
|
40353
|
+
const { runPostSwarmValidation: runPostSwarmValidation2 } = await Promise.resolve().then(() => (init_swarm_validation(), exports_swarm_validation));
|
|
40354
|
+
const { readEvents } = await import("swarm-mail");
|
|
40355
|
+
const swarmEvents = await readEvents({
|
|
40356
|
+
projectKey,
|
|
40357
|
+
types: [
|
|
40358
|
+
"swarm_started",
|
|
40359
|
+
"swarm_completed",
|
|
40360
|
+
"worker_spawned",
|
|
40361
|
+
"subtask_outcome",
|
|
40362
|
+
"decomposition_generated"
|
|
40363
|
+
]
|
|
40364
|
+
}, projectKey);
|
|
40365
|
+
runPostSwarmValidation2({
|
|
40366
|
+
project_key: projectKey,
|
|
40367
|
+
epic_id: cellId,
|
|
40368
|
+
swarm_id: cellId,
|
|
40369
|
+
started_at: new Date,
|
|
40370
|
+
emit: async (event) => {
|
|
40371
|
+
await appendEvent2(event, projectKey);
|
|
40372
|
+
}
|
|
40373
|
+
}, swarmEvents).then((result) => {
|
|
40374
|
+
if (!result.passed) {
|
|
40375
|
+
console.warn(`[Validation] Found ${result.issues.length} issues in swarm ${cellId}`);
|
|
40376
|
+
}
|
|
40377
|
+
}).catch((err) => {
|
|
40378
|
+
console.error(`[Validation] Failed:`, err);
|
|
40379
|
+
});
|
|
40380
|
+
} catch (error45) {
|
|
40381
|
+
console.warn("[hive_close] Validation hook failed (non-fatal):", error45);
|
|
40382
|
+
}
|
|
40219
40383
|
} catch (error45) {
|
|
40220
40384
|
console.warn("[hive_close] Failed to emit SwarmCompletedEvent:", error45);
|
|
40221
40385
|
}
|
|
@@ -40309,13 +40473,12 @@ PREFER THIS OVER hive_query when you need to:
|
|
|
40309
40473
|
const adapter = await getHiveAdapter(projectKey);
|
|
40310
40474
|
try {
|
|
40311
40475
|
if (args.id) {
|
|
40312
|
-
const
|
|
40313
|
-
|
|
40314
|
-
if (!cell) {
|
|
40476
|
+
const matchingCells = await findCellsByPartialId(adapter, projectKey, args.id);
|
|
40477
|
+
if (matchingCells.length === 0) {
|
|
40315
40478
|
throw new HiveError(`No cell found matching ID '${args.id}'`, "hive_cells");
|
|
40316
40479
|
}
|
|
40317
|
-
const formatted2 = formatCellForOutput(
|
|
40318
|
-
return JSON.stringify(
|
|
40480
|
+
const formatted2 = matchingCells.map((c) => formatCellForOutput(c));
|
|
40481
|
+
return JSON.stringify(formatted2, null, 2);
|
|
40319
40482
|
}
|
|
40320
40483
|
if (args.ready) {
|
|
40321
40484
|
const ready = await adapter.getNextReadyCell(projectKey);
|
|
@@ -40334,10 +40497,10 @@ PREFER THIS OVER hive_query when you need to:
|
|
|
40334
40497
|
const formatted = cells.map((c) => formatCellForOutput(c));
|
|
40335
40498
|
return JSON.stringify(formatted, null, 2);
|
|
40336
40499
|
} catch (error45) {
|
|
40337
|
-
|
|
40338
|
-
|
|
40339
|
-
throw new HiveError(`Ambiguous ID '${args.id}': multiple cells match. Please provide more characters.`, "hive_cells");
|
|
40500
|
+
if (error45 instanceof HiveError) {
|
|
40501
|
+
throw error45;
|
|
40340
40502
|
}
|
|
40503
|
+
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
40341
40504
|
if (message.includes("Bead not found") || message.includes("Cell not found")) {
|
|
40342
40505
|
throw new HiveError(`No cell found matching ID '${args.id || "unknown"}'`, "hive_cells");
|
|
40343
40506
|
}
|
|
@@ -42784,6 +42947,139 @@ init_dist();
|
|
|
42784
42947
|
init_zod();
|
|
42785
42948
|
init_swarm_strategies();
|
|
42786
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
|
|
42787
43083
|
var DECOMPOSITION_PROMPT = `You are decomposing a task into parallelizable subtasks for a swarm of agents.
|
|
42788
43084
|
|
|
42789
43085
|
## Task
|
|
@@ -43215,7 +43511,7 @@ var swarm_delegate_planning = tool({
|
|
|
43215
43511
|
selectedStrategy = args.strategy;
|
|
43216
43512
|
strategyReasoning = `User-specified strategy: ${selectedStrategy}`;
|
|
43217
43513
|
} else {
|
|
43218
|
-
const selection = selectStrategy2(args.task);
|
|
43514
|
+
const selection = await selectStrategy2(args.task);
|
|
43219
43515
|
selectedStrategy = selection.strategy;
|
|
43220
43516
|
strategyReasoning = selection.reasoning;
|
|
43221
43517
|
}
|
|
@@ -43257,6 +43553,27 @@ var swarm_delegate_planning = tool({
|
|
|
43257
43553
|
} else {
|
|
43258
43554
|
cassResultInfo = { queried: false, reason: "disabled" };
|
|
43259
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
|
+
}
|
|
43260
43577
|
let skillsContext = "";
|
|
43261
43578
|
let skillsInfo = {
|
|
43262
43579
|
included: false
|
|
@@ -43394,7 +43711,7 @@ Limit: ${memoryQuery.limit}`;
|
|
|
43394
43711
|
}
|
|
43395
43712
|
} catch (error45) {}
|
|
43396
43713
|
if (mode === "fast") {
|
|
43397
|
-
const strategyResult = selectStrategy2(args.task);
|
|
43714
|
+
const strategyResult = await selectStrategy2(args.task);
|
|
43398
43715
|
const guidelines = formatStrategyGuidelines2(strategyResult.strategy);
|
|
43399
43716
|
const output = {
|
|
43400
43717
|
mode: "fast",
|
|
@@ -43413,7 +43730,7 @@ ${guidelines}`
|
|
|
43413
43730
|
return JSON.stringify(output, null, 2);
|
|
43414
43731
|
}
|
|
43415
43732
|
if (mode === "auto") {
|
|
43416
|
-
const strategyResult = selectStrategy2(args.task);
|
|
43733
|
+
const strategyResult = await selectStrategy2(args.task);
|
|
43417
43734
|
const output = {
|
|
43418
43735
|
mode: "auto",
|
|
43419
43736
|
phase: "ready",
|
|
@@ -43508,7 +43825,7 @@ ${guidelines}`
|
|
|
43508
43825
|
return JSON.stringify(output, null, 2);
|
|
43509
43826
|
}
|
|
43510
43827
|
if (currentPhase === "alternatives") {
|
|
43511
|
-
const strategyResult = selectStrategy2(args.task);
|
|
43828
|
+
const strategyResult = await selectStrategy2(args.task);
|
|
43512
43829
|
const alternatives = [];
|
|
43513
43830
|
alternatives.push({
|
|
43514
43831
|
name: strategyResult.strategy,
|
|
@@ -43535,7 +43852,7 @@ ${guidelines}`
|
|
|
43535
43852
|
return JSON.stringify(output, null, 2);
|
|
43536
43853
|
}
|
|
43537
43854
|
if (currentPhase === "recommendation") {
|
|
43538
|
-
const strategyResult = selectStrategy2(args.task);
|
|
43855
|
+
const strategyResult = await selectStrategy2(args.task);
|
|
43539
43856
|
const guidelines = formatStrategyGuidelines2(strategyResult.strategy);
|
|
43540
43857
|
const output = {
|
|
43541
43858
|
mode: "socratic",
|
|
@@ -45606,6 +45923,22 @@ var swarm_review_feedback = tool({
|
|
|
45606
45923
|
} catch (error45) {
|
|
45607
45924
|
console.warn("[swarm_review_feedback] Failed to capture review_completed:", error45);
|
|
45608
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
|
+
}
|
|
45609
45942
|
try {
|
|
45610
45943
|
const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
|
|
45611
45944
|
const attempt = getReviewStatus(args.task_id).attempt_count || 1;
|
|
@@ -45660,6 +45993,23 @@ You may now complete the task with \`swarm_complete\`.`,
|
|
|
45660
45993
|
} catch (error45) {
|
|
45661
45994
|
console.warn("[swarm_review_feedback] Failed to capture review_completed:", error45);
|
|
45662
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
|
+
}
|
|
45663
46013
|
try {
|
|
45664
46014
|
const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
|
|
45665
46015
|
const status = remaining <= 0 ? "blocked" : "needs_changes";
|
|
@@ -61840,9 +62190,9 @@ async function getPromptInsights(options2) {
|
|
|
61840
62190
|
}
|
|
61841
62191
|
async function getCoordinatorInsights(project_key) {
|
|
61842
62192
|
try {
|
|
61843
|
-
const { createLibSQLAdapter, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
|
|
62193
|
+
const { createLibSQLAdapter: createLibSQLAdapter2, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
|
|
61844
62194
|
const { getStrategyInsights: getStrategyInsights2, getPatternInsights: getPatternInsights2, formatInsightsForPrompt: formatInsightsForPrompt2 } = await Promise.resolve().then(() => (init_swarm_insights(), exports_swarm_insights));
|
|
61845
|
-
const dbAdapter = await
|
|
62195
|
+
const dbAdapter = await createLibSQLAdapter2({ url: "file:./.swarm-mail/streams.db" });
|
|
61846
62196
|
const adapter = createSwarmMailAdapter2(dbAdapter, project_key || "default");
|
|
61847
62197
|
const [strategies, patterns] = await Promise.all([
|
|
61848
62198
|
getStrategyInsights2(adapter, ""),
|
|
@@ -61870,7 +62220,7 @@ ${formatted}
|
|
|
61870
62220
|
}
|
|
61871
62221
|
async function getWorkerInsights(files, domain2) {
|
|
61872
62222
|
try {
|
|
61873
|
-
const { createLibSQLAdapter, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
|
|
62223
|
+
const { createLibSQLAdapter: createLibSQLAdapter2, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
|
|
61874
62224
|
const { getFileInsights: getFileInsights2, formatInsightsForPrompt: formatInsightsForPrompt2 } = await Promise.resolve().then(() => (init_swarm_insights(), exports_swarm_insights));
|
|
61875
62225
|
const memoryAdapter = await getMemoryAdapter();
|
|
61876
62226
|
let query = "";
|
|
@@ -61887,7 +62237,7 @@ async function getWorkerInsights(files, domain2) {
|
|
|
61887
62237
|
if (!files || files.length === 0)
|
|
61888
62238
|
return [];
|
|
61889
62239
|
try {
|
|
61890
|
-
const dbAdapter = await
|
|
62240
|
+
const dbAdapter = await createLibSQLAdapter2({ url: "file:./.swarm-mail/streams.db" });
|
|
61891
62241
|
const swarmMail = createSwarmMailAdapter2(dbAdapter, "default");
|
|
61892
62242
|
return await getFileInsights2(swarmMail, files);
|
|
61893
62243
|
} catch (e) {
|
|
@@ -62096,6 +62446,23 @@ var swarm_spawn_subtask = tool({
|
|
|
62096
62446
|
} catch (error45) {
|
|
62097
62447
|
console.warn("[swarm_spawn_subtask] Failed to capture worker_spawned:", error45);
|
|
62098
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
|
+
}
|
|
62099
62466
|
if (args2.project_path) {
|
|
62100
62467
|
try {
|
|
62101
62468
|
const { createEvent: createEvent3, appendEvent: appendEvent3 } = await import("swarm-mail");
|
|
@@ -62325,7 +62692,7 @@ var swarm_plan_prompt = tool({
|
|
|
62325
62692
|
selectedStrategy = args2.strategy;
|
|
62326
62693
|
strategyReasoning = `User-specified strategy: ${selectedStrategy}`;
|
|
62327
62694
|
} else {
|
|
62328
|
-
const selection = selectStrategy2(args2.task);
|
|
62695
|
+
const selection = await selectStrategy2(args2.task);
|
|
62329
62696
|
selectedStrategy = selection.strategy;
|
|
62330
62697
|
strategyReasoning = selection.reasoning;
|
|
62331
62698
|
}
|
|
@@ -66430,6 +66797,243 @@ async function resetStorage() {
|
|
|
66430
66797
|
|
|
66431
66798
|
// src/index.ts
|
|
66432
66799
|
init_skills();
|
|
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
|
|
66433
67037
|
var SwarmPlugin = async (input) => {
|
|
66434
67038
|
const { $, directory, client } = input;
|
|
66435
67039
|
setHiveWorkingDirectory(directory);
|
|
@@ -66608,18 +67212,21 @@ export {
|
|
|
66608
67212
|
setAgentMailProjectDirectory,
|
|
66609
67213
|
selectStrategy,
|
|
66610
67214
|
scanSessionMessages,
|
|
67215
|
+
runPostSwarmValidation,
|
|
66611
67216
|
resetToolCache,
|
|
66612
67217
|
resetStorage,
|
|
66613
67218
|
resetMemoryCache,
|
|
66614
67219
|
resetMandateStorage,
|
|
66615
67220
|
researchTools,
|
|
66616
67221
|
requireTool,
|
|
67222
|
+
reportIssue,
|
|
66617
67223
|
repoCrawlTools,
|
|
66618
67224
|
recordPhaseStart,
|
|
66619
67225
|
recordPhaseComplete,
|
|
66620
67226
|
recordPatternSkipped,
|
|
66621
67227
|
recordPatternExtracted,
|
|
66622
67228
|
recordEvalRun,
|
|
67229
|
+
projectSwarmState,
|
|
66623
67230
|
parseFrontmatter,
|
|
66624
67231
|
migrateBeadsToHive,
|
|
66625
67232
|
mergeHistoricBeads,
|
|
@@ -66630,6 +67237,7 @@ export {
|
|
|
66630
67237
|
logger,
|
|
66631
67238
|
listSkills,
|
|
66632
67239
|
isToolAvailable,
|
|
67240
|
+
isSwarmActive,
|
|
66633
67241
|
isStateTransitionEvent,
|
|
66634
67242
|
isSemanticMemoryAvailable,
|
|
66635
67243
|
isProjectNotFoundError,
|
|
@@ -66652,9 +67260,11 @@ export {
|
|
|
66652
67260
|
hive_close,
|
|
66653
67261
|
hive_cells,
|
|
66654
67262
|
hiveTools,
|
|
67263
|
+
hasSwarmSignature,
|
|
66655
67264
|
guardrailOutput,
|
|
66656
67265
|
groupByTransition,
|
|
66657
67266
|
getToolAvailability,
|
|
67267
|
+
getSwarmSummary,
|
|
66658
67268
|
getSwarmMailProjectDirectory,
|
|
66659
67269
|
getStorage,
|
|
66660
67270
|
getStatusChanges,
|
|
@@ -66729,6 +67339,9 @@ export {
|
|
|
66729
67339
|
VoteTypeSchema,
|
|
66730
67340
|
VoteSchema,
|
|
66731
67341
|
ValidationResultSchema,
|
|
67342
|
+
ValidationIssueSeverity,
|
|
67343
|
+
ValidationIssueSchema,
|
|
67344
|
+
ValidationIssueCategory,
|
|
66732
67345
|
VARIANCE_THRESHOLD,
|
|
66733
67346
|
UpdateSwarmContextArgsSchema,
|
|
66734
67347
|
TaskDecompositionSchema,
|