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.
Files changed (48) hide show
  1. package/README.md +277 -54
  2. package/bin/swarm.ts +3 -3
  3. package/dist/decision-trace-integration.d.ts +204 -0
  4. package/dist/decision-trace-integration.d.ts.map +1 -0
  5. package/dist/hive.d.ts.map +1 -1
  6. package/dist/hive.js +14834 -0
  7. package/dist/index.d.ts +50 -2
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +640 -27
  10. package/dist/plugin.js +395 -27
  11. package/dist/query-tools.d.ts +20 -12
  12. package/dist/query-tools.d.ts.map +1 -1
  13. package/dist/swarm-decompose.d.ts +4 -4
  14. package/dist/swarm-decompose.d.ts.map +1 -1
  15. package/dist/swarm-prompts.d.ts.map +1 -1
  16. package/dist/swarm-prompts.js +39605 -0
  17. package/dist/swarm-review.d.ts.map +1 -1
  18. package/dist/swarm-signature.d.ts +106 -0
  19. package/dist/swarm-signature.d.ts.map +1 -0
  20. package/dist/swarm-strategies.d.ts +16 -3
  21. package/dist/swarm-strategies.d.ts.map +1 -1
  22. package/dist/swarm-validation.d.ts +127 -0
  23. package/dist/swarm-validation.d.ts.map +1 -0
  24. package/dist/swarm.d.ts +4 -2
  25. package/dist/swarm.d.ts.map +1 -1
  26. package/dist/validators/index.d.ts +7 -0
  27. package/dist/validators/index.d.ts.map +1 -0
  28. package/dist/validators/schema-validator.d.ts +58 -0
  29. package/dist/validators/schema-validator.d.ts.map +1 -0
  30. package/examples/commands/swarm.md +745 -0
  31. package/examples/plugin-wrapper-template.ts +2611 -0
  32. package/examples/skills/hive-workflow/SKILL.md +212 -0
  33. package/examples/skills/skill-creator/SKILL.md +223 -0
  34. package/examples/skills/swarm-coordination/SKILL.md +292 -0
  35. package/global-skills/cli-builder/SKILL.md +344 -0
  36. package/global-skills/cli-builder/references/advanced-patterns.md +244 -0
  37. package/global-skills/learning-systems/SKILL.md +644 -0
  38. package/global-skills/skill-creator/LICENSE.txt +202 -0
  39. package/global-skills/skill-creator/SKILL.md +352 -0
  40. package/global-skills/skill-creator/references/output-patterns.md +82 -0
  41. package/global-skills/skill-creator/references/workflows.md +28 -0
  42. package/global-skills/swarm-coordination/SKILL.md +995 -0
  43. package/global-skills/swarm-coordination/references/coordinator-patterns.md +235 -0
  44. package/global-skills/swarm-coordination/references/strategies.md +138 -0
  45. package/global-skills/system-design/SKILL.md +213 -0
  46. package/global-skills/testing-patterns/SKILL.md +430 -0
  47. package/global-skills/testing-patterns/references/dependency-breaking-catalog.md +586 -0
  48. package/package.json +6 -3
package/dist/plugin.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
- const confidence = totalScore > 0 ? Math.min(0.95, 0.5 + (winnerScore - runnerUpScore) / totalScore) : 0.5;
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
- const finalStrategy = winnerScore === 0 ? "feature-based" : winner;
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";
@@ -39972,6 +40105,37 @@ var hive_close = tool({
39972
40105
  total_files_touched: totalFilesTouched
39973
40106
  });
39974
40107
  await appendEvent2(swarmCompletedEvent, projectKey);
