opencode-swarm-plugin 0.59.1 → 0.60.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 (64) hide show
  1. package/README.md +14 -1
  2. package/bin/commands/doctor.test.ts +622 -0
  3. package/bin/commands/doctor.ts +658 -0
  4. package/bin/commands/status.test.ts +506 -0
  5. package/bin/commands/status.ts +520 -0
  6. package/bin/commands/tree.ts +39 -3
  7. package/bin/swarm.ts +19 -3
  8. package/claude-plugin/.claude-plugin/plugin.json +1 -1
  9. package/claude-plugin/commands/swarm.md +125 -2
  10. package/claude-plugin/dist/index.js +669 -308
  11. package/claude-plugin/dist/schemas/cell.d.ts +2 -0
  12. package/claude-plugin/dist/schemas/cell.d.ts.map +1 -1
  13. package/claude-plugin/dist/utils/adapter-cache.d.ts +36 -0
  14. package/claude-plugin/dist/utils/adapter-cache.d.ts.map +1 -0
  15. package/claude-plugin/dist/utils/event-utils.d.ts +31 -0
  16. package/claude-plugin/dist/utils/event-utils.d.ts.map +1 -0
  17. package/claude-plugin/dist/utils/git-commit-info.d.ts +10 -0
  18. package/claude-plugin/dist/utils/git-commit-info.d.ts.map +1 -0
  19. package/claude-plugin/dist/utils/tree-renderer.d.ts +69 -13
  20. package/claude-plugin/dist/utils/tree-renderer.d.ts.map +1 -1
  21. package/dist/bin/swarm.js +2664 -980
  22. package/dist/cass-tools.d.ts.map +1 -1
  23. package/dist/dashboard.d.ts.map +1 -1
  24. package/dist/hive.d.ts +8 -0
  25. package/dist/hive.d.ts.map +1 -1
  26. package/dist/hive.js +81 -101
  27. package/dist/hivemind-tools.d.ts.map +1 -1
  28. package/dist/index.d.ts +22 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +458 -311
  31. package/dist/marketplace/index.js +669 -308
  32. package/dist/memory-tools.d.ts.map +1 -1
  33. package/dist/memory.d.ts.map +1 -1
  34. package/dist/plugin.js +456 -308
  35. package/dist/replay-tools.d.ts +5 -1
  36. package/dist/replay-tools.d.ts.map +1 -1
  37. package/dist/schemas/cell.d.ts +2 -0
  38. package/dist/schemas/cell.d.ts.map +1 -1
  39. package/dist/skills.d.ts +4 -0
  40. package/dist/skills.d.ts.map +1 -1
  41. package/dist/storage.d.ts +7 -0
  42. package/dist/storage.d.ts.map +1 -1
  43. package/dist/swarm-mail.d.ts +2 -2
  44. package/dist/swarm-mail.d.ts.map +1 -1
  45. package/dist/swarm-orchestrate.d.ts +12 -0
  46. package/dist/swarm-orchestrate.d.ts.map +1 -1
  47. package/dist/swarm-prompts.d.ts +1 -1
  48. package/dist/swarm-prompts.d.ts.map +1 -1
  49. package/dist/swarm-prompts.js +408 -274
  50. package/dist/swarm-verify.d.ts +100 -0
  51. package/dist/swarm-verify.d.ts.map +1 -0
  52. package/dist/swarm.d.ts +19 -1
  53. package/dist/swarm.d.ts.map +1 -1
  54. package/dist/test-utils/msw-server.d.ts +21 -0
  55. package/dist/test-utils/msw-server.d.ts.map +1 -0
  56. package/dist/utils/adapter-cache.d.ts +36 -0
  57. package/dist/utils/adapter-cache.d.ts.map +1 -0
  58. package/dist/utils/event-utils.d.ts +31 -0
  59. package/dist/utils/event-utils.d.ts.map +1 -0
  60. package/dist/utils/git-commit-info.d.ts +10 -0
  61. package/dist/utils/git-commit-info.d.ts.map +1 -0
  62. package/dist/utils/tree-renderer.d.ts +69 -13
  63. package/dist/utils/tree-renderer.d.ts.map +1 -1
  64. package/package.json +3 -2
package/dist/plugin.js CHANGED
@@ -27180,7 +27180,7 @@ import {
27180
27180
  sep
27181
27181
  } from "path";
27182
27182
  import { fileURLToPath } from "url";
