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.
Files changed (42) hide show
  1. package/README.md +277 -54
  2. package/bin/swarm.ts +1 -1
  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 +9 -9
  7. package/dist/index.d.ts +32 -2
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +535 -27
  10. package/dist/plugin.js +295 -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 +220 -22
  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.d.ts +4 -2
  23. package/dist/swarm.d.ts.map +1 -1
  24. package/examples/commands/swarm.md +745 -0
  25. package/examples/plugin-wrapper-template.ts +2611 -0
  26. package/examples/skills/hive-workflow/SKILL.md +212 -0
  27. package/examples/skills/skill-creator/SKILL.md +223 -0
  28. package/examples/skills/swarm-coordination/SKILL.md +292 -0
  29. package/global-skills/cli-builder/SKILL.md +344 -0
  30. package/global-skills/cli-builder/references/advanced-patterns.md +244 -0
  31. package/global-skills/learning-systems/SKILL.md +644 -0
  32. package/global-skills/skill-creator/LICENSE.txt +202 -0
  33. package/global-skills/skill-creator/SKILL.md +352 -0
  34. package/global-skills/skill-creator/references/output-patterns.md +82 -0
  35. package/global-skills/skill-creator/references/workflows.md +28 -0
  36. package/global-skills/swarm-coordination/SKILL.md +995 -0
  37. package/global-skills/swarm-coordination/references/coordinator-patterns.md +235 -0
  38. package/global-skills/swarm-coordination/references/strategies.md +138 -0
  39. package/global-skills/system-design/SKILL.md +213 -0
  40. package/global-skills/testing-patterns/SKILL.md +430 -0
  41. package/global-skills/testing-patterns/references/dependency-breaking-catalog.md +586 -0
  42. 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
- 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;
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
- 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
+ }
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 fullId = await resolvePartialId(adapter, projectKey, args.id) || args.id;
40412
- const cell = await adapter.getCell(projectKey, fullId);
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(cell);
40417
- return JSON.stringify([formatted2], null, 2);
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
- const message = error45 instanceof Error ? error45.message : String(error45);
40437
- if (message.includes("Ambiguous hash")) {
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 createLibSQLAdapter({ url: "file:./.swarm-mail/streams.db" });
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 createLibSQLAdapter({ url: "file:./.swarm-mail/streams.db" });
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,