40108
+ try {
40109
+ const { runPostSwarmValidation: runPostSwarmValidation2 } = await Promise.resolve().then(() => (init_swarm_validation(), exports_swarm_validation));
40110
+ const { readEvents } = await import("swarm-mail");
40111
+ const swarmEvents = await readEvents({
40112
+ projectKey,
40113
+ types: [
40114
+ "swarm_started",
40115
+ "swarm_completed",
40116
+ "worker_spawned",
40117
+ "subtask_outcome",
40118
+ "decomposition_generated"
40119
+ ]
40120
+ }, projectKey);
40121
+ runPostSwarmValidation2({
40122
+ project_key: projectKey,
40123
+ epic_id: cellId,
40124
+ swarm_id: cellId,
40125
+ started_at: new Date,
40126
+ emit: async (event) => {
40127
+ await appendEvent2(event, projectKey);
40128
+ }
40129
+ }, swarmEvents).then((result) => {
40130
+ if (!result.passed) {
40131
+ console.warn(`[Validation] Found ${result.issues.length} issues in swarm ${cellId}`);
40132
+ }
40133
+ }).catch((err) => {
40134
+ console.error(`[Validation] Failed:`, err);
40135
+ });
40136
+ } catch (error45) {
40137
+ console.warn("[hive_close] Validation hook failed (non-fatal):", error45);
40138
+ }
39975
40139
  } catch (error45) {
39976
40140
  console.warn("[hive_close] Failed to emit SwarmCompletedEvent:", error45);
39977
40141
  }
@@ -40065,13 +40229,12 @@ PREFER THIS OVER hive_query when you need to:
40065
40229
  const adapter = await getHiveAdapter(projectKey);
