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/index.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,26 +46561,23 @@ 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
46573
  function resetMemoryCache() {
46538
- cachedAdapter = null;
46539
- cachedProjectPath = null;
46574
+ memoryAdapterCache.clear();
46540
46575
  }
46541
- 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, memoryTools;
46576
+ 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, memoryTools;
46542
46577
  var init_memory_tools = __esm(() => {
46543
46578
  init_dist();
46544
46579
  init_memory();
46580
+ memoryAdapterCache = new AdapterCache;
46545
46581
  semantic_memory_store = tool({
46546
46582
  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.",
46547
46583
  args: {
@@ -46558,9 +46594,9 @@ var init_memory_tools = __esm(() => {
46558
46594
  const adapter = await getMemoryAdapter();
46559
46595
  const result = await adapter.store(args2);
46560
46596
  try {
46561
- const projectKey = cachedProjectPath || process.cwd();
46597
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46562
46598
  const tags = args2.tags ? args2.tags.split(",").map((t) => t.trim()) : [];
46563
- const event = createEvent4("memory_stored", {
46599
+ const event = createEvent5("memory_stored", {
46564
46600
  project_key: projectKey,
46565
46601
  memory_id: result.id,
46566
46602
  content_preview: args2.information.slice(0, 100),
@@ -46568,7 +46604,7 @@ var init_memory_tools = __esm(() => {
46568
46604
  auto_tagged: args2.autoTag,
46569
46605
  collection: args2.collection
46570
46606
  });
46571
- await appendEvent3(event, projectKey);
46607
+ await appendEvent4(event, projectKey);
46572
46608
  } catch (error45) {
46573
46609
  console.warn("[semantic_memory_store] Failed to emit memory_stored event:", error45);
46574
46610
  }
@@ -46590,9 +46626,9 @@ var init_memory_tools = __esm(() => {
46590
46626
  const result = await adapter.find(args2);
46591
46627
  const duration3 = Date.now() - startTime;
46592
46628
  try {
46593
- const projectKey = cachedProjectPath || process.cwd();
46629
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46594
46630
  const topScore = result.results.length > 0 ? result.results[0].score : undefined;
46595
- const event = createEvent4("memory_found", {
46631
+ const event = createEvent5("memory_found", {
46596
46632
  project_key: projectKey,
46597
46633
  query: args2.query,
46598
46634
  result_count: result.results.length,
@@ -46600,7 +46636,7 @@ var init_memory_tools = __esm(() => {
46600
46636
  search_duration_ms: duration3,
46601
46637
  used_fts: args2.fts
46602
46638
  });
46603
- await appendEvent3(event, projectKey);
46639
+ await appendEvent4(event, projectKey);
46604
46640
  } catch (error45) {
46605
46641
  console.warn("[semantic_memory_find] Failed to emit memory_found event:", error45);
46606
46642
  }
@@ -46628,12 +46664,12 @@ var init_memory_tools = __esm(() => {
46628
46664
  const result = await adapter.remove(args2);
46629
46665
  if (result.success) {
46630
46666
  try {
46631
- const projectKey = cachedProjectPath || process.cwd();
46632
- const event = createEvent4("memory_deleted", {
46667
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46668
+ const event = createEvent5("memory_deleted", {
46633
46669
  project_key: projectKey,
46634
46670
  memory_id: args2.id
46635
46671
  });
46636
- await appendEvent3(event, projectKey);
46672
+ await appendEvent4(event, projectKey);
46637
46673
  } catch (error45) {
46638
46674
  console.warn("[semantic_memory_remove] Failed to emit memory_deleted event:", error45);
46639
46675
  }
@@ -46651,13 +46687,13 @@ var init_memory_tools = __esm(() => {
46651
46687
  const result = await adapter.validate(args2);
46652
46688
  if (result.success) {
46653
46689
  try {
46654
- const projectKey = cachedProjectPath || process.cwd();
46655
- const event = createEvent4("memory_validated", {
46690
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46691
+ const event = createEvent5("memory_validated", {
46656
46692
  project_key: projectKey,
46657
46693
  memory_id: args2.id,
46658
46694
  decay_reset: true
46659
46695
  });
46660
- await appendEvent3(event, projectKey);
46696
+ await appendEvent4(event, projectKey);
46661
46697
  } catch (error45) {
46662
46698
  console.warn("[semantic_memory_validate] Failed to emit memory_validated event:", error45);
46663
46699
  }
@@ -46710,14 +46746,14 @@ var init_memory_tools = __esm(() => {
46710
46746
  const adapter = await getMemoryAdapter();
46711
46747
  const result = await adapter.upsert(args2);
46712
46748
  try {
46713
- const projectKey = cachedProjectPath || process.cwd();
46714
- const event = createEvent4("memory_updated", {
46749
+ const projectKey = memoryAdapterCache.getCachedPath() || process.cwd();
46750
+ const event = createEvent5("memory_updated", {
46715
46751
  project_key: projectKey,
46716
46752
  memory_id: result.memoryId || "unknown",
46717
46753
  operation: result.operation,
46718
46754
  reason: result.reason
46719
46755
  });
46720
- await appendEvent3(event, projectKey);
46756
+ await appendEvent4(event, projectKey);
46721
46757
  } catch (error45) {
46722
46758
  console.warn("[semantic_memory_upsert] Failed to emit memory_updated event:", error45);
46723
46759
  }
@@ -58438,7 +58474,8 @@ var CellUpdateArgsSchema = exports_external.object({
58438
58474
  });
58439
58475
  var CellCloseArgsSchema = exports_external.object({
58440
58476
  id: exports_external.string(),
58441
- reason: exports_external.string().min(1, "Reason required")
58477
+ reason: exports_external.string().min(1, "Reason required"),
58478
+ result: exports_external.string().optional()
58442
58479
  });
58443
58480
  var CellQueryArgsSchema = exports_external.object({
58444
58481
  status: CellStatusSchema.optional(),
@@ -59040,7 +59077,24 @@ var createBeadEvent = createCellEvent;
59040
59077
  var isBeadEventType = isCellEventType;
59041
59078
  var getBeadIdFromEvent = getCellIdFromEvent;
59042
59079
  // src/hive.ts
59080
+ import { createEvent as createEvent2, appendEvent as appendEvent2 } from "swarm-mail";
59081
+
59082
+ // src/utils/event-utils.ts
59043
59083
  import { createEvent, appendEvent } from "swarm-mail";
59084
+ async function safeEmitEvent(eventType, data, toolName, projectPath) {
59085
+ try {
59086
+ const effectiveProjectPath = projectPath || process.cwd();
59087
+ const event = createEvent(eventType, {
59088
+ project_key: effectiveProjectPath,
59089
+ ...data
59090
+ });
59091
+ await appendEvent(event, effectiveProjectPath);
59092
+ } catch (error45) {
59093
+ console.warn(`[${toolName}] Failed to emit ${eventType} event:`, error45);
59094
+ }
59095
+ }
59096
+
59097
+ // src/hive.ts
59044
59098
  var hiveWorkingDirectory = null;
59045
59099
  function setHiveWorkingDirectory(directory) {
59046
59100
  hiveWorkingDirectory = directory;
@@ -59208,7 +59262,7 @@ async function importJsonlToPGLite(projectPath) {
59208
59262
  const status = cellData.status === "tombstone" ? "closed" : cellData.status;
59209
59263
  const isClosed = status === "closed";
59210
59264
  const closedAt = isClosed ? cellData.closed_at ? new Date(cellData.closed_at).getTime() : new Date(cellData.updated_at).getTime() : null;
59211
- await db.query(`INSERT INTO cells (
59265
+ await db.query(`INSERT INTO beads (
59212
59266
  id, project_key, type, status, title, description, priority,
59213
59267
  parent_id, assignee, created_at, updated_at, closed_at
59214
59268
  ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`, [
@@ -59349,20 +59403,14 @@ var hive_create = tool({
59349
59403
  parent_id: validated.parent_id
59350
59404
  });
59351
59405
  await adapter.markDirty(projectKey, cell.id);
59352
- try {
59353
- const event = createEvent("cell_created", {
59354
- project_key: projectKey,
59355
- cell_id: cell.id,
59356
- title: validated.title,
59357
- description: validated.description,
59358
- issue_type: validated.type || "task",
59359
- priority: validated.priority ?? 2,
59360
- parent_id: validated.parent_id
59361
- });
59362
- await appendEvent(event, projectKey);
59363
- } catch (error45) {
59364
- console.warn("[hive_create] Failed to emit cell_created event:", error45);
59365
- }
59406
+ await safeEmitEvent("cell_created", {
59407
+ cell_id: cell.id,
59408
+ title: validated.title,
59409
+ description: validated.description,
59410
+ issue_type: validated.type || "task",
59411
+ priority: validated.priority ?? 2,
59412
+ parent_id: validated.parent_id
59413
+ }, "hive_create", projectKey);
59366
59414
  const formatted = formatCellForOutput(cell);
59367
59415
  return JSON.stringify(formatted, null, 2);
59368
59416
  } catch (error45) {
@@ -59444,53 +59492,35 @@ var hive_create_epic = tool({
59444
59492
  subtasks: created.slice(1).map((c) => formatCellForOutput(c))
59445
59493
  };
59446
59494
  const effectiveProjectKey = args.project_key || projectKey;
59447
- try {
59448
- const epicCreatedEvent = createEvent("epic_created", {
59449
- project_key: effectiveProjectKey,
59450
- epic_id: epic.id,
59451
- title: validated.epic_title,
59452
- description: validated.epic_description,
59453
- subtask_count: validated.subtasks.length,
59454
- subtask_ids: created.slice(1).map((c) => c.id)
59455
- });
59456
- await appendEvent(epicCreatedEvent, effectiveProjectKey);
59457
- } catch (error45) {
59458
- console.warn("[hive_create_epic] Failed to emit epic_created event:", error45);
59459
- }
59460
- try {
59461
- const event = createEvent("decomposition_generated", {
59462
- project_key: effectiveProjectKey,
59463
- epic_id: epic.id,
59464
- task: args.task || validated.epic_title,
59465
- context: validated.epic_description,
59466
- strategy: args.strategy || "feature-based",
59467
- epic_title: validated.epic_title,
59468
- subtasks: validated.subtasks.map((st) => ({
59469
- title: st.title,
59470
- files: st.files || [],
59471
- priority: st.priority
59472
- })),
59473
- recovery_context: args.recovery_context
59474
- });
59475
- await appendEvent(event, effectiveProjectKey);
59476
- } catch (error45) {
59477
- console.warn("[hive_create_epic] Failed to emit DecompositionGeneratedEvent:", error45);
59478
- }
59479
- try {
59480
- const totalFiles = validated.subtasks.reduce((count, st) => count + (st.files?.length || 0), 0);
59481
- const swarmStartedEvent = createEvent("swarm_started", {
59482
- project_key: effectiveProjectKey,
59483
- epic_id: epic.id,
59484
- epic_title: validated.epic_title,
59485
- strategy: args.strategy || "feature-based",
59486
- subtask_count: validated.subtasks.length,
59487
- total_files: totalFiles,
59488
- coordinator_agent: "coordinator"
59489
- });
59490
- await appendEvent(swarmStartedEvent, effectiveProjectKey);
59491
- } catch (error45) {
59492
- console.warn("[hive_create_epic] Failed to emit SwarmStartedEvent:", error45);
59493
- }
59495
+ await safeEmitEvent("epic_created", {
59496
+ epic_id: epic.id,
59497
+ title: validated.epic_title,
59498
+ description: validated.epic_description,
59499
+ subtask_count: validated.subtasks.length,
59500
+ subtask_ids: created.slice(1).map((c) => c.id)
59501
+ }, "hive_create_epic", effectiveProjectKey);
59502
+ await safeEmitEvent("decomposition_generated", {
59503
+ epic_id: epic.id,
59504
+ task: args.task || validated.epic_title,
59505
+ context: validated.epic_description,
59506
+ strategy: args.strategy || "feature-based",
59507
+ epic_title: validated.epic_title,
59508
+ subtasks: validated.subtasks.map((st) => ({
59509
+ title: st.title,
59510
+ files: st.files || [],
59511
+ priority: st.priority
59512
+ })),
59513
+ recovery_context: args.recovery_context
59514
+ }, "hive_create_epic", effectiveProjectKey);
59515
+ const totalFiles = validated.subtasks.reduce((count, st) => count + (st.files?.length || 0), 0);
59516
+ await safeEmitEvent("swarm_started", {
59517
+ epic_id: epic.id,
59518
+ epic_title: validated.epic_title,
59519
+ strategy: args.strategy || "feature-based",
59520
+ subtask_count: validated.subtasks.length,
59521
+ total_files: totalFiles,
59522
+ coordinator_agent: "coordinator"
59523
+ }, "hive_create_epic", effectiveProjectKey);
59494
59524
  try {
59495
59525
  const { captureCoordinatorEvent: captureCoordinatorEvent2 } = await Promise.resolve().then(() => (init_eval_capture(), exports_eval_capture));
59496
59526
  const filesPerSubtask = {};
@@ -59621,23 +59651,17 @@ var hive_update = tool({
59621
59651
  cell = existingCell;
59622
59652
  }
59623
59653
  await adapter.markDirty(projectKey, cellId);
59624
- try {
59625
- const fieldsChanged = [];
59626
- if (validated.status)
59627
- fieldsChanged.push("status");
59628
- if (validated.description !== undefined)
59629
- fieldsChanged.push("description");
59630
- if (validated.priority !== undefined)
59631
- fieldsChanged.push("priority");
59632
- const event = createEvent("cell_updated", {
59633
- project_key: projectKey,
59634
- cell_id: cellId,
59635
- fields_changed: fieldsChanged
59636
- });
59637
- await appendEvent(event, projectKey);
59638
- } catch (error45) {
59639
- console.warn("[hive_update] Failed to emit cell_updated event:", error45);
59640
- }
59654
+ const fieldsChanged = [];
59655
+ if (validated.status)
59656
+ fieldsChanged.push("status");
59657
+ if (validated.description !== undefined)
59658
+ fieldsChanged.push("description");
59659
+ if (validated.priority !== undefined)
59660
+ fieldsChanged.push("priority");
59661
+ await safeEmitEvent("cell_updated", {
59662
+ cell_id: cellId,
59663
+ fields_changed: fieldsChanged
59664
+ }, "hive_update", projectKey);
59641
59665
  const formatted = formatCellForOutput(cell);
59642
59666
  return JSON.stringify(formatted, null, 2);
59643
59667
  } catch (error45) {
@@ -59656,7 +59680,8 @@ var hive_close = tool({
59656
59680
  description: "Close a cell with reason",
59657
59681
  args: {
59658
59682
  id: tool.schema.string().describe("Cell ID or partial hash"),
59659
- reason: tool.schema.string().describe("Completion reason")
59683
+ reason: tool.schema.string().describe("Completion reason"),
59684
+ result: tool.schema.string().optional().describe("Implementation summary - what was actually done (like a PR description)")
59660
59685
  },
59661
59686
  async execute(args, ctx) {
59662
59687
  const validated = CellCloseArgsSchema.parse(args);
@@ -59666,11 +59691,10 @@ var hive_close = tool({
59666
59691
  const cellId = await resolvePartialId(adapter, projectKey, validated.id) || validated.id;
59667
59692
  const cellBeforeClose = await adapter.getCell(projectKey, cellId);
59668
59693
  const isEpic = cellBeforeClose?.type === "epic";
59669
- const cell = await adapter.closeCell(projectKey, cellId, validated.reason);
59694
+ const cell = await adapter.closeCell(projectKey, cellId, validated.reason, validated.result ? { result: validated.result } : undefined);
59670
59695
  await adapter.markDirty(projectKey, cellId);
59671
59696
  if (isEpic && cellBeforeClose) {
59672
59697
  try {
59673
- const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
59674
59698
  const subtasks = await adapter.queryCells(projectKey, { parent_id: cellId });
59675
59699
  const completedSubtasks = subtasks.filter((st) => st.status === "closed");
59676
59700
  const failedSubtasks = subtasks.filter((st) => st.status === "blocked");
@@ -59708,8 +59732,7 @@ var hive_close = tool({
59708
59732
  } catch (error45) {
59709
59733
  console.warn("[hive_close] Failed to calculate duration:", error45);
59710
59734
  }
59711
- const swarmCompletedEvent = createEvent2("swarm_completed", {
59712
- project_key: projectKey,
59735
+ await safeEmitEvent("swarm_completed", {
59713
59736
  epic_id: cellId,
59714
59737
  epic_title: cellBeforeClose.title,
59715
59738
  success: failedSubtasks.length === 0,
@@ -59717,8 +59740,7 @@ var hive_close = tool({
59717
59740
  subtasks_completed: completedSubtasks.length,
59718
59741
  subtasks_failed: failedSubtasks.length,
59719
59742
  total_files_touched: totalFilesTouched
59720
- });
59721
- await appendEvent2(swarmCompletedEvent, projectKey);
59743
+ }, "hive_close", projectKey);
59722
59744
  try {
59723
59745
  const { runPostSwarmValidation: runPostSwarmValidation2 } = await Promise.resolve().then(() => (init_swarm_validation(), exports_swarm_validation));
59724
59746
  const { readEvents } = await import("swarm-mail");
@@ -59754,16 +59776,10 @@ var hive_close = tool({
59754
59776
  console.warn("[hive_close] Failed to emit SwarmCompletedEvent:", error45);
59755
59777
  }
59756
59778
  }
59757
- try {
59758
- const event = createEvent("cell_closed", {
59759
- project_key: projectKey,
59760
- cell_id: cellId,
59761
- reason: validated.reason
59762
- });
59763
- await appendEvent(event, projectKey);
59764
- } catch (error45) {
59765
- console.warn("[hive_close] Failed to emit cell_closed event:", error45);
59766
- }
59779
+ await safeEmitEvent("cell_closed", {
59780
+ cell_id: cellId,
59781
+ reason: validated.reason
59782
+ }, "hive_close", projectKey);
59767
59783
  return `Closed ${cell.id}: ${validated.reason}`;
59768
59784
  } catch (error45) {
59769
59785
  const message = error45 instanceof Error ? error45.message : String(error45);
@@ -59790,13 +59806,13 @@ var hive_start = tool({
59790
59806
  const cell = await adapter.changeCellStatus(projectKey, cellId, "in_progress");
59791
59807
  await adapter.markDirty(projectKey, cellId);
59792
59808
  try {
59793
- const event = createEvent("cell_status_changed", {
59809
+ const event = createEvent2("cell_status_changed", {
59794
59810
  project_key: projectKey,
59795
59811
  cell_id: cellId,
59796
59812
  old_status: "open",
59797
59813
  new_status: "in_progress"
59798
59814
  });
59799
- await appendEvent(event, projectKey);
59815
+ await appendEvent2(event, projectKey);
59800
59816
  } catch (error45) {
59801
59817
  console.warn("[hive_start] Failed to emit cell_status_changed event:", error45);
59802
59818
  }
@@ -59997,12 +60013,12 @@ var hive_sync = tool({
59997
60013
  pushSuccess = true;
59998
60014
  }
59999
60015
  try {
60000
- const event = createEvent("hive_synced", {
60016
+ const event = createEvent2("hive_synced", {
60001
60017
  project_key: projectKey,
60002
60018
  cells_synced: flushResult.cellsExported,
60003
60019
  push_success: pushSuccess
60004
60020
  });
60005
- await appendEvent(event, projectKey);
60021
+ await appendEvent2(event, projectKey);
60006
60022
  } catch (error45) {
60007
60023
  console.warn("[hive_sync] Failed to emit hive_synced event:", error45);
60008
60024
  }
@@ -62155,10 +62171,13 @@ var swarmmail_read_message = tool({
62155
62171
  }
62156
62172
  }
62157
62173
  });
62174
+ function normalizePath(path2) {
62175
+ return path2.replace(/\\([[\]()])/g, "$1");
62176
+ }
62158
62177
  var swarmmail_reserve = tool({
62159
- description: "Reserve file paths for exclusive editing. Prevents conflicts with other agents.",
62178
+ 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.",
62160
62179
  args: {
62161
- paths: tool.schema.array(tool.schema.string()).describe("File paths or glob patterns to reserve"),
62180
+ paths: tool.schema.array(tool.schema.string()).transform((paths) => paths.map(normalizePath)).describe("File paths or glob patterns to reserve. Do NOT escape [ ] ( ) characters."),
62162
62181
  reason: tool.schema.string().optional().describe("Reason for reservation (e.g., bead ID)"),
62163
62182
  exclusive: tool.schema.boolean().optional().describe("Whether reservation is exclusive (default: true)"),
62164
62183
  ttl_seconds: tool.schema.number().optional().describe("Time-to-live in seconds (default: 3600)")
@@ -62170,10 +62189,11 @@ var swarmmail_reserve = tool({
62170
62189
  return JSON.stringify({ error: "Session not initialized. Call swarmmail_init first." }, null, 2);
62171
62190
  }
62172
62191
  try {
62192
+ const normalizedPaths = args.paths.map(normalizePath);
62173
62193
  const result = await reserveSwarmFiles({
62174
62194
  projectPath: state.projectKey,
62175
62195
  agentName: state.agentName,
62176
- paths: args.paths,
62196
+ paths: normalizedPaths,
62177
62197
  reason: args.reason,
62178
62198
  exclusive: args.exclusive ?? true,
62179
62199
  ttlSeconds: args.ttl_seconds
@@ -62201,9 +62221,9 @@ var swarmmail_reserve = tool({
62201
62221
  }
62202
62222
  });
62203
62223
  var swarmmail_release = tool({
62204
- description: "Release file reservations. Call when done editing files.",
62224
+ description: "Release file reservations. Call when done editing files. " + "Do NOT escape brackets or parentheses in paths.",
62205
62225
  args: {
62206
- paths: tool.schema.array(tool.schema.string()).optional().describe("Specific paths to release (releases all if omitted)"),
62226
+ paths: tool.schema.array(tool.schema.string()).optional().describe("Specific paths to release (releases all if omitted). Do NOT escape [ ] ( ) characters."),
62207
62227
  reservation_ids: tool.schema.array(tool.schema.number()).optional().describe("Specific reservation IDs to release")
62208
62228
  },
62209
62229
  async execute(args, ctx) {
@@ -62214,10 +62234,11 @@ var swarmmail_release = tool({
62214
62234
  }
62215
62235
  try {
62216
62236
  const currentReservations = await getActiveReservations(state.projectKey, state.projectKey, state.agentName);
62237
+ const normalizedPaths = args.paths?.map(normalizePath);
62217
62238
  const result = await releaseSwarmFiles({
62218
62239
  projectPath: state.projectKey,
62219
62240
  agentName: state.agentName,
62220
- paths: args.paths,
62241
+ paths: normalizedPaths,
62221
62242
  reservationIds: args.reservation_ids
62222
62243
  });
62223
62244
  if (!args.paths && !args.reservation_ids) {
@@ -65110,8 +65131,8 @@ import {
65110
65131
  releaseSwarmFiles as releaseSwarmFiles2,
65111
65132
  sendSwarmMessage as sendSwarmMessage3,
65112
65133
  getAgent,
65113
- createEvent as createEvent3,
65114
- appendEvent as appendEvent2,
65134
+ createEvent as createEvent4,
65135
+ appendEvent as appendEvent3,
65115
65136
  getSwarmMailLibSQL as getSwarmMailLibSQL4
65116
65137
  } from "swarm-mail";
65117
65138
  init_skills();
@@ -65616,15 +65637,15 @@ var swarm_review = tool({
65616
65637
  downstream_tasks: downstreamTasks.length > 0 ? downstreamTasks : undefined
65617
65638
  });
65618
65639
  try {
65619
- const { createEvent: createEvent3, appendEvent: appendEvent2 } = await import("swarm-mail");
65640
+ const { createEvent: createEvent4, appendEvent: appendEvent3 } = await import("swarm-mail");
65620
65641
  const attempt = getReviewStatus(args.task_id).attempt_count || 1;
65621
- const reviewStartedEvent = createEvent3("review_started", {
65642
+ const reviewStartedEvent = createEvent4("review_started", {
65622
65643
  project_key: args.project_key,
65623
65644
  epic_id: args.epic_id,
65624
65645
  bead_id: args.task_id,
65625
65646
  attempt
65626
65647
  });
65627
- await appendEvent2(reviewStartedEvent, args.project_key);
65648
+ await appendEvent3(reviewStartedEvent, args.project_key);
65628
65649
  } catch (error45) {
65629
65650
  console.warn("[swarm_review] Failed to emit ReviewStartedEvent:", error45);
65630
65651
  }
@@ -65707,16 +65728,16 @@ var swarm_review_feedback = tool({
65707
65728
  console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
65708
65729
  }
65709
65730
  try {
65710
- const { createEvent: createEvent3, appendEvent: appendEvent2 } = await import("swarm-mail");
65731
+ const { createEvent: createEvent4, appendEvent: appendEvent3 } = await import("swarm-mail");
65711
65732
  const attempt = getReviewStatus(args.task_id).attempt_count || 1;
65712
- const reviewCompletedEvent = createEvent3("review_completed", {
65733
+ const reviewCompletedEvent = createEvent4("review_completed", {
65713
65734
  project_key: args.project_key,
65714
65735
  epic_id: epicId,
65715
65736
  bead_id: args.task_id,
65716
65737
  status: "approved",
65717
65738
  attempt
65718
65739
  });
65719
- await appendEvent2(reviewCompletedEvent, args.project_key);
65740
+ await appendEvent3(reviewCompletedEvent, args.project_key);
65720
65741
  } catch (error45) {
65721
65742
  console.warn("[swarm_review_feedback] Failed to emit ReviewCompletedEvent:", error45);
65722
65743
  }
@@ -65778,16 +65799,16 @@ You may now complete the task with \`swarm_complete\`.`,
65778
65799
  console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
65779
65800
  }
65780
65801
  try {
65781
- const { createEvent: createEvent3, appendEvent: appendEvent2 } = await import("swarm-mail");
65802
+ const { createEvent: createEvent4, appendEvent: appendEvent3 } = await import("swarm-mail");
65782
65803
  const status = remaining <= 0 ? "blocked" : "needs_changes";
65783
- const reviewCompletedEvent = createEvent3("review_completed", {
65804
+ const reviewCompletedEvent = createEvent4("review_completed", {
65784
65805
  project_key: args.project_key,
65785
65806
  epic_id: epicId,
65786
65807
  bead_id: args.task_id,
65787
65808
  status,
65788
65809
  attempt: attemptNumber
65789
65810
  });
65790
- await appendEvent2(reviewCompletedEvent, args.project_key);
65811
+ await appendEvent3(reviewCompletedEvent, args.project_key);
65791
65812
  } catch (error45) {
65792
65813
  console.warn("[swarm_review_feedback] Failed to emit ReviewCompletedEvent:", error45);
65793
65814
  }
@@ -65845,8 +65866,200 @@ var reviewTools = {
65845
65866
  swarm_review_feedback
65846
65867
  };
65847
65868
 
65869
+ // src/utils/git-commit-info.ts
65870
+ import { execSync } from "child_process";
65871
+ function getGitCommitInfo(cwd) {
65872
+ try {
65873
+ const opts = { cwd, encoding: "utf-8", timeout: 5000 };
65874
+ const sha = execSync("git rev-parse HEAD", opts).trim();
65875
+ const message = execSync("git log -1 --format=%s", opts).trim();
65876
+ const branch = execSync("git rev-parse --abbrev-ref HEAD", opts).trim();
65877
+ return { sha, message, branch };
65878
+ } catch {
65879
+ return null;
65880
+ }
65881
+ }
65882
+
65848
65883
  // src/swarm-orchestrate.ts
65849
65884
  init_eval_capture();
65885
+
65886
+ // src/swarm-verify.ts
65887
+ init_dist();
65888
+ async function runTypecheckVerification() {
65889
+ const step = {
65890
+ name: "typecheck",
65891
+ command: "tsc --noEmit",
65892
+ passed: false,
65893
+ exitCode: -1
65894
+ };
65895
+ try {
65896
+ const tsconfigExists = await Bun.file("tsconfig.json").exists();
65897
+ if (!tsconfigExists) {
65898
+ step.skipped = true;
65899
+ step.skipReason = "No tsconfig.json found";
65900
+ step.passed = true;
65901
+ return step;
65902
+ }
65903
+ const result = await Bun.$`tsc --noEmit`.quiet().nothrow();
65904
+ step.exitCode = result.exitCode;
65905
+ step.passed = result.exitCode === 0;
65906
+ if (!step.passed) {
65907
+ step.error = result.stderr.toString().slice(0, 1000);
65908
+ step.output = result.stdout.toString().slice(0, 1000);
65909
+ }
65910
+ } catch (error45) {
65911
+ step.skipped = true;
65912
+ step.skipReason = `tsc not available: ${error45 instanceof Error ? error45.message : String(error45)}`;
65913
+ step.passed = true;
65914
+ }
65915
+ return step;
65916
+ }
65917
+ async function runTestVerification(filesTouched) {
65918
+ const step = {
65919
+ name: "tests",
65920
+ command: "bun test <related-files>",
65921
+ passed: false,
65922
+ exitCode: -1
65923
+ };
65924
+ if (filesTouched.length === 0) {
65925
+ step.skipped = true;
65926
+ step.skipReason = "No files touched";
65927
+ step.passed = true;
65928
+ return step;
65929
+ }
65930
+ const testPatterns = [];
65931
+ for (const file2 of filesTouched) {
65932
+ if (file2.includes(".test.") || file2.includes(".spec.")) {
65933
+ testPatterns.push(file2);
65934
+ continue;
65935
+ }
65936
+ const baseName = file2.replace(/\.(ts|tsx|js|jsx)$/, "");
65937
+ testPatterns.push(`${baseName}.test.ts`);
65938
+ testPatterns.push(`${baseName}.test.tsx`);
65939
+ testPatterns.push(`${baseName}.spec.ts`);
65940
+ }
65941
+ const existingTests = [];
65942
+ for (const pattern of testPatterns) {
65943
+ try {
65944
+ const exists = await Bun.file(pattern).exists();
65945
+ if (exists) {
65946
+ existingTests.push(pattern);
65947
+ }
65948
+ } catch {}
65949
+ }
65950
+ if (existingTests.length === 0) {
65951
+ step.skipped = true;
65952
+ step.skipReason = "No related test files found";
65953
+ step.passed = true;
65954
+ return step;
65955
+ }
65956
+ try {
65957
+ step.command = `bun test ${existingTests.join(" ")}`;
65958
+ const result = await Bun.$`bun test ${existingTests}`.quiet().nothrow();
65959
+ step.exitCode = result.exitCode;
65960
+ step.passed = result.exitCode === 0;
65961
+ if (!step.passed) {
65962
+ step.error = result.stderr.toString().slice(0, 1000);
65963
+ step.output = result.stdout.toString().slice(0, 1000);
65964
+ }
65965
+ } catch (error45) {
65966
+ step.skipped = true;
65967
+ step.skipReason = `Test runner failed: ${error45 instanceof Error ? error45.message : String(error45)}`;
65968
+ step.passed = true;
65969
+ }
65970
+ return step;
65971
+ }
65972
+ async function runVerificationGate(filesTouched, _skipUbs = false) {
65973
+ const steps = [];
65974
+ const blockers = [];
65975
+ const typecheckStep = await runTypecheckVerification();
65976
+ steps.push(typecheckStep);
65977
+ if (!typecheckStep.passed && !typecheckStep.skipped) {
65978
+ 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.`);
65979
+ }
65980
+ const testStep = await runTestVerification(filesTouched);
65981
+ steps.push(testStep);
65982
+ if (!testStep.passed && !testStep.skipped) {
65983
+ 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.`);
65984
+ }
65985
+ const passedCount = steps.filter((s) => s.passed).length;
65986
+ const skippedCount = steps.filter((s) => s.skipped).length;
65987
+ const failedCount = steps.filter((s) => !s.passed && !s.skipped).length;
65988
+ const summary = failedCount === 0 ? `Verification passed: ${passedCount} checks passed, ${skippedCount} skipped` : `Verification FAILED: ${failedCount} checks failed, ${passedCount} passed, ${skippedCount} skipped`;
65989
+ return {
65990
+ passed: failedCount === 0,
65991
+ steps,
65992
+ summary,
65993
+ blockers
65994
+ };
65995
+ }
65996
+ var swarm_verify = tool({
65997
+ description: "Run verification gate (typecheck + tests) for files. Returns verification results without blocking. Used by swarm_complete to verify worker output.",
65998
+ args: {
65999
+ files_touched: tool.schema.array(tool.schema.string()).describe("Files to verify (typecheck + test discovery)"),
66000
+ skip_verification: tool.schema.boolean().optional().describe("Skip verification entirely (default: false)")
66001
+ },
66002
+ async execute(args) {
66003
+ try {
66004
+ if (args.skip_verification) {
66005
+ return JSON.stringify({
66006
+ success: true,
66007
+ data: {
66008
+ passed: true,
66009
+ skipped: true,
66010
+ reason: "skip_verification=true",
66011
+ summary: "Verification skipped by request",
66012
+ steps: [],
66013
+ blockers: []
66014
+ }
66015
+ }, null, 2);
66016
+ }
66017
+ if (!args.files_touched || args.files_touched.length === 0) {
66018
+ return JSON.stringify({
66019
+ success: true,
66020
+ data: {
66021
+ passed: true,
66022
+ skipped: true,
66023
+ reason: "no files_touched provided",
66024
+ summary: "No files to verify",
66025
+ steps: [],
66026
+ blockers: []
66027
+ }
66028
+ }, null, 2);
66029
+ }
66030
+ const result = await runVerificationGate(args.files_touched, false);
66031
+ return JSON.stringify({
66032
+ success: true,
66033
+ data: {
66034
+ passed: result.passed,
66035
+ skipped: false,
66036
+ summary: result.summary,
66037
+ steps: result.steps.map((s) => ({
66038
+ name: s.name,
66039
+ command: s.command,
66040
+ passed: s.passed,
66041
+ exitCode: s.exitCode,
66042
+ skipped: s.skipped,
66043
+ skipReason: s.skipReason,
66044
+ error: s.error?.slice(0, 200),
66045
+ output: s.output?.slice(0, 200)
66046
+ })),
66047
+ blockers: result.blockers
66048
+ }
66049
+ }, null, 2);
66050
+ } catch (error45) {
66051
+ return JSON.stringify({
66052
+ success: false,
66053
+ error: `Verification failed: ${error45 instanceof Error ? error45.message : String(error45)}`
66054
+ }, null, 2);
66055
+ }
66056
+ }
66057
+ });
66058
+ var verificationTools = {
66059
+ swarm_verify
66060
+ };
66061
+
66062
+ // src/swarm-orchestrate.ts
65850
66063
  function generateWorkerHandoff(params) {
65851
66064
  const handoff = {
65852
66065
  contract: {
@@ -65988,114 +66201,6 @@ ${progress.blockers.map((b) => `- ${b}`).join(`
65988
66201
 
65989
66202
  `);
65990
66203
  }
65991
- async function runTypecheckVerification() {
65992
- const step = {
65993
- name: "typecheck",
65994
- command: "tsc --noEmit",
65995
- passed: false,
65996
- exitCode: -1
65997
- };
65998
- try {
65999
- const tsconfigExists = await Bun.file("tsconfig.json").exists();
66000
- if (!tsconfigExists) {
66001
- step.skipped = true;
66002
- step.skipReason = "No tsconfig.json found";
66003
- step.passed = true;
66004
- return step;
66005
- }
66006
- const result = await Bun.$`tsc --noEmit`.quiet().nothrow();
66007
- step.exitCode = result.exitCode;
66008
- step.passed = result.exitCode === 0;
66009
- if (!step.passed) {
66010
- step.error = result.stderr.toString().slice(0, 1000);
66011
- step.output = result.stdout.toString().slice(0, 1000);
66012
- }
66013
- } catch (error45) {
66014
- step.skipped = true;
66015
- step.skipReason = `tsc not available: ${error45 instanceof Error ? error45.message : String(error45)}`;
66016
- step.passed = true;
66017
- }
66018
- return step;
66019
- }
66020
- async function runTestVerification(filesTouched) {
66021
- const step = {
66022
- name: "tests",
66023
- command: "bun test <related-files>",
66024
- passed: false,
66025
- exitCode: -1
66026
- };
66027
- if (filesTouched.length === 0) {
66028
- step.skipped = true;
66029
- step.skipReason = "No files touched";
66030
- step.passed = true;
66031
- return step;
66032
- }
66033
- const testPatterns = [];
66034
- for (const file2 of filesTouched) {
66035
- if (file2.includes(".test.") || file2.includes(".spec.")) {
66036
- testPatterns.push(file2);
66037
- continue;
66038
- }
66039
- const baseName = file2.replace(/\.(ts|tsx|js|jsx)$/, "");
66040
- testPatterns.push(`${baseName}.test.ts`);
66041
- testPatterns.push(`${baseName}.test.tsx`);
66042
- testPatterns.push(`${baseName}.spec.ts`);
66043
- }
66044
- const existingTests = [];
66045
- for (const pattern of testPatterns) {
66046
- try {
66047
- const exists = await Bun.file(pattern).exists();
66048
- if (exists) {
66049
- existingTests.push(pattern);
66050
- }
66051
- } catch {}
66052
- }
66053
- if (existingTests.length === 0) {
66054
- step.skipped = true;
66055
- step.skipReason = "No related test files found";
66056
- step.passed = true;
66057
- return step;
66058
- }
66059
- try {
66060
- step.command = `bun test ${existingTests.join(" ")}`;
66061
- const result = await Bun.$`bun test ${existingTests}`.quiet().nothrow();
66062
- step.exitCode = result.exitCode;
66063
- step.passed = result.exitCode === 0;
66064
- if (!step.passed) {
66065
- step.error = result.stderr.toString().slice(0, 1000);
66066
- step.output = result.stdout.toString().slice(0, 1000);
66067
- }
66068
- } catch (error45) {
66069
- step.skipped = true;
66070
- step.skipReason = `Test runner failed: ${error45 instanceof Error ? error45.message : String(error45)}`;
66071
- step.passed = true;
66072
- }
66073
- return step;
66074
- }
66075
- async function runVerificationGate(filesTouched, _skipUbs = false) {
66076
- const steps = [];
66077
- const blockers = [];
66078
- const typecheckStep = await runTypecheckVerification();
66079
- steps.push(typecheckStep);
66080
- if (!typecheckStep.passed && !typecheckStep.skipped) {
66081
- 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.`);
66082
- }
66083
- const testStep = await runTestVerification(filesTouched);
66084
- steps.push(testStep);
66085
- if (!testStep.passed && !testStep.skipped) {
66086
- 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.`);
66087
- }
66088
- const passedCount = steps.filter((s) => s.passed).length;
66089
- const skippedCount = steps.filter((s) => s.skipped).length;
66090
- const failedCount = steps.filter((s) => !s.passed && !s.skipped).length;
66091
- const summary = failedCount === 0 ? `Verification passed: ${passedCount} checks passed, ${skippedCount} skipped` : `Verification FAILED: ${failedCount} checks failed, ${passedCount} passed, ${skippedCount} skipped`;
66092
- return {
66093
- passed: failedCount === 0,
66094
- steps,
66095
- summary,
66096
- blockers
66097
- };
66098
- }
66099
66204
  function classifyFailure(error45) {
66100
66205
  const msg = (typeof error45 === "string" ? error45 : error45.message).toLowerCase();
66101
66206
  if (msg.includes("timeout"))
@@ -66357,15 +66462,15 @@ var swarm_progress = tool({
66357
66462
  }
66358
66463
  };
66359
66464
  const checkpointData = JSON.stringify(checkpoint);
66360
- const checkpointEvent = createEvent3("swarm_checkpointed", {
66465
+ const checkpointEvent = createEvent4("swarm_checkpointed", {
66361
66466
  project_key: args.project_key,
66362
66467
  ...checkpoint,
66363
66468
  checkpoint_size_bytes: Buffer.byteLength(checkpointData, "utf8"),
66364
66469
  trigger: "progress"
66365
66470
  });
66366
- await appendEvent2(checkpointEvent, args.project_key);
66471
+ await appendEvent3(checkpointEvent, args.project_key);
66367
66472
  const checkpointId = `ckpt-${Date.now()}-${args.bead_id}`;
66368
- const createdEvent = createEvent3("checkpoint_created", {
66473
+ const createdEvent = createEvent4("checkpoint_created", {
66369
66474
  project_key: args.project_key,
66370
66475
  epic_id: epicId,
66371
66476
  bead_id: args.bead_id,
@@ -66375,7 +66480,7 @@ var swarm_progress = tool({
66375
66480
  progress_percent: args.progress_percent,
66376
66481
  files_snapshot: args.files_touched
66377
66482
  });
66378
- await appendEvent2(createdEvent, args.project_key);
66483
+ await appendEvent3(createdEvent, args.project_key);
66379
66484
  checkpointCreated = true;
66380
66485
  } catch (error45) {
66381
66486
  console.warn(`[swarm_progress] Auto-checkpoint failed at ${args.progress_percent}%:`, error45);
@@ -66446,7 +66551,10 @@ var swarm_complete = tool({
66446
66551
  start_time: tool.schema.number().describe("Task start timestamp (Unix ms) for duration calculation - REQUIRED for accurate analytics"),
66447
66552
  error_count: tool.schema.number().optional().describe("Number of errors encountered during task"),
66448
66553
  retry_count: tool.schema.number().optional().describe("Number of retry attempts during task"),
66449
- skip_review: tool.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review.")
66554
+ skip_review: tool.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review."),
66555
+ commit_sha: tool.schema.string().optional().describe("Git commit SHA (auto-detected if not provided)"),
66556
+ commit_message: tool.schema.string().optional().describe("Commit message (auto-detected if not provided)"),
66557
+ commit_branch: tool.schema.string().optional().describe("Git branch (auto-detected if not provided)")
66450
66558
  },
66451
66559
  async execute(args, _ctx) {
66452
66560
  const missing = [];
@@ -66507,6 +66615,13 @@ var swarm_complete = tool({
66507
66615
  }, null, 2);
66508
66616
  }
66509
66617
  }
66618
+ const gitInfo = getGitCommitInfo(args.project_key) || {};
66619
+ const commitSha = args.commit_sha || gitInfo.sha;
66620
+ const commitMessage = args.commit_message || gitInfo.message;
66621
+ const commitBranch = args.commit_branch || gitInfo.branch;
66622
+ const resultText = commitSha ? `${args.summary}
66623
+
66624
+ Commit: ${commitSha.slice(0, 8)} (${commitBranch || "unknown"}) - ${commitMessage || "no message"}` : args.summary;
66510
66625
  try {
66511
66626
  const adapter = await getHiveAdapter(args.project_key);
66512
66627
  const cell = await adapter.getCell(args.project_key, args.bead_id);
@@ -66621,7 +66736,9 @@ This will be recorded as a negative learning signal.`;
66621
66736
  }
66622
66737
  }
66623
66738
  try {
66624
- await adapter.closeCell(args.project_key, args.bead_id, args.summary);
66739
+ await adapter.closeCell(args.project_key, args.bead_id, args.summary, {
66740
+ result: resultText
66741
+ });
66625
66742
  } catch (closeError) {
66626
66743
  const errorMessage = closeError instanceof Error ? closeError.message : String(closeError);
66627
66744
  return JSON.stringify({
@@ -66678,7 +66795,7 @@ This will be recorded as a negative learning signal.`;
66678
66795
  const eventEpicId = cell.parent_id || (args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id);
66679
66796
  let outcomeEventId;
66680
66797
  try {
66681
- const event = createEvent3("subtask_outcome", {
66798
+ const event = createEvent4("subtask_outcome", {
66682
66799
  project_key: args.project_key,
66683
66800
  epic_id: eventEpicId,
66684
66801
  bead_id: args.bead_id,
@@ -66689,9 +66806,10 @@ This will be recorded as a negative learning signal.`;
66689
66806
  retry_count: args.retry_count || 0,
66690
66807
  success: true,
66691
66808
  scope_violation: contractValidation ? !contractValidation.valid : undefined,
66692
- violation_files: contractValidation?.violations
66809
+ violation_files: contractValidation?.violations,
66810
+ commit: commitSha ? { sha: commitSha, message: commitMessage, branch: commitBranch } : undefined
66693
66811
  });
66694
- const savedEvent = await appendEvent2(event, args.project_key);
66812
+ const savedEvent = await appendEvent3(event, args.project_key);
66695
66813
  outcomeEventId = savedEvent.id;
66696
66814
  } catch (error45) {
66697
66815
  console.warn("[swarm_complete] Failed to emit SubtaskOutcomeEvent:", error45);
@@ -66709,7 +66827,7 @@ This will be recorded as a negative learning signal.`;
66709
66827
  }
66710
66828
  }
66711
66829
  try {
66712
- const workerCompletedEvent = createEvent3("worker_completed", {
66830
+ const workerCompletedEvent = createEvent4("worker_completed", {
66713
66831
  project_key: args.project_key,
66714
66832
  epic_id: eventEpicId,
66715
66833
  bead_id: args.bead_id,
@@ -66718,7 +66836,7 @@ This will be recorded as a negative learning signal.`;
66718
66836
  duration_ms: completionDurationMs,
66719
66837
  files_touched: args.files_touched || []
66720
66838
  });
66721
- await appendEvent2(workerCompletedEvent, args.project_key);
66839
+ await appendEvent3(workerCompletedEvent, args.project_key);
66722
66840
  } catch (error45) {
66723
66841
  console.warn("[swarm_complete] Failed to emit worker_completed event:", error45);
66724
66842
  }
@@ -66874,6 +66992,8 @@ This will be recorded as a negative learning signal.`;
66874
66992
  success: true,
66875
66993
  bead_id: args.bead_id,
66876
66994
  closed: true,
66995
+ result: resultText,
66996
+ commit: commitSha ? { sha: commitSha, message: commitMessage, branch: commitBranch } : undefined,
66877
66997
  reservations_released: reservationsReleased,
66878
66998
  reservations_released_count: reservationsReleasedCount,
66879
66999
  reservations_release_error: reservationsReleaseError,
@@ -67442,7 +67562,7 @@ var swarm_checkpoint = tool({
67442
67562
  }
67443
67563
  };
67444
67564
  const checkpointData = JSON.stringify(checkpoint);
67445
- const event = createEvent3("swarm_checkpointed", {
67565
+ const event = createEvent4("swarm_checkpointed", {
67446
67566
  project_key: args.project_key,
67447
67567
  epic_id: args.epic_id,
67448
67568
  bead_id: args.bead_id,
@@ -67454,7 +67574,7 @@ var swarm_checkpoint = tool({
67454
67574
  checkpoint_size_bytes: Buffer.byteLength(checkpointData, "utf8"),
67455
67575
  trigger: args.error_context ? "error" : "manual"
67456
67576
  });
67457
- await appendEvent2(event, args.project_key);
67577
+ await appendEvent3(event, args.project_key);
67458
67578
  const now = Date.now();
67459
67579
  return JSON.stringify({
67460
67580
  success: true,
@@ -67512,13 +67632,13 @@ var swarm_recover = tool({
67512
67632
  created_at: row.created_at,
67513
67633
  updated_at: row.updated_at
67514
67634
  };
67515
- const event = createEvent3("swarm_recovered", {
67635
+ const event = createEvent4("swarm_recovered", {
67516
67636
  project_key: args.project_key,
67517
67637
  epic_id: args.epic_id,
67518
67638
  bead_id: context.bead_id,
67519
67639
  recovered_from_checkpoint: context.recovery.last_checkpoint
67520
67640
  });
67521
- await appendEvent2(event, args.project_key);
67641
+ await appendEvent3(event, args.project_key);
67522
67642
  return JSON.stringify({
67523
67643
  found: true,
67524
67644
  context,
@@ -67939,6 +68059,27 @@ swarmmail_reserve(
67939
68059
 
67940
68060
  **Workers reserve their own files.** This prevents edit conflicts with other agents.
67941
68061
 
68062
+ ### ⚠️ CRITICAL: File Path Handling (Next.js/Special Characters)
68063
+
68064
+ **DO NOT escape brackets or parentheses in file paths!**
68065
+
68066
+ When working with Next.js App Router or any codebase with special characters in paths:
68067
+
68068
+ ❌ **WRONG** (will fail):
68069
+ \`\`\`
68070
+ Read: app/\\(content\\)/events/\\[slug\\]/page.tsx
68071
+ Glob: src/**/\\[id\\]/**/*.ts
68072
+ \`\`\`
68073
+
68074
+ ✅ **CORRECT** (use raw paths):
68075
+ \`\`\`
68076
+ Read: app/(content)/events/[slug]/page.tsx
68077
+ Glob: src/**/[id]/**/*.ts
68078
+ \`\`\`
68079
+
68080
+ **The Read and Glob tools handle special characters automatically.**
68081
+ Never add backslashes before \`[\`, \`]\`, \`(\`, or \`)\` in file paths.
68082
+
67942
68083
  ### Step 5: Do the Work (TDD MANDATORY)
67943
68084
 
67944
68085
  **Follow RED → GREEN → REFACTOR. No exceptions.**
@@ -68701,9 +68842,9 @@ var swarm_spawn_subtask = tool({
68701
68842
  }
68702
68843
  if (args2.project_path) {
68703
68844
  try {
68704
- const { createEvent: createEvent5, appendEvent: appendEvent4 } = await import("swarm-mail");
68845
+ const { createEvent: createEvent6, appendEvent: appendEvent5 } = await import("swarm-mail");
68705
68846
  const spawnOrder = 0;
68706
- const workerSpawnedEvent = createEvent5("worker_spawned", {
68847
+ const workerSpawnedEvent = createEvent6("worker_spawned", {
68707
68848
  project_key: args2.project_path,
68708
68849
  epic_id: args2.epic_id,
68709
68850
  bead_id: args2.bead_id,
@@ -68713,7 +68854,7 @@ var swarm_spawn_subtask = tool({
68713
68854
  spawn_order: spawnOrder,
68714
68855
  is_parallel: false
68715
68856
  });
68716
- await appendEvent4(workerSpawnedEvent, args2.project_path);
68857
+ await appendEvent5(workerSpawnedEvent, args2.project_path);
68717
68858
  } catch (error45) {
68718
68859
  console.warn("[swarm_spawn_subtask] Failed to emit WorkerSpawnedEvent:", error45);
68719
68860
  }
@@ -69411,7 +69552,8 @@ var swarmTools = {
69411
69552
  ...promptTools,
69412
69553
  ...orchestrateTools,
69413
69554
  ...researchTools,
69414
- ...adversarialReviewTools
69555
+ ...adversarialReviewTools,
69556
+ ...verificationTools
69415
69557
  };
69416
69558
 
69417
69559
  // src/repo-crawl.ts
@@ -70500,36 +70642,35 @@ var mandateTools = {
70500
70642
  // src/hivemind-tools.ts
70501
70643
  init_dist();
70502
70644
  init_esm();
70503
- init_memory();
70504
- init_memory();
70505
70645
  import {
70506
70646
  getSwarmMailLibSQL as getSwarmMailLibSQL6,
70507
- createEvent as createEvent5,
70508
70647
  SessionIndexer,
70509
70648
  syncMemories as syncMemories2,
70510
70649
  toSwarmDb as toSwarmDb2,
70511
70650
  makeOllamaLive as makeOllamaLive2
70512
70651
  } from "swarm-mail";
70652
+ init_memory();
70653
+ init_memory();
70513
70654
  import * as os2 from "node:os";
70514
70655
  import * as path3 from "node:path";
70515
70656
  import { join as join12 } from "node:path";
70516
- var cachedAdapter2 = null;
70657
+ var cachedAdapter = null;
70517
70658
  var cachedIndexer = null;
70518
- var cachedProjectPath2 = null;
70659
+ var cachedProjectPath = null;
70519
70660
  async function getMemoryAdapter2(projectPath) {
70520
70661
  const path4 = projectPath || process.cwd();
70521
- if (cachedAdapter2 && cachedProjectPath2 === path4) {
70522
- return cachedAdapter2;
70662
+ if (cachedAdapter && cachedProjectPath === path4) {
70663
+ return cachedAdapter;
70523
70664
  }
70524
70665
  const swarmMail = await getSwarmMailLibSQL6(path4);
70525
70666
  const dbAdapter = await swarmMail.getDatabase();
70526
- cachedAdapter2 = await createMemoryAdapter(dbAdapter);
70527
- cachedProjectPath2 = path4;
70528
- return cachedAdapter2;
70667
+ cachedAdapter = await createMemoryAdapter(dbAdapter);
70668
+ cachedProjectPath = path4;
70669
+ return cachedAdapter;
70529
70670
  }
70530
70671
  async function getSessionIndexer(projectPath) {
70531
70672
  const path4 = projectPath || process.cwd();
70532
- if (cachedIndexer && cachedProjectPath2 === path4) {
70673
+ if (cachedIndexer && cachedProjectPath === path4) {
70533
70674
  return cachedIndexer;
70534
70675
  }
70535
70676
  const swarmMail = await getSwarmMailLibSQL6(path4);
@@ -70540,20 +70681,13 @@ async function getSessionIndexer(projectPath) {
70540
70681
  ollamaModel: process.env.OLLAMA_MODEL || "mxbai-embed-large"
70541
70682
  });
70542
70683
  cachedIndexer = new SessionIndexer(db, ollamaLayer);
70543
- cachedProjectPath2 = path4;
70684
+ cachedProjectPath = path4;
70544
70685
  return cachedIndexer;
70545
70686
  }
70546
70687
  var getHivemindAdapter = getMemoryAdapter2;
70547
70688
  async function emitEvent(eventType, data) {
70548
- try {
70549
- const projectPath = cachedProjectPath2 || process.cwd();
70550
- const swarmMail = await getSwarmMailLibSQL6(projectPath);
70551
- const event = createEvent5(eventType, {
70552
- project_key: projectPath,
70553
- ...data
70554
- });
70555
- await swarmMail.appendEvent(event);
70556
- } catch {}
70689
+ const projectPath = cachedProjectPath || process.cwd();
70690
+ await safeEmitEvent(eventType, data, "hivemind", projectPath);
70557
70691
  }
70558
70692
  var AGENT_DIRECTORIES = [
70559
70693
  path3.join(os2.homedir(), ".config", "swarm-tools", "sessions"),
@@ -70596,6 +70730,15 @@ var hivemind_find = tool({
70596
70730
  fts: tool.schema.boolean().optional().describe("Use full-text search instead of vector search (default: false)")
70597
70731
  },
70598
70732
  async execute(args2, ctx) {
70733
+ if (!args2.query || typeof args2.query !== "string" || args2.query.trim() === "") {
70734
+ return JSON.stringify({
70735
+ success: false,
70736
+ error: {
70737
+ code: "VALIDATION_ERROR",
70738
+ message: "query parameter is required and must be a non-empty string"
70739
+ }
70740
+ });
70741
+ }
70599
70742
  const startTime = Date.now();
70600
70743
  const adapter = await getMemoryAdapter2();
70601
70744
  const result = await adapter.find(args2);
@@ -70716,7 +70859,7 @@ var hivemind_sync = tool({
70716
70859
  args: {},
70717
70860
  async execute(args2, ctx) {
70718
70861
  try {
70719
- const projectPath = cachedProjectPath2 || process.cwd();
70862
+ const projectPath = cachedProjectPath || process.cwd();
70720
70863
  const swarmMail = await getSwarmMailLibSQL6(projectPath);
70721
70864
  const dbAdapter = await swarmMail.getDatabase();
70722
70865
  const hiveDir = join12(projectPath, ".hive");
@@ -72951,13 +73094,17 @@ var AGENT_DIRECTORIES2 = [
72951
73094
  path5.join(os3.homedir(), ".local", "share", "Claude"),
72952
73095
  path5.join(os3.homedir(), ".aider")
72953
73096
  ];
73097
+ var sessionIndexerCache = new AdapterCache;
72954
73098
  async function getSessionIndexer2() {
72955
- const db = await getDb();
72956
- const ollamaLayer = makeOllamaLive3({
72957
- ollamaHost: process.env.OLLAMA_HOST || "http://localhost:11434",
72958
- ollamaModel: process.env.OLLAMA_MODEL || "mxbai-embed-large"
73099
+ const globalKey = "global-session-indexer";
73100
+ return sessionIndexerCache.get(globalKey, async () => {
73101
+ const db = await getDb();
73102
+ const ollamaLayer = makeOllamaLive3({
73103
+ ollamaHost: process.env.OLLAMA_HOST || "http://localhost:11434",
73104
+ ollamaModel: process.env.OLLAMA_MODEL || "mxbai-embed-large"
73105
+ });
73106
+ return new SessionIndexer2(db, ollamaLayer);
72959
73107
  });
72960
- return new SessionIndexer2(db, ollamaLayer);
72961
73108
  }
72962
73109
  async function emitEvent2(eventType, data) {
72963
73110
  try {