27183
- import { getSwarmMailLibSQL as getSwarmMailLibSQL3, createEvent as createEvent2 } from "swarm-mail";
27183
+ import { getSwarmMailLibSQL as getSwarmMailLibSQL3, createEvent as createEvent3 } from "swarm-mail";
27184
27184
  function resolveGuidanceModel(model) {
27185
27185
  if (!model)
27186
27186
  return "unknown";
@@ -27223,7 +27223,7 @@ async function emitSkillLoadedEvent(data) {
27223
27223
  try {
27224
27224
  const projectPath = skillsProjectDirectory;
27225
27225
  const swarmMail = await getSwarmMailLibSQL3(projectPath);
27226
- const event = createEvent2("skill_loaded", {
27226
+ const event = createEvent3("skill_loaded", {
27227
27227
  project_key: projectPath,
27228
27228
  skill_name: data.skill_name,
27229
27229
  skill_source: data.skill_source,
@@ -27237,7 +27237,7 @@ async function emitSkillCreatedEvent(data) {
27237
27237
  try {
27238
27238
  const projectPath = skillsProjectDirectory;
27239
27239
  const swarmMail = await getSwarmMailLibSQL3(projectPath);
27240
- const event = createEvent2("skill_created", {
27240
+ const event = createEvent3("skill_created", {
27241
27241
  project_key: projectPath,
27242
27242
  skill_name: data.skill_name,
27243
27243
  skill_scope: data.skill_scope,
@@ -27757,7 +27757,8 @@ Scripts run in the skill's directory with the project directory as an argument.`
27757
27757
  args: {
27758
27758
  skill: tool.schema.string().describe("Name of the skill"),
27759
27759
  script: tool.schema.string().describe("Name of the script file to execute"),
27760
- args: tool.schema.array(tool.schema.string()).optional().describe("Additional arguments to pass to the script")
27760
+ args: tool.schema.array(tool.schema.string()).optional().describe("Additional arguments to pass to the script"),
27761
+ timeout_ms: tool.schema.number().optional().describe("Timeout in milliseconds (default: 60000)")
27761
27762
  },
27762
27763
  async execute(args, ctx) {
27763
27764
  console.warn("[DEPRECATED] skills_execute is deprecated. OpenCode now provides native skills support. This tool will be removed in a future version.");
@@ -27770,7 +27771,7 @@ Scripts run in the skill's directory with the project directory as an argument.`
27770
27771
  }
27771
27772
  const scriptPath = join6(skill.directory, "scripts", args.script);
27772
27773
  const scriptArgs = args.args || [];
27773
- const TIMEOUT_MS = 60000;
27774
+ const TIMEOUT_MS = args.timeout_ms ?? 60000;
27774
27775
  const proc = Bun.spawn([scriptPath, skillsProjectDirectory, ...scriptArgs], {
27775
27776
  cwd: skill.directory,
27776
27777
  stdout: "pipe",
@@ -28673,6 +28674,7 @@ __export(exports_storage, {
28673
28674
  resetStorage: () => resetStorage,
28674
28675
  resetSessionStats: () => resetSessionStats,
28675
28676
  resetCommandCache: () => resetCommandCache,
28677
+ resetAvailabilityCache: () => resetAvailabilityCache,
28676
28678
  isSemanticMemoryAvailable: () => isSemanticMemoryAvailable,
28677
28679
  getTestCollectionName: () => getTestCollectionName,
28678
28680
  getStorage: () => getStorage,
@@ -29023,12 +29025,25 @@ function createStorage(config2 = {}) {
29023
29025
  }
29024
29026
  }
29025
29027
  async function isSemanticMemoryAvailable() {
29026
- try {
29027
- const result = await execSemanticMemory(["stats"]);
29028
- return result.exitCode === 0;
29029
- } catch {
29030
- return false;
29031
- }
29028
+ if (_availabilityCache !== null)
29029
+ return _availabilityCache;
29030
+ if (_availabilityPromise)
29031
+ return _availabilityPromise;
29032
+ _availabilityPromise = (async () => {
29033
+ try {
29034
+ const result = await execSemanticMemory(["stats"]);
29035
+ _availabilityCache = result.exitCode === 0;
29036
+ } catch {
29037
+ _availabilityCache = false;
29038
+ }
29039
+ _availabilityPromise = null;
29040
+ return _availabilityCache;
29041
+ })();
29042
+ return _availabilityPromise;
29043
+ }
29044
+ function resetAvailabilityCache() {
29045
+ _availabilityCache = null;
29046
+ _availabilityPromise = null;
29032
29047
  }
29033
29048
  async function getResolvedCommand() {
29034
29049
  return resolveSemanticMemoryCommand();
@@ -29064,7 +29079,7 @@ async function resetStorage() {
29064
29079
  }
29065
29080
  globalStoragePromise = null;
29066
29081
  }
29067
- var cachedCommand = null, DEFAULT_STORAGE_CONFIG, sessionStats, globalStorage = null, globalStoragePromise = null;
29082
+ var cachedCommand = null, DEFAULT_STORAGE_CONFIG, sessionStats, _availabilityCache = null, _availabilityPromise = null, globalStorage = null, globalStoragePromise = null;
29068
29083
  var init_storage = __esm(() => {
29069
29084
  init_learning();
29070
29085
  init_anti_patterns();
@@ -29078,6 +29093,27 @@ var init_storage = __esm(() => {
29078
29093
  };
29079
29094
  });
29080
29095
 
29096
+ // src/utils/adapter-cache.ts
29097
+ class AdapterCache {
29098
+ cached = null;
29099
+ cachedPath = null;
29100
+ async get(projectPath, factory) {
29101
+ if (this.cached && this.cachedPath === projectPath) {
29102
+ return this.cached;
29103
+ }
29104
+ this.cached = await factory(projectPath);
29105
+ this.cachedPath = projectPath;
29106
+ return this.cached;
29107
+ }
29108
+ clear() {
29109
+ this.cached = null;
29110
+ this.cachedPath = null;
29111
+ }
29112
+ getCachedPath() {
29113
+ return this.cachedPath;
29114
+ }
29115
+ }
29116
+
29081
29117
  // ../../node_modules/.bun/effect@3.19.12/node_modules/effect/dist/esm/Function.js
29082
29118
  function pipe2(a, ab, bc, cd, de, ef, fg, gh, hi) {
29083
29119
  switch (arguments.length) {
@@ -46404,6 +46440,9 @@ Linked to ${result.links.length} related memor${result.links.length === 1 ? "y"
46404
46440
  };
46405
46441
  },
46406
46442
  async find(args2) {
46443
+ if (!args2.query || typeof args2.query !== "string") {
46444
+ throw new Error("query is required for find operation");
46445
+ }
46407
46446
  const limit = args2.limit ?? 10;
46408
46447
  let results;
46409
46448
  let usedFallback = false;
@@ -46522,22 +46561,20 @@ var init_memory = __esm(() => {
46522
46561
  });
46523
46562
 
46524
46563
  // src/memory-tools.ts
46525
- import { getSwarmMailLibSQL as getSwarmMailLibSQL5, createEvent as createEvent4, appendEvent as appendEvent3 } from "swarm-mail";
46564
+ import { getSwarmMailLibSQL as getSwarmMailLibSQL5, createEvent as createEvent5, appendEvent as appendEvent4 } from "swarm-mail";
46526
46565
  async function getMemoryAdapter(projectPath) {
46527
46566
  const path3 = projectPath || process.cwd();
46528
- if (cachedAdapter && cachedProjectPath === path3) {
46529
- return cachedAdapter;
46530
- }
46531
- const swarmMail = await getSwarmMailLibSQL5(path3);
46532
- const dbAdapter = await swarmMail.getDatabase();
46533
- cachedAdapter = await createMemoryAdapter(dbAdapter);
46534
- cachedProjectPath = path3;
46535
- return cachedAdapter;
46567
+ return memoryAdapterCache.get(path3, async (projectPath2) => {
46568
+ const swarmMail = await getSwarmMailLibSQL5(projectPath2);
46569
+ const dbAdapter = await swarmMail.getDatabase();
46570
+ return await createMemoryAdapter(dbAdapter);
46571
+ });
46536
46572
  }
46537
- var cachedAdapter = null, cachedProjectPath = null, semantic_memory_store, semantic_memory_find, semantic_memory_get, semantic_memory_remove, semantic_memory_validate, semantic_memory_list, semantic_memory_stats, semantic_memory_check, semantic_memory_upsert;
46573
+ var memoryAdapterCache, semantic_memory_store, semantic_memory_find, semantic_memory_get, semantic_memory_remove, semantic_memory_validate, semantic_memory_list, semantic_memory_stats, semantic_memory_check, semantic_memory_upsert;
46538
46574
  var init_memory_tools = __esm(() => {
46539
46575
  init_dist();
46540
46576
  init_memory();
46577
+ memoryAdapterCache = new AdapterCache;
46541
46578
  semantic_memory_store = tool({
46542
46579
  description: "Store a memory with semantic embedding. Memories are searchable by semantic similarity and can be organized into collections. Confidence affects decay rate: high confidence (1.0) = 135 day half-life, low confidence (0.0) = 45 day half-life. Supports auto-tagging, auto-linking, and entity extraction via LLM.",
46543
46580
  args: {
@@ -46554,9 +46591,9 @@ var init_memory_tools = __esm(() => {
46554
46591
  const adapter = await getMemoryAdapter();
46555
46592
  const result = await adapter.store(args2);
46556
46593
  try {
46557
- const projectKey = cachedProjectPath || process.cwd();
46594
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46558
46595
  const tags = args2.tags ? args2.tags.split(",").map((t) => t.trim()) : [];
46559
- const event = createEvent4("memory_stored", {
46596
+ const event = createEvent5("memory_stored", {
46560
46597
  project_key: projectKey,
46561
46598
  memory_id: result.id,
46562
46599
  content_preview: args2.information.slice(0, 100),
@@ -46564,7 +46601,7 @@ var init_memory_tools = __esm(() => {
46564
46601
  auto_tagged: args2.autoTag,
46565
46602
  collection: args2.collection
46566
46603
  });
46567
- await appendEvent3(event, projectKey);
46604
+ await appendEvent4(event, projectKey);
46568
46605
  } catch (error45) {
46569
46606
  console.warn("[semantic_memory_store] Failed to emit memory_stored event:", error45);
46570
46607
  }
@@ -46586,9 +46623,9 @@ var init_memory_tools = __esm(() => {
46586
46623
  const result = await adapter.find(args2);
46587
46624
  const duration3 = Date.now() - startTime;
46588
46625
  try {
46589
- const projectKey = cachedProjectPath || process.cwd();
46626
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46590
46627
  const topScore = result.results.length > 0 ? result.results[0].score : undefined;
46591
- const event = createEvent4("memory_found", {
46628
+ const event = createEvent5("memory_found", {
46592
46629
  project_key: projectKey,
46593
46630
  query: args2.query,
46594
46631
  result_count: result.results.length,
@@ -46596,7 +46633,7 @@ var init_memory_tools = __esm(() => {
46596
46633
  search_duration_ms: duration3,
46597
46634
  used_fts: args2.fts
46598
46635
  });
46599
- await appendEvent3(event, projectKey);
46636
+ await appendEvent4(event, projectKey);
46600
46637
  } catch (error45) {
46601
46638
  console.warn("[semantic_memory_find] Failed to emit memory_found event:", error45);
46602
46639
  }
@@ -46624,12 +46661,12 @@ var init_memory_tools = __esm(() => {
46624
46661
  const result = await adapter.remove(args2);
46625
46662
  if (result.success) {
46626
46663
  try {
46627
- const projectKey = cachedProjectPath || process.cwd();
46628
- const event = createEvent4("memory_deleted", {
46664
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46665
+ const event = createEvent5("memory_deleted", {
46629
46666
  project_key: projectKey,
46630
46667
  memory_id: args2.id
46631
46668
  });
46632
- await appendEvent3(event, projectKey);
46669
+ await appendEvent4(event, projectKey);
46633
46670
  } catch (error45) {
46634
46671
  console.warn("[semantic_memory_remove] Failed to emit memory_deleted event:", error45);
46635
46672
  }
@@ -46647,13 +46684,13 @@ var init_memory_tools = __esm(() => {
46647
46684
  const result = await adapter.validate(args2);
46648
46685
  if (result.success) {
46649
46686
  try {
46650
- const projectKey = cachedProjectPath || process.cwd();
46651
- const event = createEvent4("memory_validated", {
46687
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46688
+ const event = createEvent5("memory_validated", {
46652
46689
  project_key: projectKey,
46653
46690
  memory_id: args2.id,
46654
46691
  decay_reset: true
46655
46692
  });
46656
- await appendEvent3(event, projectKey);
46693
+ await appendEvent4(event, projectKey);
46657
46694
  } catch (error45) {
46658
46695
  console.warn("[semantic_memory_validate] Failed to emit memory_validated event:", error45);
46659
46696
  }
@@ -46706,14 +46743,14 @@ var init_memory_tools = __esm(() => {
46706
46743
  const adapter = await getMemoryAdapter();
46707
46744
  const result = await adapter.upsert(args2);
46708
46745
  try {
46709
- const projectKey = cachedProjectPath || process.cwd();
46710
- const event = createEvent4("memory_updated", {
46746
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46747
+ const event = createEvent5("memory_updated", {
46711
46748
  project_key: projectKey,
46712
46749
  memory_id: result.memoryId || "unknown",
46713
46750
  operation: result.operation,
46714
46751
  reason: result.reason
46715
46752
  });
46716
- await appendEvent3(event, projectKey);
46753
+ await appendEvent4(event, projectKey);
46717
46754
  } catch (error45) {
46718
46755
  console.warn("[semantic_memory_upsert] Failed to emit memory_updated event:", error45);
46719
46756
  }
@@ -58423,7 +58460,8 @@ var CellUpdateArgsSchema = exports_external.object({
58423
58460
  });
58424
58461
  var CellCloseArgsSchema = exports_external.object({
58425
58462
  id: exports_external.string(),
58426
- reason: exports_external.string().min(1, "Reason required")
58463
+ reason: exports_external.string().min(1, "Reason required"),
58464
+ result: exports_external.string().optional()
58427
58465
  });
58428
58466
  var CellQueryArgsSchema = exports_external.object({
58429
58467
  status: CellStatusSchema.optional(),
@@ -58929,7 +58967,24 @@ var CellEventSchema = exports_external.discriminatedUnion("type", [
58929
58967
  CellCompactedEventSchema
58930
58968
  ]);
58931
58969
  // src/hive.ts
58970
+ import { createEvent as createEvent2, appendEvent as appendEvent2 } from "swarm-mail";
58971
+
58972
+ // src/utils/event-utils.ts
58932
58973
  import { createEvent, appendEvent } from "swarm-mail";
58974
+ async function safeEmitEvent(eventType, data, toolName, projectPath) {
58975
+ try {
58976
+ const effectiveProjectPath = projectPath || process.cwd();
58977
+ const event = createEvent(eventType, {
58978
+ project_key: effectiveProjectPath,
58979
+ ...data
58980
+ });
58981
+ await appendEvent(event, effectiveProjectPath);
58982
+ } catch (error45) {
58983
+ console.warn(`[${toolName}] Failed to emit ${eventType} event:`, error45);
58984
+ }
58985
+ }
58986
+
58987
+ // src/hive.ts
58933
58988
  var hiveWorkingDirectory = null;
58934
58989
  function setHiveWorkingDirectory(directory) {
58935
58990
  hiveWorkingDirectory = directory;
@@ -59087,20 +59142,14 @@ var hive_create = tool({
59087
59142
  parent_id: validated.parent_id
59088
59143
  });
59089
59144
  await adapter.markDirty(projectKey, cell.id);
59090
- try {
59091
- const event = createEvent("cell_created", {
59092
- project_key: projectKey,
59093
- cell_id: cell.id,
59094
- title: validated.title,
59095
- description: validated.description,
59096
- issue_type: validated.type || "task",
59097
- priority: validated.priority ?? 2,
59098
- parent_id: validated.parent_id
59099
- });
59100
- await appendEvent(event, projectKey);
59101
- } catch (error45) {
59102
- console.warn("[hive_create] Failed to emit cell_created event:", error45);
59103
- }
59145
+ await safeEmitEvent("cell_created", {
59146
+ cell_id: cell.id,
59147
+ title: validated.title,
59148
+ description: validated.description,
59149
+ issue_type: validated.type || "task",
59150
+ priority: validated.priority ?? 2,
59151
+ parent_id: validated.parent_id
59152
+ }, "hive_create", projectKey);
59104
59153
  const formatted = formatCellForOutput(cell);
59105
59154
  return JSON.stringify(formatted, null, 2);
59106
59155
  } catch (error45) {
@@ -59182,53 +59231,35 @@ var hive_create_epic = tool({
59182
59231
  subtasks: created.slice(1).map((c) => formatCellForOutput(c))
59183
59232
  };
59184
59233
  const effectiveProjectKey = args.project_key || projectKey;
59185
- try {
59186
- const epicCreatedEvent = createEvent("epic_created", {
59187
- project_key: effectiveProjectKey,
59188
- epic_id: epic.id,
59189
- title: validated.epic_title,
59190
- description: validated.epic_description,
59191
- subtask_count: validated.subtasks.length,
59192
- subtask_ids: created.slice(1).map((c) => c.id)
59193
- });
59194
- await appendEvent(epicCreatedEvent, effectiveProjectKey);
59195
- } catch (error45) {
59196
- console.warn("[hive_create_epic] Failed to emit epic_created event:", error45);
59197
- }
59198
- try {
59199
- const event = createEvent("decomposition_generated", {
59200
- project_key: effectiveProjectKey,
59201
- epic_id: epic.id,
59202
- task: args.task || validated.epic_title,
59203
- context: validated.epic_description,
59204
- strategy: args.strategy || "feature-based",
59205
- epic_title: validated.epic_title,
59206
- subtasks: validated.subtasks.map((st) => ({
59207
- title: st.title,
59208
- files: st.files || [],
59209
- priority: st.priority
59210
- })),
59211
- recovery_context: args.recovery_context
59212
- });
59213
- await appendEvent(event, effectiveProjectKey);
59214
- } catch (error45) {
59215
- console.warn("[hive_create_epic] Failed to emit DecompositionGeneratedEvent:", error45);
59216
- }
59217
- try {
59218
- const totalFiles = validated.subtasks.reduce((count, st) => count + (st.files?.length || 0), 0);
59219
- const swarmStartedEvent = createEvent("swarm_started", {
59220
- project_key: effectiveProjectKey,
59221
- epic_id: epic.id,
59222
- epic_title: validated.epic_title,
59223
- strategy: args.strategy || "feature-based",
59224
- subtask_count: validated.subtasks.length,
59225
- total_files: totalFiles,
59226
- coordinator_agent: "coordinator"
59227
- });
59228
- await appendEvent(swarmStartedEvent, effectiveProjectKey);
59229
- } catch (error45) {
59230
- console.warn("[hive_create_epic] Failed to emit SwarmStartedEvent:", error45);
59231
- }
59234
+ await safeEmitEvent("epic_created", {
59235
+ epic_id: epic.id,
59236
+ title: validated.epic_title,
59237
+ description: validated.epic_description,
59238
+ subtask_count: validated.subtasks.length,
59239
+ subtask_ids: created.slice(1).map((c) => c.id)
59240
+ }, "hive_create_epic", effectiveProjectKey);
59241
+ await safeEmitEvent("decomposition_generated", {
59242
+ epic_id: epic.id,
59243
+ task: args.task || validated.epic_title,
59244
+ context: validated.epic_description,
59245
+ strategy: args.strategy || "feature-based",
59246
+ epic_title: validated.epic_title,
59247
+ subtasks: validated.subtasks.map((st) => ({
59248
+ title: st.title,
59249
+ files: st.files || [],
59250
+ priority: st.priority
59251
+ })),
59252
+ recovery_context: args.recovery_context
59253
+ }, "hive_create_epic", effectiveProjectKey);
59254
+ const totalFiles = validated.subtasks.reduce((count, st) => count + (st.files?.length || 0), 0);
59255
+ await safeEmitEvent("swarm_started", {
59256
+ epic_id: epic.id,
59257
+ epic_title: validated.epic_title,
59258
+ strategy: args.strategy || "feature-based",
59259
+ subtask_count: validated.subtasks.length,
59260
+ total_files: totalFiles,
59261
+ coordinator_agent: "coordinator"
59262
+ }, "hive_create_epic", effectiveProjectKey);
59232
59263
  try {
59233
59264
  const { captureCoordinatorEvent: captureCoordinatorEvent2 } = await Promise.resolve().then(() => (init_eval_capture(), exports_eval_capture));
59234
59265
  const filesPerSubtask = {};
@@ -59359,23 +59390,17 @@ var hive_update = tool({
59359
59390
  cell = existingCell;
59360
59391
  }
59361
59392
  await adapter.markDirty(projectKey, cellId);
59362
- try {
59363
- const fieldsChanged = [];
59364
- if (validated.status)
59365
- fieldsChanged.push("status");
59366
- if (validated.description !== undefined)
59367
- fieldsChanged.push("description");
59368
- if (validated.priority !== undefined)
59369
- fieldsChanged.push("priority");
59370
- const event = createEvent("cell_updated", {
59371
- project_key: projectKey,
59372
- cell_id: cellId,
59373
- fields_changed: fieldsChanged
59374
- });
59375
- await appendEvent(event, projectKey);
59376
- } catch (error45) {
59377
- console.warn("[hive_update] Failed to emit cell_updated event:", error45);
59378
- }
59393
+ const fieldsChanged = [];
59394
+ if (validated.status)
59395
+ fieldsChanged.push("status");
59396
+ if (validated.description !== undefined)
59397
+ fieldsChanged.push("description");
59398
+ if (validated.priority !== undefined)
59399
+ fieldsChanged.push("priority");
59400
+ await safeEmitEvent("cell_updated", {
59401
+ cell_id: cellId,
59402
+ fields_changed: fieldsChanged
59403
+ }, "hive_update", projectKey);
59379
59404
  const formatted = formatCellForOutput(cell);
59380
59405
  return JSON.stringify(formatted, null, 2);
59381
59406
  } catch (error45) {
@@ -59394,7 +59419,8 @@ var hive_close = tool({
59394
59419
  description: "Close a cell with reason",
59395
59420
  args: {
59396
59421
  id: tool.schema.string().describe("Cell ID or partial hash"),
59397
- reason: tool.schema.string().describe("Completion reason")
59422
+ reason: tool.schema.string().describe("Completion reason"),
59423
+ result: tool.schema.string().optional().describe("Implementation summary - what was actually done (like a PR description)")
59398
59424
  },
59399
59425
  async execute(args, ctx) {
59400
59426
  const validated = CellCloseArgsSchema.parse(args);
@@ -59404,11 +59430,10 @@ var hive_close = tool({
59404
59430
  const cellId = await resolvePartialId(adapter, projectKey, validated.id) || validated.id;
59405
59431
  const cellBeforeClose = await adapter.getCell(projectKey, cellId);
59406
59432
  const isEpic = cellBeforeClose?.type === "epic";
59407
- const cell = await adapter.closeCell(projectKey, cellId, validated.reason);
59433
+ const cell = await adapter.closeCell(projectKey, cellId, validated.reason, validated.result ? { result: validated.result } : undefined);
59408
59434
  await adapter.markDirty(projectKey, cellId);
59409
59435
  if (isEpic && cellBeforeClose) {
59410
59436
  try {
59411
- const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
59412
59437
  const subtasks = await adapter.queryCells(projectKey, { parent_id: cellId });
59413
59438
  const completedSubtasks = subtasks.filter((st) => st.status === "closed");
59414
59439
  const failedSubtasks = subtasks.filter((st) => st.status === "blocked");
@@ -59446,8 +59471,7 @@ var hive_close = tool({
59446
59471
  } catch (error45) {
59447
59472
  console.warn("[hive_close] Failed to calculate duration:", error45);
59448
59473
  }
59449
- const swarmCompletedEvent = createEvent2("swarm_completed", {
59450
- project_key: projectKey,
59474
+ await safeEmitEvent("swarm_completed", {
59451
59475
  epic_id: cellId,
59452
59476
  epic_title: cellBeforeClose.title,
59453
59477
  success: failedSubtasks.length === 0,
@@ -59455,8 +59479,7 @@ var hive_close = tool({
59455
59479
  subtasks_completed: completedSubtasks.length,
59456
59480
  subtasks_failed: failedSubtasks.length,
59457
59481
  total_files_touched: totalFilesTouched
59458
- });
59459
- await appendEvent2(swarmCompletedEvent, projectKey);
59482
+ }, "hive_close", projectKey);
59460
59483
  try {
59461
59484
  const { runPostSwarmValidation: runPostSwarmValidation2 } = await Promise.resolve().then(() => (init_swarm_validation(), exports_swarm_validation));
59462
59485
  const { readEvents } = await import("swarm-mail");
@@ -59492,16 +59515,10 @@ var hive_close = tool({
59492
59515
  console.warn("[hive_close] Failed to emit SwarmCompletedEvent:", error45);
59493
59516
  }
59494
59517
  }
59495
- try {
59496
- const event = createEvent("cell_closed", {
59497
- project_key: projectKey,
59498
- cell_id: cellId,
59499
- reason: validated.reason
59500
- });
59501
- await appendEvent(event, projectKey);
59502
- } catch (error45) {
59503
- console.warn("[hive_close] Failed to emit cell_closed event:", error45);
59504
- }
59518
+ await safeEmitEvent("cell_closed", {
59519
+ cell_id: cellId,
59520
+ reason: validated.reason
59521
+ }, "hive_close", projectKey);
59505
59522
  return `Closed ${cell.id}: ${validated.reason}`;
59506
59523
  } catch (error45) {
59507
59524
  const message = error45 instanceof Error ? error45.message : String(error45);
@@ -59528,13 +59545,13 @@ var hive_start = tool({
59528
59545
  const cell = await adapter.changeCellStatus(projectKey, cellId, "in_progress");
59529
59546
  await adapter.markDirty(projectKey, cellId);
59530
59547
  try {
59531
- const event = createEvent("cell_status_changed", {
59548
+ const event = createEvent2("cell_status_changed", {
59532
59549
  project_key: projectKey,
59533
59550
  cell_id: cellId,
59534
59551
  old_status: "open",
59535
59552
  new_status: "in_progress"
59536
59553
  });
59537
- await appendEvent(event, projectKey);
59554
+ await appendEvent2(event, projectKey);
59538
59555
  } catch (error45) {
59539
59556
  console.warn("[hive_start] Failed to emit cell_status_changed event:", error45);
59540
59557
  }
@@ -59735,12 +59752,12 @@ var hive_sync = tool({
59735
59752
  pushSuccess = true;
59736
59753
  }
59737
59754
  try {
59738
- const event = createEvent("hive_synced", {
59755
+ const event = createEvent2("hive_synced", {
59739
59756
  project_key: projectKey,
59740
59757
  cells_synced: flushResult.cellsExported,
59741
59758
  push_success: pushSuccess
59742
59759
  });
59743
- await appendEvent(event, projectKey);
59760
+ await appendEvent2(event, projectKey);
59744
59761
  } catch (error45) {
59745
59762
  console.warn("[hive_sync] Failed to emit hive_synced event:", error45);
59746
59763
  }
@@ -61755,10 +61772,13 @@ var swarmmail_read_message = tool({
61755
61772
  }
61756
61773
  }
61757
61774
  });
61775
+ function normalizePath(path2) {
61776
+ return path2.replace(/\\([[\]()])/g, "$1");
61777
+ }
61758
61778
  var swarmmail_reserve = tool({
61759
- description: "Reserve file paths for exclusive editing. Prevents conflicts with other agents.",
61779
+ description: "Reserve file paths for exclusive editing. Prevents conflicts with other agents. " + "IMPORTANT: Do NOT escape brackets or parentheses - paths like app/(content)/[slug]/page.tsx work as-is.",
61760
61780
  args: {
61761
- paths: tool.schema.array(tool.schema.string()).describe("File paths or glob patterns to reserve"),
61781
+ paths: tool.schema.array(tool.schema.string()).transform((paths) => paths.map(normalizePath)).describe("File paths or glob patterns to reserve. Do NOT escape [ ] ( ) characters."),
61762
61782
  reason: tool.schema.string().optional().describe("Reason for reservation (e.g., bead ID)"),
61763
61783
  exclusive: tool.schema.boolean().optional().describe("Whether reservation is exclusive (default: true)"),
61764
61784
  ttl_seconds: tool.schema.number().optional().describe("Time-to-live in seconds (default: 3600)")
@@ -61770,10 +61790,11 @@ var swarmmail_reserve = tool({
61770
61790
  return JSON.stringify({ error: "Session not initialized. Call swarmmail_init first." }, null, 2);
61771
61791
  }
61772
61792
  try {
61793
+ const normalizedPaths = args.paths.map(normalizePath);
61773
61794
  const result = await reserveSwarmFiles({
61774
61795
  projectPath: state.projectKey,
61775
61796
  agentName: state.agentName,
61776
- paths: args.paths,
61797
+ paths: normalizedPaths,
61777
61798
  reason: args.reason,
61778
61799
  exclusive: args.exclusive ?? true,
61779
61800
  ttlSeconds: args.ttl_seconds
@@ -61801,9 +61822,9 @@ var swarmmail_reserve = tool({
61801
61822
  }
61802
61823
  });
61803
61824
  var swarmmail_release = tool({
61804
- description: "Release file reservations. Call when done editing files.",
61825
+ description: "Release file reservations. Call when done editing files. " + "Do NOT escape brackets or parentheses in paths.",
61805
61826
  args: {
61806
- paths: tool.schema.array(tool.schema.string()).optional().describe("Specific paths to release (releases all if omitted)"),
61827
+ paths: tool.schema.array(tool.schema.string()).optional().describe("Specific paths to release (releases all if omitted). Do NOT escape [ ] ( ) characters."),
61807
61828
  reservation_ids: tool.schema.array(tool.schema.number()).optional().describe("Specific reservation IDs to release")
61808
61829
  },
61809
61830
  async execute(args, ctx) {
@@ -61814,10 +61835,11 @@ var swarmmail_release = tool({
61814
61835
  }
61815
61836
  try {
61816
61837
  const currentReservations = await getActiveReservations(state.projectKey, state.projectKey, state.agentName);
61838
+ const normalizedPaths = args.paths?.map(normalizePath);
61817
61839
  const result = await releaseSwarmFiles({
61818
61840
  projectPath: state.projectKey,
61819
61841
  agentName: state.agentName,
61820
- paths: args.paths,
61842
+ paths: normalizedPaths,
61821
61843
  reservationIds: args.reservation_ids
61822
61844
  });
61823
61845
  if (!args.paths && !args.reservation_ids) {
@@ -64691,8 +64713,8 @@ import {
64691
64713
  releaseSwarmFiles as releaseSwarmFiles2,
64692
64714
  sendSwarmMessage as sendSwarmMessage3,
64693
64715
  getAgent,
64694
- createEvent as createEvent3,
64695
- appendEvent as appendEvent2,
64716
+ createEvent as createEvent4,
64717
+ appendEvent as appendEvent3,
64696
64718
  getSwarmMailLibSQL as getSwarmMailLibSQL4
64697
64719
  } from "swarm-mail";
64698
64720
  init_skills();
@@ -65197,15 +65219,15 @@ var swarm_review = tool({
65197
65219
  downstream_tasks: downstreamTasks.length > 0 ? downstreamTasks : undefined
65198
65220
  });
65199
65221
  try {
65200
- const { createEvent: createEvent3, appendEvent: appendEvent2 } = await import("swarm-mail");
65222
+ const { createEvent: createEvent4, appendEvent: appendEvent3 } = await import("swarm-mail");
65201
65223
  const attempt = getReviewStatus(args.task_id).attempt_count || 1;
65202
- const reviewStartedEvent = createEvent3("review_started", {
65224
+ const reviewStartedEvent = createEvent4("review_started", {
65203
65225
  project_key: args.project_key,
65204
65226
  epic_id: args.epic_id,
65205
65227
  bead_id: args.task_id,
65206
65228
  attempt
65207
65229
  });
65208
- await appendEvent2(reviewStartedEvent, args.project_key);
65230
+ await appendEvent3(reviewStartedEvent, args.project_key);
65209
65231
  } catch (error45) {
65210
65232
  console.warn("[swarm_review] Failed to emit ReviewStartedEvent:", error45);
65211
65233
  }
@@ -65288,16 +65310,16 @@ var swarm_review_feedback = tool({
65288
65310
  console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
65289
65311
  }
65290
65312
  try {
65291
- const { createEvent: createEvent3, appendEvent: appendEvent2 } = await import("swarm-mail");
65313
+ const { createEvent: createEvent4, appendEvent: appendEvent3 } = await import("swarm-mail");
65292
65314
  const attempt = getReviewStatus(args.task_id).attempt_count || 1;
65293
- const reviewCompletedEvent = createEvent3("review_completed", {
65315
+ const reviewCompletedEvent = createEvent4("review_completed", {
65294
65316
  project_key: args.project_key,
65295
65317
  epic_id: epicId,
65296
65318
  bead_id: args.task_id,
65297
65319
  status: "approved",
65298
65320
  attempt
65299
65321
  });
65300
- await appendEvent2(reviewCompletedEvent, args.project_key);
65322
+ await appendEvent3(reviewCompletedEvent, args.project_key);
65301
65323
  } catch (error45) {
65302
65324
  console.warn("[swarm_review_feedback] Failed to emit ReviewCompletedEvent:", error45);
65303
65325
  }
@@ -65359,16 +65381,16 @@ You may now complete the task with \`swarm_complete\`.`,
65359
65381
  console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
65360
65382
  }
65361
65383
  try {
65362
- const { createEvent: createEvent3, appendEvent: appendEvent2 } = await import("swarm-mail");
65384
+ const { createEvent: createEvent4, appendEvent: appendEvent3 } = await import("swarm-mail");
65363
65385
  const status = remaining <= 0 ? "blocked" : "needs_changes";
65364
- const reviewCompletedEvent = createEvent3("review_completed", {
65386
+ const reviewCompletedEvent = createEvent4("review_completed", {
65365
65387
  project_key: args.project_key,
65366
65388
  epic_id: epicId,
65367
65389
  bead_id: args.task_id,
65368
65390
  status,
65369
65391
  attempt: attemptNumber
65370
65392
  });
65371
- await appendEvent2(reviewCompletedEvent, args.project_key);
65393
+ await appendEvent3(reviewCompletedEvent, args.project_key);
65372
65394
  } catch (error45) {
65373
65395
  console.warn("[swarm_review_feedback] Failed to emit ReviewCompletedEvent:", error45);
65374
65396
  }
@@ -65426,8 +65448,200 @@ var reviewTools = {
65426
65448
  swarm_review_feedback
65427
65449
  };
65428
65450
 
65451
+ // src/utils/git-commit-info.ts
65452
+ import { execSync } from "child_process";
65453
+ function getGitCommitInfo(cwd) {
65454
+ try {
65455
+ const opts = { cwd, encoding: "utf-8", timeout: 5000 };
65456
+ const sha = execSync("git rev-parse HEAD", opts).trim();
65457
+ const message = execSync("git log -1 --format=%s", opts).trim();
65458
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", opts).trim();
65459
+ return { sha, message, branch };
65460
+ } catch {
65461
+ return null;
65462
+ }
65463
+ }
65464
+
65429
65465
  // src/swarm-orchestrate.ts
65430
65466
  init_eval_capture();
65467
+
65468
+ // src/swarm-verify.ts
65469
+ init_dist();
65470
+ async function runTypecheckVerification() {
65471
+ const step = {
65472
+ name: "typecheck",
65473
+ command: "tsc --noEmit",
65474
+ passed: false,
65475
+ exitCode: -1
65476
+ };
65477
+ try {
65478
+ const tsconfigExists = await Bun.file("tsconfig.json").exists();
65479
+ if (!tsconfigExists) {
65480
+ step.skipped = true;
65481
+ step.skipReason = "No tsconfig.json found";
65482
+ step.passed = true;
65483
+ return step;
65484
+ }
65485
+ const result = await Bun.$`tsc --noEmit`.quiet().nothrow();
65486
+ step.exitCode = result.exitCode;
65487
+ step.passed = result.exitCode === 0;
65488
+ if (!step.passed) {
65489
+ step.error = result.stderr.toString().slice(0, 1000);
65490
+ step.output = result.stdout.toString().slice(0, 1000);
65491
+ }
65492
+ } catch (error45) {
65493
+ step.skipped = true;
65494
+ step.skipReason = `tsc not available: ${error45 instanceof Error ? error45.message : String(error45)}`;
65495
+ step.passed = true;
65496
+ }
65497
+ return step;
65498
+ }
65499
+ async function runTestVerification(filesTouched) {
65500
+ const step = {
65501
+ name: "tests",
65502
+ command: "bun test <related-files>",
65503
+ passed: false,
65504
+ exitCode: -1
65505
+ };
65506
+ if (filesTouched.length === 0) {
65507
+ step.skipped = true;
65508
+ step.skipReason = "No files touched";
65509
+ step.passed = true;
65510
+ return step;
65511
+ }
65512
+ const testPatterns = [];
65513
+ for (const file2 of filesTouched) {
65514
+ if (file2.includes(".test.") || file2.includes(".spec.")) {
65515
+ testPatterns.push(file2);
65516
+ continue;
65517
+ }
65518
+ const baseName = file2.replace(/\.(ts|tsx|js|jsx)$/, "");
65519
+ testPatterns.push(`${baseName}.test.ts`);
65520
+ testPatterns.push(`${baseName}.test.tsx`);
65521
+ testPatterns.push(`${baseName}.spec.ts`);
65522
+ }
65523
+ const existingTests = [];
65524
+ for (const pattern of testPatterns) {
65525
+ try {
65526
+ const exists = await Bun.file(pattern).exists();
65527
+ if (exists) {
65528
+ existingTests.push(pattern);
65529
+ }
65530
+ } catch {}
65531
+ }
65532
+ if (existingTests.length === 0) {
65533
+ step.skipped = true;
65534
+ step.skipReason = "No related test files found";
65535
+ step.passed = true;
65536
+ return step;
65537
+ }
65538
+ try {
65539
+ step.command = `bun test ${existingTests.join(" ")}`;
65540
+ const result = await Bun.$`bun test ${existingTests}`.quiet().nothrow();
65541
+ step.exitCode = result.exitCode;
65542
+ step.passed = result.exitCode === 0;
65543
+ if (!step.passed) {
65544
+ step.error = result.stderr.toString().slice(0, 1000);
65545
+ step.output = result.stdout.toString().slice(0, 1000);
65546
+ }
65547
+ } catch (error45) {
65548
+ step.skipped = true;
65549
+ step.skipReason = `Test runner failed: ${error45 instanceof Error ? error45.message : String(error45)}`;
65550
+ step.passed = true;
65551
+ }
65552
+ return step;
65553
+ }
65554
+ async function runVerificationGate(filesTouched, _skipUbs = false) {
65555
+ const steps = [];
65556
+ const blockers = [];
65557
+ const typecheckStep = await runTypecheckVerification();
65558
+ steps.push(typecheckStep);
65559
+ if (!typecheckStep.passed && !typecheckStep.skipped) {
65560
+ blockers.push(`Typecheck failed: ${typecheckStep.error?.slice(0, 100) || "type errors found"}. Try: Run 'tsc --noEmit' to see full errors, check tsconfig.json configuration, or fix reported type errors in modified files.`);
65561
+ }
65562
+ const testStep = await runTestVerification(filesTouched);
65563
+ steps.push(testStep);
65564
+ if (!testStep.passed && !testStep.skipped) {
65565
+ blockers.push(`Tests failed: ${testStep.error?.slice(0, 100) || "test failures"}. Try: Run 'bun test ${testStep.command.split(" ").slice(2).join(" ")}' to see full output, check test assertions, or fix failing tests in modified files.`);
65566
+ }
65567
+ const passedCount = steps.filter((s) => s.passed).length;
65568
+ const skippedCount = steps.filter((s) => s.skipped).length;
65569
+ const failedCount = steps.filter((s) => !s.passed && !s.skipped).length;
65570
+ const summary = failedCount === 0 ? `Verification passed: ${passedCount} checks passed, ${skippedCount} skipped` : `Verification FAILED: ${failedCount} checks failed, ${passedCount} passed, ${skippedCount} skipped`;
65571
+ return {
65572
+ passed: failedCount === 0,
65573
+ steps,
65574
+ summary,
65575
+ blockers
65576
+ };
65577
+ }
65578
+ var swarm_verify = tool({
65579
+ description: "Run verification gate (typecheck + tests) for files. Returns verification results without blocking. Used by swarm_complete to verify worker output.",
65580
+ args: {
65581
+ files_touched: tool.schema.array(tool.schema.string()).describe("Files to verify (typecheck + test discovery)"),
65582
+ skip_verification: tool.schema.boolean().optional().describe("Skip verification entirely (default: false)")
65583
+ },
65584
+ async execute(args) {
65585
+ try {
65586
+ if (args.skip_verification) {
65587
+ return JSON.stringify({
65588
+ success: true,
65589
+ data: {
65590
+ passed: true,
65591
+ skipped: true,
65592
+ reason: "skip_verification=true",
65593
+ summary: "Verification skipped by request",
65594
+ steps: [],
65595
+ blockers: []
65596
+ }
65597
+ }, null, 2);
65598
+ }
65599
+ if (!args.files_touched || args.files_touched.length === 0) {
65600
+ return JSON.stringify({
65601
+ success: true,
65602
+ data: {
65603
+ passed: true,
65604
+ skipped: true,
65605
+ reason: "no files_touched provided",
65606
+ summary: "No files to verify",
65607
+ steps: [],
65608
+ blockers: []
65609
+ }
65610
+ }, null, 2);
65611
+ }
65612
+ const result = await runVerificationGate(args.files_touched, false);
65613
+ return JSON.stringify({
65614
+ success: true,
65615
+ data: {
65616
+ passed: result.passed,
65617
+ skipped: false,
65618
+ summary: result.summary,
65619
+ steps: result.steps.map((s) => ({
65620
+ name: s.name,
65621
+ command: s.command,
65622
+ passed: s.passed,
65623
+ exitCode: s.exitCode,
65624
+ skipped: s.skipped,
65625
+ skipReason: s.skipReason,
65626
+ error: s.error?.slice(0, 200),
65627
+ output: s.output?.slice(0, 200)
65628
+ })),
65629
+ blockers: result.blockers
65630
+ }
65631
+ }, null, 2);
65632
+ } catch (error45) {
65633
+ return JSON.stringify({
65634
+ success: false,
65635
+ error: `Verification failed: ${error45 instanceof Error ? error45.message : String(error45)}`
65636
+ }, null, 2);
65637
+ }
65638
+ }
65639
+ });
65640
+ var verificationTools = {
65641
+ swarm_verify
65642
+ };
65643
+
65644
+ // src/swarm-orchestrate.ts
65431
65645
  function generateWorkerHandoff(params) {
65432
65646
  const handoff = {
65433
65647
  contract: {
@@ -65569,114 +65783,6 @@ ${progress.blockers.map((b) => `- ${b}`).join(`
65569
65783
 
65570
65784
  `);
65571
65785
  }
65572
- async function runTypecheckVerification() {
65573
- const step = {
65574
- name: "typecheck",
65575
- command: "tsc --noEmit",
65576
- passed: false,
65577
- exitCode: -1
65578
- };
65579
- try {
65580
- const tsconfigExists = await Bun.file("tsconfig.json").exists();
65581
- if (!tsconfigExists) {
65582
- step.skipped = true;
65583
- step.skipReason = "No tsconfig.json found";
65584
- step.passed = true;
65585
- return step;
65586
- }
65587
- const result = await Bun.$`tsc --noEmit`.quiet().nothrow();
65588
- step.exitCode = result.exitCode;
65589
- step.passed = result.exitCode === 0;
65590
- if (!step.passed) {
65591
- step.error = result.stderr.toString().slice(0, 1000);
65592
- step.output = result.stdout.toString().slice(0, 1000);
65593
- }
65594
- } catch (error45) {
65595
- step.skipped = true;
65596
- step.skipReason = `tsc not available: ${error45 instanceof Error ? error45.message : String(error45)}`;
65597
- step.passed = true;
65598
- }
65599
- return step;
65600
- }
65601
- async function runTestVerification(filesTouched) {
65602
- const step = {
65603
- name: "tests",
65604
- command: "bun test <related-files>",
65605
- passed: false,
65606
- exitCode: -1
65607
- };
65608
- if (filesTouched.length === 0) {
65609
- step.skipped = true;
65610
- step.skipReason = "No files touched";
65611
- step.passed = true;
65612
- return step;
65613
- }
65614
- const testPatterns = [];
65615
- for (const file2 of filesTouched) {
65616
- if (file2.includes(".test.") || file2.includes(".spec.")) {
65617
- testPatterns.push(file2);
65618
- continue;
65619
- }
65620
- const baseName = file2.replace(/\.(ts|tsx|js|jsx)$/, "");
65621
- testPatterns.push(`${baseName}.test.ts`);
65622
- testPatterns.push(`${baseName}.test.tsx`);
65623
- testPatterns.push(`${baseName}.spec.ts`);
65624
- }
65625
- const existingTests = [];
65626
- for (const pattern of testPatterns) {
65627
- try {
65628
- const exists = await Bun.file(pattern).exists();
65629
- if (exists) {
65630
- existingTests.push(pattern);
65631
- }
65632
- } catch {}
65633
- }
65634
- if (existingTests.length === 0) {
65635
- step.skipped = true;
65636
- step.skipReason = "No related test files found";
65637
- step.passed = true;
65638
- return step;
65639
- }
65640
- try {
65641
- step.command = `bun test ${existingTests.join(" ")}`;
65642
- const result = await Bun.$`bun test ${existingTests}`.quiet().nothrow();
65643
- step.exitCode = result.exitCode;
65644
- step.passed = result.exitCode === 0;
65645
- if (!step.passed) {
65646
- step.error = result.stderr.toString().slice(0, 1000);
65647
- step.output = result.stdout.toString().slice(0, 1000);
65648
- }
65649
- } catch (error45) {
65650
- step.skipped = true;
65651
- step.skipReason = `Test runner failed: ${error45 instanceof Error ? error45.message : String(error45)}`;
65652
- step.passed = true;
65653
- }
65654
- return step;
65655
- }
65656
- async function runVerificationGate(filesTouched, _skipUbs = false) {
65657
- const steps = [];
65658
- const blockers = [];
65659
- const typecheckStep = await runTypecheckVerification();
65660
- steps.push(typecheckStep);
65661
- if (!typecheckStep.passed && !typecheckStep.skipped) {
65662
- blockers.push(`Typecheck failed: ${typecheckStep.error?.slice(0, 100) || "type errors found"}. Try: Run 'tsc --noEmit' to see full errors, check tsconfig.json configuration, or fix reported type errors in modified files.`);
65663
- }
65664
- const testStep = await runTestVerification(filesTouched);
65665
- steps.push(testStep);
65666
- if (!testStep.passed && !testStep.skipped) {
65667
- blockers.push(`Tests failed: ${testStep.error?.slice(0, 100) || "test failures"}. Try: Run 'bun test ${testStep.command.split(" ").slice(2).join(" ")}' to see full output, check test assertions, or fix failing tests in modified files.`);
65668
- }
65669
- const passedCount = steps.filter((s) => s.passed).length;
65670
- const skippedCount = steps.filter((s) => s.skipped).length;
65671
- const failedCount = steps.filter((s) => !s.passed && !s.skipped).length;
65672
- const summary = failedCount === 0 ? `Verification passed: ${passedCount} checks passed, ${skippedCount} skipped` : `Verification FAILED: ${failedCount} checks failed, ${passedCount} passed, ${skippedCount} skipped`;
65673
- return {
65674
- passed: failedCount === 0,
65675
- steps,
65676
- summary,
65677
- blockers
65678
- };
65679
- }
65680
65786
  function classifyFailure(error45) {
65681
65787
  const msg = (typeof error45 === "string" ? error45 : error45.message).toLowerCase();
65682
65788
  if (msg.includes("timeout"))
@@ -65938,15 +66044,15 @@ var swarm_progress = tool({
65938
66044
  }
65939
66045
  };
65940
66046
  const checkpointData = JSON.stringify(checkpoint);
65941
- const checkpointEvent = createEvent3("swarm_checkpointed", {
66047
+ const checkpointEvent = createEvent4("swarm_checkpointed", {
65942
66048
  project_key: args.project_key,
65943
66049
  ...checkpoint,
65944
66050
  checkpoint_size_bytes: Buffer.byteLength(checkpointData, "utf8"),
65945
66051
  trigger: "progress"
65946
66052
  });
65947
- await appendEvent2(checkpointEvent, args.project_key);
66053
+ await appendEvent3(checkpointEvent, args.project_key);
65948
66054
  const checkpointId = `ckpt-${Date.now()}-${args.bead_id}`;
65949
- const createdEvent = createEvent3("checkpoint_created", {
66055
+ const createdEvent = createEvent4("checkpoint_created", {
65950
66056
  project_key: args.project_key,
65951
66057
  epic_id: epicId,
65952
66058
  bead_id: args.bead_id,
@@ -65956,7 +66062,7 @@ var swarm_progress = tool({
65956
66062
  progress_percent: args.progress_percent,
65957
66063
  files_snapshot: args.files_touched
65958
66064
  });
65959
- await appendEvent2(createdEvent, args.project_key);
66065
+ await appendEvent3(createdEvent, args.project_key);
65960
66066
  checkpointCreated = true;
65961
66067
  } catch (error45) {
65962
66068
  console.warn(`[swarm_progress] Auto-checkpoint failed at ${args.progress_percent}%:`, error45);
@@ -66027,7 +66133,10 @@ var swarm_complete = tool({
66027
66133
  start_time: tool.schema.number().describe("Task start timestamp (Unix ms) for duration calculation - REQUIRED for accurate analytics"),
66028
66134
  error_count: tool.schema.number().optional().describe("Number of errors encountered during task"),
66029
66135
  retry_count: tool.schema.number().optional().describe("Number of retry attempts during task"),
66030
- skip_review: tool.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review.")
66136
+ skip_review: tool.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review."),
66137
+ commit_sha: tool.schema.string().optional().describe("Git commit SHA (auto-detected if not provided)"),
66138
+ commit_message: tool.schema.string().optional().describe("Commit message (auto-detected if not provided)"),
66139
+ commit_branch: tool.schema.string().optional().describe("Git branch (auto-detected if not provided)")
66031
66140
  },
66032
66141
  async execute(args, _ctx) {
66033
66142
  const missing = [];
@@ -66088,6 +66197,13 @@ var swarm_complete = tool({
66088
66197
  }, null, 2);
66089
66198
  }
66090
66199
  }
66200
+ const gitInfo = getGitCommitInfo(args.project_key) || {};
66201
+ const commitSha = args.commit_sha || gitInfo.sha;
66202
+ const commitMessage = args.commit_message || gitInfo.message;
66203
+ const commitBranch = args.commit_branch || gitInfo.branch;
66204
+ const resultText = commitSha ? `${args.summary}
66205
+
66206
+ Commit: ${commitSha.slice(0, 8)} (${commitBranch || "unknown"}) - ${commitMessage || "no message"}` : args.summary;
66091
66207
  try {
66092
66208
  const adapter = await getHiveAdapter(args.project_key);
66093
66209
  const cell = await adapter.getCell(args.project_key, args.bead_id);
@@ -66202,7 +66318,9 @@ This will be recorded as a negative learning signal.`;
66202
66318
  }
66203
66319
  }
66204
66320
  try {
66205
- await adapter.closeCell(args.project_key, args.bead_id, args.summary);
66321
+ await adapter.closeCell(args.project_key, args.bead_id, args.summary, {
66322
+ result: resultText
66323
+ });
66206
66324
  } catch (closeError) {
66207
66325
  const errorMessage = closeError instanceof Error ? closeError.message : String(closeError);
66208
66326
  return JSON.stringify({
@@ -66259,7 +66377,7 @@ This will be recorded as a negative learning signal.`;
66259
66377
  const eventEpicId = cell.parent_id || (args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id);
66260
66378
  let outcomeEventId;
66261
66379
  try {
66262
- const event = createEvent3("subtask_outcome", {
66380
+ const event = createEvent4("subtask_outcome", {
66263
66381
  project_key: args.project_key,
66264
66382
  epic_id: eventEpicId,
66265
66383
  bead_id: args.bead_id,
@@ -66270,9 +66388,10 @@ This will be recorded as a negative learning signal.`;
66270
66388
  retry_count: args.retry_count || 0,
66271
66389
  success: true,
66272
66390
  scope_violation: contractValidation ? !contractValidation.valid : undefined,
66273
- violation_files: contractValidation?.violations
66391
+ violation_files: contractValidation?.violations,
66392
+ commit: commitSha ? { sha: commitSha, message: commitMessage, branch: commitBranch } : undefined
66274
66393
  });
66275
- const savedEvent = await appendEvent2(event, args.project_key);
66394
+ const savedEvent = await appendEvent3(event, args.project_key);
66276
66395
  outcomeEventId = savedEvent.id;
66277
66396
  } catch (error45) {
66278
66397
  console.warn("[swarm_complete] Failed to emit SubtaskOutcomeEvent:", error45);
@@ -66290,7 +66409,7 @@ This will be recorded as a negative learning signal.`;
66290
66409
  }
66291
66410
  }
66292
66411
  try {
66293
- const workerCompletedEvent = createEvent3("worker_completed", {
66412
+ const workerCompletedEvent = createEvent4("worker_completed", {
66294
66413
  project_key: args.project_key,
66295
66414
  epic_id: eventEpicId,
66296
66415
  bead_id: args.bead_id,
@@ -66299,7 +66418,7 @@ This will be recorded as a negative learning signal.`;
66299
66418
  duration_ms: completionDurationMs,
66300
66419
  files_touched: args.files_touched || []
66301
66420
  });
66302
- await appendEvent2(workerCompletedEvent, args.project_key);
66421
+ await appendEvent3(workerCompletedEvent, args.project_key);
66303
66422
  } catch (error45) {
66304
66423
  console.warn("[swarm_complete] Failed to emit worker_completed event:", error45);
66305
66424
  }
@@ -66455,6 +66574,8 @@ This will be recorded as a negative learning signal.`;
66455
66574
  success: true,
66456
66575
  bead_id: args.bead_id,
66457
66576
  closed: true,
66577
+ result: resultText,
66578
+ commit: commitSha ? { sha: commitSha, message: commitMessage, branch: commitBranch } : undefined,
66458
66579
  reservations_released: reservationsReleased,
66459
66580
  reservations_released_count: reservationsReleasedCount,
66460
66581
  reservations_release_error: reservationsReleaseError,
@@ -67023,7 +67144,7 @@ var swarm_checkpoint = tool({
67023
67144
  }
67024
67145
  };
67025
67146
  const checkpointData = JSON.stringify(checkpoint);
67026
- const event = createEvent3("swarm_checkpointed", {
67147
+ const event = createEvent4("swarm_checkpointed", {
67027
67148
  project_key: args.project_key,
67028
67149
  epic_id: args.epic_id,
67029
67150
  bead_id: args.bead_id,
@@ -67035,7 +67156,7 @@ var swarm_checkpoint = tool({
67035
67156
  checkpoint_size_bytes: Buffer.byteLength(checkpointData, "utf8"),
67036
67157
  trigger: args.error_context ? "error" : "manual"
67037
67158
  });
67038
- await appendEvent2(event, args.project_key);
67159
+ await appendEvent3(event, args.project_key);
67039
67160
  const now = Date.now();
67040
67161
  return JSON.stringify({
67041
67162
  success: true,
@@ -67093,13 +67214,13 @@ var swarm_recover = tool({
67093
67214
  created_at: row.created_at,
67094
67215
  updated_at: row.updated_at
67095
67216
  };
67096
- const event = createEvent3("swarm_recovered", {
67217
+ const event = createEvent4("swarm_recovered", {
67097
67218
  project_key: args.project_key,
67098
67219
  epic_id: args.epic_id,
67099
67220
  bead_id: context.bead_id,
67100
67221
  recovered_from_checkpoint: context.recovery.last_checkpoint
67101
67222
  });
67102
- await appendEvent2(event, args.project_key);
67223
+ await appendEvent3(event, args.project_key);
67103
67224
  return JSON.stringify({
67104
67225
  found: true,
67105
67226
  context,
@@ -67520,6 +67641,27 @@ swarmmail_reserve(
67520
67641
 
67521
67642
  **Workers reserve their own files.** This prevents edit conflicts with other agents.
67522
67643
 
67644
+ ### ⚠️ CRITICAL: File Path Handling (Next.js/Special Characters)
67645
+
67646
+ **DO NOT escape brackets or parentheses in file paths!**
67647
+
67648
+ When working with Next.js App Router or any codebase with special characters in paths:
67649
+
67650
+ ❌ **WRONG** (will fail):
67651
+ \`\`\`
67652
+ Read: app/\\(content\\)/events/\\[slug\\]/page.tsx
67653
+ Glob: src/**/\\[id\\]/**/*.ts
67654
+ \`\`\`
67655
+
67656
+ ✅ **CORRECT** (use raw paths):
67657
+ \`\`\`
67658
+ Read: app/(content)/events/[slug]/page.tsx
67659
+ Glob: src/**/[id]/**/*.ts
67660
+ \`\`\`
67661
+
67662
+ **The Read and Glob tools handle special characters automatically.**
67663
+ Never add backslashes before \`[\`, \`]\`, \`(\`, or \`)\` in file paths.
67664
+
67523
67665
  ### Step 5: Do the Work (TDD MANDATORY)
67524
67666
 
67525
67667
  **Follow RED → GREEN → REFACTOR. No exceptions.**
@@ -68282,9 +68424,9 @@ var swarm_spawn_subtask = tool({
68282
68424
  }
68283
68425
  if (args2.project_path) {
68284
68426
  try {
68285
- const { createEvent: createEvent5, appendEvent: appendEvent4 } = await import("swarm-mail");
68427
+ const { createEvent: createEvent6, appendEvent: appendEvent5 } = await import("swarm-mail");
68286
68428
  const spawnOrder = 0;
68287
- const workerSpawnedEvent = createEvent5("worker_spawned", {
68429
+ const workerSpawnedEvent = createEvent6("worker_spawned", {
68288
68430
  project_key: args2.project_path,
68289
68431
  epic_id: args2.epic_id,
68290
68432
  bead_id: args2.bead_id,
@@ -68294,7 +68436,7 @@ var swarm_spawn_subtask = tool({
68294
68436
  spawn_order: spawnOrder,
68295
68437
  is_parallel: false
68296
68438
  });
68297
- await appendEvent4(workerSpawnedEvent, args2.project_path);
68439
+ await appendEvent5(workerSpawnedEvent, args2.project_path);
68298
68440
  } catch (error45) {
68299
68441
  console.warn("[swarm_spawn_subtask] Failed to emit WorkerSpawnedEvent:", error45);
68300
68442
  }
@@ -68992,7 +69134,8 @@ var swarmTools = {
68992
69134
  ...promptTools,
68993
69135
  ...orchestrateTools,
68994
69136
  ...researchTools,
68995
- ...adversarialReviewTools
69137
+ ...adversarialReviewTools,
69138
+ ...verificationTools
68996
69139
  };
68997
69140
 
68998
69141
  // src/repo-crawl.ts
@@ -70035,36 +70178,35 @@ var mandateTools = {
70035
70178
  // src/hivemind-tools.ts
70036
70179
  init_dist();
70037
70180
  init_esm();
70038
- init_memory();
70039
- init_memory();
70040
70181
  import {
70041
70182
  getSwarmMailLibSQL as getSwarmMailLibSQL6,
70042
- createEvent as createEvent5,
70043
70183
  SessionIndexer,
70044
70184
  syncMemories as syncMemories2,
70045
70185
  toSwarmDb as toSwarmDb2,
70046
70186
  makeOllamaLive as makeOllamaLive2
70047
70187
  } from "swarm-mail";
70188
+ init_memory();
70189
+ init_memory();
70048
70190
  import * as os2 from "node:os";
70049
70191
  import * as path3 from "node:path";
70050
70192
  import { join as join12 } from "node:path";
70051
- var cachedAdapter2 = null;
70193
+ var cachedAdapter = null;
70052
70194
  var cachedIndexer = null;
70053
- var cachedProjectPath2 = null;
70195
+ var cachedProjectPath = null;
70054
70196
  async function getMemoryAdapter2(projectPath) {
70055
70197
  const path4 = projectPath || process.cwd();
70056
- if (cachedAdapter2 && cachedProjectPath2 === path4) {
70057
- return cachedAdapter2;
70198
+ if (cachedAdapter && cachedProjectPath === path4) {
70199
+ return cachedAdapter;
70058
70200
  }
70059
70201
  const swarmMail = await getSwarmMailLibSQL6(path4);
70060
70202
  const dbAdapter = await swarmMail.getDatabase();
70061
- cachedAdapter2 = await createMemoryAdapter(dbAdapter);
70062
- cachedProjectPath2 = path4;
70063
- return cachedAdapter2;
70203
+ cachedAdapter = await createMemoryAdapter(dbAdapter);
70204
+ cachedProjectPath = path4;
70205
+ return cachedAdapter;
70064
70206
  }
70065
70207
  async function getSessionIndexer(projectPath) {
70066
70208
  const path4 = projectPath || process.cwd();
70067
- if (cachedIndexer && cachedProjectPath2 === path4) {
70209
+ if (cachedIndexer && cachedProjectPath === path4) {
70068
70210
  return cachedIndexer;
70069
70211
  }
70070
70212
  const swarmMail = await getSwarmMailLibSQL6(path4);
@@ -70075,20 +70217,13 @@ async function getSessionIndexer(projectPath) {
70075
70217
  ollamaModel: process.env.OLLAMA_MODEL || "mxbai-embed-large"
70076
70218
  });
70077
70219
  cachedIndexer = new SessionIndexer(db, ollamaLayer);
70078
- cachedProjectPath2 = path4;
70220
+ cachedProjectPath = path4;
70079
70221
  return cachedIndexer;
70080
70222
  }
70081
70223
  var getHivemindAdapter = getMemoryAdapter2;
70082
70224
  async function emitEvent(eventType, data) {
70083
- try {
70084
- const projectPath = cachedProjectPath2 || process.cwd();
70085
- const swarmMail = await getSwarmMailLibSQL6(projectPath);
70086
- const event = createEvent5(eventType, {
70087
- project_key: projectPath,
70088
- ...data
70089
- });
70090
- await swarmMail.appendEvent(event);
70091
- } catch {}
70225
+ const projectPath = cachedProjectPath || process.cwd();
70226
+ await safeEmitEvent(eventType, data, "hivemind", projectPath);
70092
70227
  }
70093
70228
  var AGENT_DIRECTORIES = [
70094
70229
  path3.join(os2.homedir(), ".config", "swarm-tools", "sessions"),
@@ -70131,6 +70266,15 @@ var hivemind_find = tool({
70131
70266
  fts: tool.schema.boolean().optional().describe("Use full-text search instead of vector search (default: false)")
70132
70267
  },
70133
70268
  async execute(args2, ctx) {
70269
+ if (!args2.query || typeof args2.query !== "string" || args2.query.trim() === "") {
70270
+ return JSON.stringify({
70271
+ success: false,
70272
+ error: {
70273
+ code: "VALIDATION_ERROR",
70274
+ message: "query parameter is required and must be a non-empty string"
70275
+ }
70276
+ });
70277
+ }
70134
70278
  const startTime = Date.now();
70135
70279
  const adapter = await getMemoryAdapter2();
70136
70280
  const result = await adapter.find(args2);
@@ -70251,7 +70395,7 @@ var hivemind_sync = tool({
70251
70395
  args: {},
70252
70396
  async execute(args2, ctx) {
70253
70397
  try {
70254
- const projectPath = cachedProjectPath2 || process.cwd();
70398
+ const projectPath = cachedProjectPath || process.cwd();
70255
70399
  const swarmMail = await getSwarmMailLibSQL6(projectPath);
70256
70400
  const dbAdapter = await swarmMail.getDatabase();
70257
70401
  const hiveDir = join12(projectPath, ".hive");
@@ -72074,13 +72218,17 @@ var AGENT_DIRECTORIES2 = [
72074
72218
  path4.join(os3.homedir(), ".local", "share", "Claude"),
72075
72219
  path4.join(os3.homedir(), ".aider")
72076
72220
  ];
72221
+ var sessionIndexerCache = new AdapterCache;
72077
72222
  async function getSessionIndexer2() {
72078
- const db = await getDb();
72079
- const ollamaLayer = makeOllamaLive3({
72080
- ollamaHost: process.env.OLLAMA_HOST || "http://localhost:11434",
72081
- ollamaModel: process.env.OLLAMA_MODEL || "mxbai-embed-large"
72223
+ const globalKey = "global-session-indexer";
72224
+ return sessionIndexerCache.get(globalKey, async () => {
72225
+ const db = await getDb();
72226
+ const ollamaLayer = makeOllamaLive3({
72227
+ ollamaHost: process.env.OLLAMA_HOST || "http://localhost:11434",
72228
+ ollamaModel: process.env.OLLAMA_MODEL || "mxbai-embed-large"
72229
+ });
72230
+ return new SessionIndexer2(db, ollamaLayer);
72082
72231
  });
72083
- return new SessionIndexer2(db, ollamaLayer);
72084
72232
  }
72085
72233
  async function emitEvent2(eventType, data) {
72086
72234
  try {