40066
40230
  try {
40067
40231
  if (args.id) {
40068
- const fullId = await resolvePartialId(adapter, projectKey, args.id) || args.id;
40069
- const cell = await adapter.getCell(projectKey, fullId);
40070
- if (!cell) {
40232
+ const matchingCells = await findCellsByPartialId(adapter, projectKey, args.id);
40233
+ if (matchingCells.length === 0) {
40071
40234
  throw new HiveError(`No cell found matching ID '${args.id}'`, "hive_cells");
40072
40235
  }
40073
- const formatted2 = formatCellForOutput(cell);
40074
- return JSON.stringify([formatted2], null, 2);
40236
+ const formatted2 = matchingCells.map((c) => formatCellForOutput(c));
40237
+ return JSON.stringify(formatted2, null, 2);
40075
40238
  }
40076
40239
  if (args.ready) {
40077
40240
  const ready = await adapter.getNextReadyCell(projectKey);
@@ -40090,10 +40253,10 @@ PREFER THIS OVER hive_query when you need to:
40090
40253
  const formatted = cells.map((c) => formatCellForOutput(c));
40091
40254
  return JSON.stringify(formatted, null, 2);
40092
40255
  } catch (error45) {
40093
- const message = error45 instanceof Error ? error45.message : String(error45);
40094
- if (message.includes("Ambiguous hash")) {
40095
- throw new HiveError(`Ambiguous ID '${args.id}': multiple cells match. Please provide more characters.`, "hive_cells");
40256
+ if (error45 instanceof HiveError) {
40257
+ throw error45;
40096
40258
  }
40259
+ const message = error45 instanceof Error ? error45.message : String(error45);
40097
40260
  if (message.includes("Bead not found") || message.includes("Cell not found")) {
40098
40261
  throw new HiveError(`No cell found matching ID '${args.id || "unknown"}'`, "hive_cells");
40099
40262
  }
@@ -42402,6 +42565,139 @@ init_dist();
42402
42565
  init_zod();
42403
42566
  init_swarm_strategies();
42404
42567
  init_eval_capture();
42568
+
42569
+ // src/decision-trace-integration.ts
42570
+ import {
42571
+ createDecisionTrace,
42572
+ createEntityLink
42573
+ } from "swarm-mail";
42574
+ import { createLibSQLAdapter } from "swarm-mail";
42575
+ import { getDatabasePath } from "swarm-mail";
42576
+ async function getTraceDb(projectPath) {
42577
+ const dbPath = getDatabasePath(projectPath);
42578
+ return createLibSQLAdapter({ url: `file:${dbPath}` });
42579
+ }
42580
+ function extractMemoryIds(precedentCited) {
42581
+ if (!precedentCited) {
42582
+ return [];
42583
+ }
42584
+ if (precedentCited.memoryIds && Array.isArray(precedentCited.memoryIds)) {
42585
+ return precedentCited.memoryIds;
42586
+ }
42587
+ if (precedentCited.memoryId) {
42588
+ return [precedentCited.memoryId];
42589
+ }
42590
+ return [];
42591
+ }
42592
+ async function traceStrategySelection(input) {
42593
+ try {
42594
+ const db = await getTraceDb(input.projectKey);
42595
+ const trace = await createDecisionTrace(db, {
42596
+ decision_type: "strategy_selection",
42597
+ epic_id: input.epicId,
42598
+ bead_id: input.beadId,
42599
+ agent_name: input.agentName,
42600
+ project_key: input.projectKey,
42601
+ decision: {
42602
+ strategy: input.strategy,
42603
+ confidence: input.confidence,
42604
+ task_preview: input.taskPreview
42605
+ },
42606
+ rationale: input.reasoning,
42607
+ inputs_gathered: input.inputsGathered,
42608
+ alternatives: input.alternatives,
42609
+ precedent_cited: input.precedentCited
42610
+ });
42611
+ const memoryIds = extractMemoryIds(input.precedentCited);
42612
+ for (const memoryId of memoryIds) {
42613
+ await createEntityLink(db, {
42614
+ source_decision_id: trace.id,
42615
+ target_entity_type: "memory",
42616
+ target_entity_id: memoryId,
42617
+ link_type: "cites_precedent",
42618
+ strength: input.precedentCited?.similarity ?? 1,
42619
+ context: "Cited as precedent for strategy selection"
42620
+ });
42621
+ }
42622
+ await db.close?.();
42623
+ return trace.id;
42624
+ } catch (error45) {
42625
+ console.warn("[decision-trace] Failed to trace strategy_selection:", error45);
42626
+ return "";
42627
+ }
42628
+ }
42629
+ async function traceWorkerSpawn(input) {
42630
+ try {
42631
+ const db = await getTraceDb(input.projectKey);
42632
+ const trace = await createDecisionTrace(db, {
42633
+ decision_type: "worker_spawn",
42634
+ epic_id: input.epicId,
42635
+ bead_id: input.beadId,
42636
+ agent_name: input.agentName,
42637
+ project_key: input.projectKey,
42638
+ decision: {
42639
+ worker: input.workerName || "worker",
42640
+ subtask_title: input.subtaskTitle,
42641
+ files: input.files,
42642
+ model: input.model,
42643
+ spawn_order: input.spawnOrder,
42644
+ is_parallel: input.isParallel
42645
+ },
42646
+ rationale: input.rationale || `Spawning worker for: ${input.subtaskTitle}`
42647
+ });
42648
+ for (const file2 of input.files) {
42649
+ await createEntityLink(db, {
42650
+ source_decision_id: trace.id,
42651
+ target_entity_type: "file",
42652
+ target_entity_id: file2,
42653
+ link_type: "assigns_file",
42654
+ strength: 1,
42655
+ context: `File assigned to worker ${input.workerName || "worker"}`
42656
+ });
42657
+ }
42658
+ await db.close?.();
42659
+ return trace.id;
42660
+ } catch (error45) {
42661
+ console.warn("[decision-trace] Failed to trace worker_spawn:", error45);
42662
+ return "";
42663
+ }
42664
+ }
42665
+ async function traceReviewDecision(input) {
42666
+ try {
42667
+ const db = await getTraceDb(input.projectKey);
42668
+ const trace = await createDecisionTrace(db, {
42669
+ decision_type: "review_decision",
42670
+ epic_id: input.epicId,
42671
+ bead_id: input.beadId,
42672
+ agent_name: input.agentName,
42673
+ project_key: input.projectKey,
42674
+ decision: {
42675
+ status: input.status,
42676
+ worker_id: input.workerId,
42677
+ issues_count: input.issues?.length || 0,
42678
+ attempt_number: input.attemptNumber,
42679
+ remaining_attempts: input.remainingAttempts
42680
+ },
42681
+ rationale: input.rationale || input.summary || `Review ${input.status}`,
42682
+ inputs_gathered: input.issues ? [{ source: "code_review", issues: input.issues }] : undefined
42683
+ });
42684
+ await createEntityLink(db, {
42685
+ source_decision_id: trace.id,
42686
+ target_entity_type: "agent",
42687
+ target_entity_id: input.workerId,
42688
+ link_type: "reviewed_work_by",
42689
+ strength: 1,
42690
+ context: `Review ${input.status} for ${input.workerId}`
42691
+ });
42692
+ await db.close?.();
42693
+ return trace.id;
42694
+ } catch (error45) {
42695
+ console.warn("[decision-trace] Failed to trace review_decision:", error45);
42696
+ return "";
42697
+ }
42698
+ }
42699
+
42700
+ // src/swarm-decompose.ts
42405
42701
  var DECOMPOSITION_PROMPT = `You are decomposing a task into parallelizable subtasks for a swarm of agents.
42406
42702
 
42407
42703
  ## Task
@@ -42833,7 +43129,7 @@ var swarm_delegate_planning = tool({
42833
43129
  selectedStrategy = args.strategy;
42834
43130
  strategyReasoning = `User-specified strategy: ${selectedStrategy}`;
42835
43131
  } else {
42836
- const selection = selectStrategy2(args.task);
43132
+ const selection = await selectStrategy2(args.task);
42837
43133
  selectedStrategy = selection.strategy;
42838
43134
  strategyReasoning = selection.reasoning;
42839
43135
  }
@@ -42875,6 +43171,27 @@ var swarm_delegate_planning = tool({
42875
43171
  } else {
42876
43172
  cassResultInfo = { queried: false, reason: "disabled" };
42877
43173
  }
43174
+ try {
43175
+ await traceStrategySelection({
43176
+ projectKey: args.context?.includes("/") ? args.context.split(" ")[0] : process.cwd(),
43177
+ agentName: "coordinator",
43178
+ epicId: undefined,
43179
+ strategy: selectedStrategy,
43180
+ reasoning: strategyReasoning,
43181
+ confidence: undefined,
43182
+ taskPreview: args.task.slice(0, 200),
43183
+ inputsGathered: cassResultInfo.queried ? [
43184
+ {
43185
+ source: "cass",
43186
+ query: args.task,
43187
+ results: cassResultInfo.results_found ?? 0
43188
+ }
43189
+ ] : undefined,
43190
+ alternatives: undefined
43191
+ });
43192
+ } catch (error45) {
43193
+ console.warn("[swarm_delegate_planning] Failed to trace strategy_selection:", error45);
43194
+ }
42878
43195
  let skillsContext = "";
42879
43196
  let skillsInfo = {
42880
43197
  included: false
@@ -42993,7 +43310,7 @@ Limit: ${memoryQuery.limit}`;
42993
43310
  }
42994
43311
  } catch (error45) {}
42995
43312
  if (mode === "fast") {
42996
- const strategyResult = selectStrategy2(args.task);
43313
+ const strategyResult = await selectStrategy2(args.task);
42997
43314
  const guidelines = formatStrategyGuidelines2(strategyResult.strategy);
42998
43315
  const output = {
42999
43316
  mode: "fast",
@@ -43012,7 +43329,7 @@ ${guidelines}`
43012
43329
  return JSON.stringify(output, null, 2);
43013
43330
  }
43014
43331
  if (mode === "auto") {
43015
- const strategyResult = selectStrategy2(args.task);
43332
+ const strategyResult = await selectStrategy2(args.task);
43016
43333
  const output = {
43017
43334
  mode: "auto",
43018
43335
  phase: "ready",
@@ -43107,7 +43424,7 @@ ${guidelines}`
43107
43424
  return JSON.stringify(output, null, 2);
43108
43425
  }
43109
43426
  if (currentPhase === "alternatives") {
43110
- const strategyResult = selectStrategy2(args.task);
43427
+ const strategyResult = await selectStrategy2(args.task);
43111
43428
  const alternatives = [];
43112
43429
  alternatives.push({
43113
43430
  name: strategyResult.strategy,
@@ -43134,7 +43451,7 @@ ${guidelines}`
43134
43451
  return JSON.stringify(output, null, 2);
43135
43452
  }
43136
43453
  if (currentPhase === "recommendation") {
43137
- const strategyResult = selectStrategy2(args.task);
43454
+ const strategyResult = await selectStrategy2(args.task);
43138
43455
  const guidelines = formatStrategyGuidelines2(strategyResult.strategy);
43139
43456
  const output = {
43140
43457
  mode: "socratic",
@@ -45205,6 +45522,22 @@ var swarm_review_feedback = tool({
45205
45522
  } catch (error45) {
45206
45523
  console.warn("[swarm_review_feedback] Failed to capture review_completed:", error45);
45207
45524
  }
45525
+ try {
45526
+ await traceReviewDecision({
45527
+ projectKey: args.project_key,
45528
+ agentName: "coordinator",
45529
+ epicId,
45530
+ beadId: args.task_id,
45531
+ workerId: args.worker_id,
45532
+ status: "approved",
45533
+ summary: args.summary,
45534
+ attemptNumber: 1,
45535
+ remainingAttempts: MAX_REVIEW_ATTEMPTS,
45536
+ rationale: args.summary || "Review approved"
45537
+ });
45538
+ } catch (error45) {
45539
+ console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
45540
+ }
45208
45541
  try {
45209
45542
  const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
45210
45543
  const attempt = getReviewStatus(args.task_id).attempt_count || 1;
@@ -45259,6 +45592,23 @@ You may now complete the task with \`swarm_complete\`.`,
45259
45592
  } catch (error45) {
45260
45593
  console.warn("[swarm_review_feedback] Failed to capture review_completed:", error45);
45261
45594
  }
45595
+ try {
45596
+ await traceReviewDecision({
45597
+ projectKey: args.project_key,
45598
+ agentName: "coordinator",
45599
+ epicId,
45600
+ beadId: args.task_id,
45601
+ workerId: args.worker_id,
45602
+ status: "needs_changes",
45603
+ summary: args.summary,
45604
+ issues: parsedIssues,
45605
+ attemptNumber,
45606
+ remainingAttempts: remaining,
45607
+ rationale: args.summary || `Review rejected: ${parsedIssues.length} issue(s) found`
45608
+ });
45609
+ } catch (error45) {
45610
+ console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
45611
+ }
45262
45612
  try {
45263
45613
  const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
45264
45614
  const status = remaining <= 0 ? "blocked" : "needs_changes";
@@ -61435,9 +61785,9 @@ async function getPromptInsights(options2) {
61435
61785
  }
61436
61786
  async function getCoordinatorInsights(project_key) {
61437
61787
  try {
61438
- const { createLibSQLAdapter, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
61788
+ const { createLibSQLAdapter: createLibSQLAdapter2, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
61439
61789
  const { getStrategyInsights: getStrategyInsights2, getPatternInsights: getPatternInsights2, formatInsightsForPrompt: formatInsightsForPrompt2 } = await Promise.resolve().then(() => (init_swarm_insights(), exports_swarm_insights));
61440
- const dbAdapter = await createLibSQLAdapter({ url: "file:./.swarm-mail/streams.db" });
61790
+ const dbAdapter = await createLibSQLAdapter2({ url: "file:./.swarm-mail/streams.db" });
61441
61791
  const adapter = createSwarmMailAdapter2(dbAdapter, project_key || "default");
61442
61792
  const [strategies, patterns] = await Promise.all([
61443
61793
  getStrategyInsights2(adapter, ""),
@@ -61465,7 +61815,7 @@ ${formatted}
61465
61815
  }
61466
61816
  async function getWorkerInsights(files, domain2) {
61467
61817
  try {
61468
- const { createLibSQLAdapter, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
61818
+ const { createLibSQLAdapter: createLibSQLAdapter2, createSwarmMailAdapter: createSwarmMailAdapter2 } = await import("swarm-mail");
61469
61819
  const { getFileInsights: getFileInsights2, formatInsightsForPrompt: formatInsightsForPrompt2 } = await Promise.resolve().then(() => (init_swarm_insights(), exports_swarm_insights));
61470
61820
  const memoryAdapter = await getMemoryAdapter();
61471
61821
  let query = "";
@@ -61482,7 +61832,7 @@ async function getWorkerInsights(files, domain2) {
61482
61832
  if (!files || files.length === 0)
61483
61833
  return [];
61484
61834
  try {
61485
- const dbAdapter = await createLibSQLAdapter({ url: "file:./.swarm-mail/streams.db" });
61835
+ const dbAdapter = await createLibSQLAdapter2({ url: "file:./.swarm-mail/streams.db" });
61486
61836
  const swarmMail = createSwarmMailAdapter2(dbAdapter, "default");
61487
61837
  return await getFileInsights2(swarmMail, files);
61488
61838
  } catch (e) {
@@ -61691,6 +62041,23 @@ var swarm_spawn_subtask = tool({
61691
62041
  } catch (error45) {
61692
62042
  console.warn("[swarm_spawn_subtask] Failed to capture worker_spawned:", error45);
61693
62043
  }
62044
+ try {
62045
+ await traceWorkerSpawn({
62046
+ projectKey: args2.project_path || process.cwd(),
62047
+ agentName: "coordinator",
62048
+ epicId: args2.epic_id,
62049
+ beadId: args2.bead_id,
62050
+ workerName: "worker",
62051
+ subtaskTitle: args2.subtask_title,
62052
+ files: args2.files,
62053
+ model: selectedModel,
62054
+ spawnOrder: 0,
62055
+ isParallel: false,
62056
+ rationale: args2.subtask_description || `Spawning worker for: ${args2.subtask_title}`
62057
+ });
62058
+ } catch (error45) {
62059
+ console.warn("[swarm_spawn_subtask] Failed to trace worker_spawn:", error45);
62060
+ }
61694
62061
  if (args2.project_path) {
61695
62062
  try {
61696
62063
  const { createEvent: createEvent3, appendEvent: appendEvent3 } = await import("swarm-mail");
@@ -61920,7 +62287,7 @@ var swarm_plan_prompt = tool({
61920
62287
  selectedStrategy = args2.strategy;
61921
62288
  strategyReasoning = `User-specified strategy: ${selectedStrategy}`;
61922
62289
  } else {
61923
- const selection = selectStrategy2(args2.task);
62290
+ const selection = await selectStrategy2(args2.task);
61924
62291
  selectedStrategy = selection.strategy;
61925
62292
  strategyReasoning = selection.reasoning;
61926
62293
  }
@@ -65626,6 +65993,7 @@ var sessionStats = {
65626
65993
 
65627
65994
  // src/index.ts
65628
65995
  init_skills();
65996
+ init_swarm_validation();
65629
65997
  var SwarmPlugin = async (input) => {
65630
65998
  const { $, directory, client } = input;
65631
65999
  setHiveWorkingDirectory(directory);
@@ -2,12 +2,11 @@
2
2
  * GREEN PHASE: SQL Query Tools Implementation
3
3
  *
4
4
  * Provides:
5
- * - 10 preset queries for observability insights
5
+ * - 13 preset queries for observability insights (10 base + 3 decision trace)
6
6
  * - Custom SQL execution with timing
7
7
  * - 3 output formats: Table (box-drawing), CSV, JSON
8
8
  */
9
- import type { DatabaseAdapter } from "swarm-mail";
10
- export type PresetQueryName = "failed_decompositions" | "duration_by_strategy" | "file_conflicts" | "worker_success_rate" | "review_rejections" | "blocked_tasks" | "agent_activity" | "event_frequency" | "error_patterns" | "compaction_stats";
9
+ export type PresetQueryName = "failed_decompositions" | "duration_by_strategy" | "file_conflicts" | "worker_success_rate" | "review_rejections" | "blocked_tasks" | "agent_activity" | "event_frequency" | "error_patterns" | "compaction_stats" | "decision_quality" | "strategy_success_rates" | "decisions_by_pattern";
11
10
  export interface QueryResult {
12
11
  columns: string[];
13
12
  rows: Record<string, unknown>[];
@@ -16,14 +15,23 @@ export interface QueryResult {
16
15
  }
17
16
  export declare const presetQueries: Record<PresetQueryName, string>;
18
17
  /**
19
- * Execute custom SQL against the events table.
18
+ * Execute custom SQL query (CLI wrapper).
19
+ * Creates database adapter automatically.
20
20
  *
21
- * @param db - DatabaseAdapter instance
21
+ * @param projectPath - Project path (unused, queries global database)
22
22
  * @param sql - SQL query string
23
- * @param params - Optional parameterized query values
24
- * @returns QueryResult with rows, columns, timing
23
+ * @returns Raw rows array for CLI formatting
25
24
  */
26
- export declare function executeQuery(db: DatabaseAdapter, sql: string, params?: unknown[]): Promise<QueryResult>;
25
+ export declare function executeQuery(projectPath: string, sql: string): Promise<any[]>;
26
+ /**
27
+ * Execute a preset query by name (CLI wrapper).
28
+ * Creates database adapter automatically.
29
+ *
30
+ * @param projectPath - Project path (unused, queries global database)
31
+ * @param presetName - Name of the preset query
32
+ * @returns Raw rows array for CLI formatting
33
+ */
34
+ export declare function executePreset(projectPath: string, presetName: string): Promise<any[]>;
27
35
  /**
28
36
  * Format query result as aligned table with box-drawing characters.
29
37
  *
@@ -34,9 +42,9 @@ export declare function executeQuery(db: DatabaseAdapter, sql: string, params?:
34
42
  * │ AgentA │ 5 │
35
43
  * │ AgentB │ 3 │
36
44
  * └──────────┴───────┘
37
- * 2 rows in 5.2ms
45
+ * 2 rows
38
46
  */
39
- export declare function formatAsTable(result: QueryResult): string;
47
+ export declare function formatAsTable(rows: Record<string, unknown>[]): string;
40
48
  /**
41
49
  * Format query result as CSV with proper escaping.
42
50
  *
@@ -45,7 +53,7 @@ export declare function formatAsTable(result: QueryResult): string;
45
53
  * - Quotes → double them
46
54
  * - Newlines → wrap in quotes
47
55
  */
48
- export declare function formatAsCSV(result: QueryResult): string;
56
+ export declare function formatAsCSV(rows: Record<string, unknown>[]): string;
49
57
  /**
50
58
  * Format query result as pretty-printed JSON array.
51
59
  *
@@ -55,5 +63,5 @@ export declare function formatAsCSV(result: QueryResult): string;
55
63
  * { "name": "AgentB", "count": 3 }
56
64
  * ]
57
65
  */
58
- export declare function formatAsJSON(result: QueryResult): string;
66
+ export declare function formatAsJSON(rows: Record<string, unknown>[]): string;
59
67
  //# sourceMappingURL=query-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"query-tools.d.ts","sourceRoot":"","sources":["../src/query-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMlD,MAAM,MAAM,eAAe,GACxB,uBAAuB,GACvB,sBAAsB,GACtB,gBAAgB,GAChB,qBAAqB,GACrB,mBAAmB,GACnB,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,kBAAkB,CAAC;AAEtB,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACxB;AAMD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAoHzD,CAAC;AAMF;;;;;;;GAOG;AACH,wBAAsB,YAAY,CACjC,EAAE,EAAE,eAAe,EACnB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,OAAO,EAAE,GAChB,OAAO,CAAC,WAAW,CAAC,CAiBtB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAkEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CA2BvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAExD"}
1
+ {"version":3,"file":"query-tools.d.ts","sourceRoot":"","sources":["../src/query-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,MAAM,MAAM,eAAe,GACxB,uBAAuB,GACvB,sBAAsB,GACtB,gBAAgB,GAChB,qBAAqB,GACrB,mBAAmB,GACnB,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,kBAAkB,GAClB,kBAAkB,GAClB,wBAAwB,GACxB,sBAAsB,CAAC;AAE1B,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACxB;AAMD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAgKzD,CAAC;AAgFF;;;;;;;GAOG;AACH,wBAAsB,YAAY,CACjC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,GAAG,EAAE,CAAC,CAIhB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAClC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,EAAE,CAAC,CAIhB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAmErE;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CA2BnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,CAEpE"}