opencode-swarm-plugin 0.57.6 → 0.58.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/swarm.js CHANGED
@@ -27719,14 +27719,17 @@ class FlushManager {
27719
27719
  outputPath;
27720
27720
  debounceMs;
27721
27721
  onFlush;
27722
+ onError;
27722
27723
  timer = null;
27723
27724
  flushing = false;
27725
+ lastError = null;
27724
27726
  constructor(options2) {
27725
27727
  this.adapter = options2.adapter;
27726
27728
  this.projectKey = options2.projectKey;
27727
27729
  this.outputPath = options2.outputPath;
27728
27730
  this.debounceMs = options2.debounceMs ?? 30000;
27729
27731
  this.onFlush = options2.onFlush;
27732
+ this.onError = options2.onError;
27730
27733
  }
27731
27734
  scheduleFlush() {
27732
27735
  if (this.timer) {
@@ -27734,7 +27737,11 @@ class FlushManager {
27734
27737
  }
27735
27738
  this.timer = setTimeout(() => {
27736
27739
  this.flush().catch((err) => {
27740
+ this.lastError = err instanceof Error ? err : new Error(String(err));
27737
27741
  console.error("[FlushManager] Flush error:", err);
27742
+ if (this.onError) {
27743
+ this.onError(this.lastError);
27744
+ }
27738
27745
  });
27739
27746
  }, this.debounceMs);
27740
27747
  }
@@ -27796,6 +27803,15 @@ class FlushManager {
27796
27803
  this.flushing = false;
27797
27804
  }
27798
27805
  }
27806
+ hasError() {
27807
+ return this.lastError !== null;
27808
+ }
27809
+ getLastError() {
27810
+ return this.lastError;
27811
+ }
27812
+ clearError() {
27813
+ this.lastError = null;
27814
+ }
27799
27815
  stop() {
27800
27816
  if (this.timer) {
27801
27817
  clearTimeout(this.timer);
@@ -144240,14 +144256,17 @@ class FlushManager2 {
144240
144256
  outputPath;
144241
144257
  debounceMs;
144242
144258
  onFlush;
144259
+ onError;
144243
144260
  timer = null;
144244
144261
  flushing = false;
144262
+ lastError = null;
144245
144263
  constructor(options2) {
144246
144264
  this.adapter = options2.adapter;
144247
144265
  this.projectKey = options2.projectKey;
144248
144266
  this.outputPath = options2.outputPath;
144249
144267
  this.debounceMs = options2.debounceMs ?? 30000;
144250
144268
  this.onFlush = options2.onFlush;
144269
+ this.onError = options2.onError;
144251
144270
  }
144252
144271
  scheduleFlush() {
144253
144272
  if (this.timer) {
@@ -144255,7 +144274,11 @@ class FlushManager2 {
144255
144274
  }
144256
144275
  this.timer = setTimeout(() => {
144257
144276
  this.flush().catch((err) => {
144277
+ this.lastError = err instanceof Error ? err : new Error(String(err));
144258
144278
  console.error("[FlushManager] Flush error:", err);
144279
+ if (this.onError) {
144280
+ this.onError(this.lastError);
144281
+ }
144259
144282
  });
144260
144283
  }, this.debounceMs);
144261
144284
  }
@@ -144317,6 +144340,15 @@ class FlushManager2 {
144317
144340
  this.flushing = false;
144318
144341
  }
144319
144342
  }
144343
+ hasError() {
144344
+ return this.lastError !== null;
144345
+ }
144346
+ getLastError() {
144347
+ return this.lastError;
144348
+ }
144349
+ clearError() {
144350
+ this.lastError = null;
144351
+ }
144320
144352
  stop() {
144321
144353
  if (this.timer) {
144322
144354
  clearTimeout(this.timer);
@@ -278218,13 +278250,13 @@ Scripts run in the skill's directory with the project directory as an argument.`
278218
278250
  }
278219
278251
  const scriptPath = join47(skill.directory, "scripts", args5.script);
278220
278252
  const scriptArgs = args5.args || [];
278253
+ const TIMEOUT_MS = 60000;
278254
+ const proc = Bun.spawn([scriptPath, skillsProjectDirectory2, ...scriptArgs], {
278255
+ cwd: skill.directory,
278256
+ stdout: "pipe",
278257
+ stderr: "pipe"
278258
+ });
278221
278259
  try {
278222
- const TIMEOUT_MS = 60000;
278223
- const proc = Bun.spawn([scriptPath, skillsProjectDirectory2, ...scriptArgs], {
278224
- cwd: skill.directory,
278225
- stdout: "pipe",
278226
- stderr: "pipe"
278227
- });
278228
278260
  const timeoutPromise = new Promise((resolve9) => {
278229
278261
  setTimeout(() => resolve9({ timedOut: true }), TIMEOUT_MS);
278230
278262
  });
@@ -278238,7 +278270,6 @@ Scripts run in the skill's directory with the project directory as an argument.`
278238
278270
  })();
278239
278271
  const result = await Promise.race([resultPromise, timeoutPromise]);
278240
278272
  if (result.timedOut) {
278241
- proc.kill();
278242
278273
  return `Script timed out after ${TIMEOUT_MS / 1000} seconds.`;
278243
278274
  }
278244
278275
  const output = result.stdout + result.stderr;
@@ -278250,6 +278281,8 @@ ${output}`;
278250
278281
  }
278251
278282
  } catch (error56) {
278252
278283
  return `Failed to execute script: ${error56 instanceof Error ? error56.message : String(error56)}`;
278284
+ } finally {
278285
+ proc.kill();
278253
278286
  }
278254
278287
  }
278255
278288
  });
@@ -279152,9 +279185,11 @@ async function execSemanticMemory2(args5) {
279152
279185
  stderr: "pipe"
279153
279186
  });
279154
279187
  try {
279188
+ const TIMEOUT_MS = 30000;
279189
+ const timeoutPromise = new Promise((_, reject4) => setTimeout(() => reject4(new Error("Process timed out after 30s")), TIMEOUT_MS));
279155
279190
  const stdout = Buffer.from(await new Response(proc.stdout).arrayBuffer());
279156
279191
  const stderr = Buffer.from(await new Response(proc.stderr).arrayBuffer());
279157
- const exitCode = await proc.exited;
279192
+ const exitCode = await Promise.race([proc.exited, timeoutPromise]);
279158
279193
  return { exitCode, stdout, stderr };
279159
279194
  } finally {
279160
279195
  proc.kill();
@@ -305134,12 +305169,16 @@ async function runGitCommand(args2) {
305134
305169
  stdout: "pipe",
305135
305170
  stderr: "pipe"
305136
305171
  });
305137
- const [stdout, stderr] = await Promise.all([
305138
- new Response(proc.stdout).text(),
305139
- new Response(proc.stderr).text()
305140
- ]);
305141
- const exitCode = await proc.exited;
305142
- return { exitCode, stdout, stderr };
305172
+ try {
305173
+ const [stdout, stderr] = await Promise.all([
305174
+ new Response(proc.stdout).text(),
305175
+ new Response(proc.stderr).text()
305176
+ ]);
305177
+ const exitCode = await proc.exited;
305178
+ return { exitCode, stdout, stderr };
305179
+ } finally {
305180
+ proc.kill();
305181
+ }
305143
305182
  }
305144
305183
 
305145
305184
  class HiveError extends Error {
@@ -305430,9 +305469,9 @@ var hive_create = tool({
305430
305469
  }
305431
305470
  });
305432
305471
  var hive_create_epic = tool({
305433
- description: "Create epic with subtasks in one atomic operation",
305472
+ description: "Create epic with subtasks atomically. REQUIRED: epic_title, subtasks (array with {title, files?}). Use after swarm_validate_decomposition confirms your decomposition is valid. Each subtask should list files it will modify to enable parallel work without conflicts.",
305434
305473
  args: {
305435
- epic_title: tool.schema.string().describe("Epic title"),
305474
+ epic_title: tool.schema.string().describe("Epic title (e.g., 'Implement user auth')"),
305436
305475
  epic_description: tool.schema.string().optional().describe("Epic description"),
305437
305476
  epic_id: tool.schema.string().optional().describe("Custom ID for the epic (e.g., 'phase-0')"),
305438
305477
  subtasks: tool.schema.array(tool.schema.object({
@@ -305451,6 +305490,28 @@ var hive_create_epic = tool({
305451
305490
  }).optional().describe("Recovery context from checkpoint compaction")
305452
305491
  },
305453
305492
  async execute(args2, ctx) {
305493
+ const missing = [];
305494
+ if (!args2.epic_title)
305495
+ missing.push("epic_title");
305496
+ if (!args2.subtasks || args2.subtasks.length === 0)
305497
+ missing.push("subtasks (array of subtask objects)");
305498
+ if (missing.length > 0) {
305499
+ return JSON.stringify({
305500
+ success: false,
305501
+ error: `Missing required parameters: ${missing.join(", ")}`,
305502
+ hint: "hive_create_epic creates an epic with subtasks atomically.",
305503
+ example: {
305504
+ epic_title: "Implement user authentication",
305505
+ epic_description: "Add login, logout, and session management",
305506
+ subtasks: [
305507
+ { title: "Create auth service", files: ["src/auth/service.ts"] },
305508
+ { title: "Add login endpoint", files: ["src/api/login.ts"] },
305509
+ { title: "Add session middleware", files: ["src/middleware/session.ts"] }
305510
+ ]
305511
+ },
305512
+ tip: "Each subtask should have a title and optionally files it will modify. This helps with file reservation and parallel execution."
305513
+ }, null, 2);
305514
+ }
305454
305515
  const validated = EpicCreateArgsSchema.parse(args2);
305455
305516
  const projectKey = getHiveWorkingDirectory();
305456
305517
  const adapter5 = await getHiveAdapter(projectKey);
@@ -324176,13 +324237,13 @@ Scripts run in the skill's directory with the project directory as an argument.`
324176
324237
  }
324177
324238
  const scriptPath = join33(skill.directory, "scripts", args2.script);
324178
324239
  const scriptArgs = args2.args || [];
324240
+ const TIMEOUT_MS = 60000;
324241
+ const proc = Bun.spawn([scriptPath, skillsProjectDirectory, ...scriptArgs], {
324242
+ cwd: skill.directory,
324243
+ stdout: "pipe",
324244
+ stderr: "pipe"
324245
+ });
324179
324246
  try {
324180
- const TIMEOUT_MS = 60000;
324181
- const proc = Bun.spawn([scriptPath, skillsProjectDirectory, ...scriptArgs], {
324182
- cwd: skill.directory,
324183
- stdout: "pipe",
324184
- stderr: "pipe"
324185
- });
324186
324247
  const timeoutPromise = new Promise((resolve23) => {
324187
324248
  setTimeout(() => resolve23({ timedOut: true }), TIMEOUT_MS);
324188
324249
  });
@@ -324196,7 +324257,6 @@ Scripts run in the skill's directory with the project directory as an argument.`
324196
324257
  })();
324197
324258
  const result = await Promise.race([resultPromise, timeoutPromise]);
324198
324259
  if (result.timedOut) {
324199
- proc.kill();
324200
324260
  return `Script timed out after ${TIMEOUT_MS / 1000} seconds.`;
324201
324261
  }
324202
324262
  const output = result.stdout + result.stderr;
@@ -324208,6 +324268,8 @@ ${output}`;
324208
324268
  }
324209
324269
  } catch (error452) {
324210
324270
  return `Failed to execute script: ${error452 instanceof Error ? error452.message : String(error452)}`;
324271
+ } finally {
324272
+ proc.kill();
324211
324273
  }
324212
324274
  }
324213
324275
  });
@@ -325114,9 +325176,11 @@ async function execSemanticMemory(args2) {
325114
325176
  stderr: "pipe"
325115
325177
  });
325116
325178
  try {
325179
+ const TIMEOUT_MS = 30000;
325180
+ const timeoutPromise = new Promise((_, reject3) => setTimeout(() => reject3(new Error("Process timed out after 30s")), TIMEOUT_MS));
325117
325181
  const stdout = Buffer.from(await new Response(proc.stdout).arrayBuffer());
325118
325182
  const stderr = Buffer.from(await new Response(proc.stderr).arrayBuffer());
325119
- const exitCode = await proc.exited;
325183
+ const exitCode = await Promise.race([proc.exited, timeoutPromise]);
325120
325184
  return { exitCode, stdout, stderr };
325121
325185
  } finally {
325122
325186
  proc.kill();
@@ -347714,13 +347778,17 @@ var toolCheckers = {
347714
347778
  stderr: "pipe"
347715
347779
  });
347716
347780
  const timeout7 = setTimeout(() => proc.kill(), BUNX_TIMEOUT_MS);
347717
- const exitCode = await proc.exited;
347718
- clearTimeout(timeout7);
347719
- return {
347720
- available: exitCode === 0,
347721
- checkedAt: new Date().toISOString(),
347722
- version: "bunx"
347723
- };
347781
+ try {
347782
+ const exitCode = await proc.exited;
347783
+ return {
347784
+ available: exitCode === 0,
347785
+ checkedAt: new Date().toISOString(),
347786
+ version: "bunx"
347787
+ };
347788
+ } finally {
347789
+ clearTimeout(timeout7);
347790
+ proc.kill();
347791
+ }
347724
347792
  } catch (e) {
347725
347793
  return {
347726
347794
  available: false,
@@ -347793,13 +347861,17 @@ var toolCheckers = {
347793
347861
  stderr: "pipe"
347794
347862
  });
347795
347863
  const timeout7 = setTimeout(() => proc.kill(), BUNX_TIMEOUT_MS);
347796
- const exitCode = await proc.exited;
347797
- clearTimeout(timeout7);
347798
- return {
347799
- available: exitCode === 0,
347800
- checkedAt: new Date().toISOString(),
347801
- version: "bunx-semantic-memory"
347802
- };
347864
+ try {
347865
+ const exitCode = await proc.exited;
347866
+ return {
347867
+ available: exitCode === 0,
347868
+ checkedAt: new Date().toISOString(),
347869
+ version: "bunx-semantic-memory"
347870
+ };
347871
+ } finally {
347872
+ clearTimeout(timeout7);
347873
+ proc.kill();
347874
+ }
347803
347875
  } catch (e) {
347804
347876
  return {
347805
347877
  available: false,
@@ -347949,12 +348021,16 @@ async function runGitCommand2(args3) {
347949
348021
  stdout: "pipe",
347950
348022
  stderr: "pipe"
347951
348023
  });
347952
- const [stdout, stderr] = await Promise.all([
347953
- new Response(proc.stdout).text(),
347954
- new Response(proc.stderr).text()
347955
- ]);
347956
- const exitCode = await proc.exited;
347957
- return { exitCode, stdout, stderr };
348024
+ try {
348025
+ const [stdout, stderr] = await Promise.all([
348026
+ new Response(proc.stdout).text(),
348027
+ new Response(proc.stderr).text()
348028
+ ]);
348029
+ const exitCode = await proc.exited;
348030
+ return { exitCode, stdout, stderr };
348031
+ } finally {
348032
+ proc.kill();
348033
+ }
347958
348034
  }
347959
348035
 
347960
348036
  class HiveError2 extends Error {
@@ -348111,9 +348187,9 @@ var hive_create2 = tool2({
348111
348187
  }
348112
348188
  });
348113
348189
  var hive_create_epic2 = tool2({
348114
- description: "Create epic with subtasks in one atomic operation",
348190
+ description: "Create epic with subtasks atomically. REQUIRED: epic_title, subtasks (array with {title, files?}). Use after swarm_validate_decomposition confirms your decomposition is valid. Each subtask should list files it will modify to enable parallel work without conflicts.",
348115
348191
  args: {
348116
- epic_title: tool2.schema.string().describe("Epic title"),
348192
+ epic_title: tool2.schema.string().describe("Epic title (e.g., 'Implement user auth')"),
348117
348193
  epic_description: tool2.schema.string().optional().describe("Epic description"),
348118
348194
  epic_id: tool2.schema.string().optional().describe("Custom ID for the epic (e.g., 'phase-0')"),
348119
348195
  subtasks: tool2.schema.array(tool2.schema.object({
@@ -348132,6 +348208,28 @@ var hive_create_epic2 = tool2({
348132
348208
  }).optional().describe("Recovery context from checkpoint compaction")
348133
348209
  },
348134
348210
  async execute(args3, ctx) {
348211
+ const missing = [];
348212
+ if (!args3.epic_title)
348213
+ missing.push("epic_title");
348214
+ if (!args3.subtasks || args3.subtasks.length === 0)
348215
+ missing.push("subtasks (array of subtask objects)");
348216
+ if (missing.length > 0) {
348217
+ return JSON.stringify({
348218
+ success: false,
348219
+ error: `Missing required parameters: ${missing.join(", ")}`,
348220
+ hint: "hive_create_epic creates an epic with subtasks atomically.",
348221
+ example: {
348222
+ epic_title: "Implement user authentication",
348223
+ epic_description: "Add login, logout, and session management",
348224
+ subtasks: [
348225
+ { title: "Create auth service", files: ["src/auth/service.ts"] },
348226
+ { title: "Add login endpoint", files: ["src/api/login.ts"] },
348227
+ { title: "Add session middleware", files: ["src/middleware/session.ts"] }
348228
+ ]
348229
+ },
348230
+ tip: "Each subtask should have a title and optionally files it will modify. This helps with file reservation and parallel execution."
348231
+ }, null, 2);
348232
+ }
348135
348233
  const validated = EpicCreateArgsSchema2.parse(args3);
348136
348234
  const projectKey = getHiveWorkingDirectory2();
348137
348235
  const adapter5 = await getHiveAdapter2(projectKey);
@@ -350101,17 +350199,41 @@ var swarm_status = tool2({
350101
350199
  }
350102
350200
  });
350103
350201
  var swarm_progress = tool2({
350104
- description: "Report progress on a subtask to coordinator",
350202
+ description: "Report progress on a subtask to coordinator. REQUIRED: project_key, agent_name, bead_id, status. Call periodically (every 25% or when blocked) to keep coordinator informed. Use status='blocked' with message explaining the blocker if you're stuck.",
350105
350203
  args: {
350106
- project_key: tool2.schema.string().describe("Project path"),
350107
- agent_name: tool2.schema.string().describe("Your Agent Mail name"),
350108
- bead_id: tool2.schema.string().describe("Subtask bead ID"),
350204
+ project_key: tool2.schema.string().describe("Project path (e.g., '/Users/name/project')"),
350205
+ agent_name: tool2.schema.string().describe("Your agent name from swarmmail_init"),
350206
+ bead_id: tool2.schema.string().describe("Task ID from your spawn prompt or hive cell"),
350109
350207
  status: tool2.schema.enum(["in_progress", "blocked", "completed", "failed"]).describe("Current status"),
350110
350208
  message: tool2.schema.string().optional().describe("Progress message or blockers"),
350111
350209
  progress_percent: tool2.schema.number().min(0).max(100).optional().describe("Completion percentage"),
350112
350210
  files_touched: tool2.schema.array(tool2.schema.string()).optional().describe("Files modified so far")
350113
350211
  },
350114
350212
  async execute(args3) {
350213
+ const missing = [];
350214
+ if (!args3.bead_id)
350215
+ missing.push("bead_id");
350216
+ if (!args3.project_key)
350217
+ missing.push("project_key");
350218
+ if (!args3.agent_name)
350219
+ missing.push("agent_name");
350220
+ if (!args3.status)
350221
+ missing.push("status");
350222
+ if (missing.length > 0) {
350223
+ return JSON.stringify({
350224
+ success: false,
350225
+ error: `Missing required parameters: ${missing.join(", ")}`,
350226
+ hint: "swarm_progress reports task progress to the coordinator.",
350227
+ example: {
350228
+ project_key: "/path/to/project",
350229
+ agent_name: "your-agent-name",
350230
+ bead_id: "your-task-id from spawn",
350231
+ status: "in_progress",
350232
+ progress_percent: 50,
350233
+ message: "Completed X, working on Y"
350234
+ }
350235
+ }, null, 2);
350236
+ }
350115
350237
  const progress = {
350116
350238
  bead_id: args3.bead_id,
350117
350239
  agent_name: args3.agent_name,
@@ -350237,12 +350359,12 @@ ${args3.files_affected.map((f) => `- \`${f}\``).join(`
350237
350359
  }
350238
350360
  });
350239
350361
  var swarm_complete = tool2({
350240
- description: "Mark subtask complete with Verification Gate. Runs typecheck and tests before allowing completion.",
350362
+ description: "Mark subtask complete with Verification Gate. REQUIRED: project_key, agent_name, bead_id (from your task assignment), summary, start_time (Date.now() from when you started). Before calling: 1) hivemind_store your learnings, 2) list files_touched for verification. Runs typecheck/tests before finalizing.",
350241
350363
  args: {
350242
- project_key: tool2.schema.string().describe("Project path"),
350243
- agent_name: tool2.schema.string().describe("Your Agent Mail name"),
350244
- bead_id: tool2.schema.string().describe("Subtask bead ID"),
350245
- summary: tool2.schema.string().describe("Brief summary of work done"),
350364
+ project_key: tool2.schema.string().describe("Project path (e.g., '/Users/name/project')"),
350365
+ agent_name: tool2.schema.string().describe("Your agent name from swarmmail_init"),
350366
+ bead_id: tool2.schema.string().describe("Task ID from your spawn prompt or hive cell"),
350367
+ summary: tool2.schema.string().describe("What you accomplished (1-3 sentences)"),
350246
350368
  evaluation: tool2.schema.string().optional().describe("Self-evaluation JSON (Evaluation schema)"),
350247
350369
  files_touched: tool2.schema.array(tool2.schema.string()).optional().describe("Files modified - will be verified (typecheck, tests)"),
350248
350370
  skip_verification: tool2.schema.boolean().optional().describe("Skip ALL verification (typecheck, tests). Use sparingly! (default: false)"),
@@ -350253,6 +350375,33 @@ var swarm_complete = tool2({
350253
350375
  skip_review: tool2.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review.")
350254
350376
  },
350255
350377
  async execute(args3, _ctx) {
350378
+ const missing = [];
350379
+ if (!args3.bead_id)
350380
+ missing.push("bead_id");
350381
+ if (!args3.project_key)
350382
+ missing.push("project_key");
350383
+ if (!args3.agent_name)
350384
+ missing.push("agent_name");
350385
+ if (!args3.summary)
350386
+ missing.push("summary");
350387
+ if (args3.start_time === undefined)
350388
+ missing.push("start_time");
350389
+ if (missing.length > 0) {
350390
+ return JSON.stringify({
350391
+ success: false,
350392
+ error: `Missing required parameters: ${missing.join(", ")}`,
350393
+ hint: "swarm_complete marks a subtask as done. All parameters are required.",
350394
+ example: {
350395
+ project_key: "/path/to/project",
350396
+ agent_name: "your-agent-name",
350397
+ bead_id: "epic-id.subtask-num OR cell-id from hive",
350398
+ summary: "Brief description of what you completed",
350399
+ start_time: Date.now(),
350400
+ files_touched: ["src/file1.ts", "src/file2.ts"]
350401
+ },
350402
+ tip: "The bead_id comes from swarm_spawn_subtask or hive_create. Check your task assignment for the correct ID."
350403
+ }, null, 2);
350404
+ }
350256
350405
  const epicId = args3.bead_id.includes(".") ? args3.bead_id.split(".")[0] : args3.bead_id;
350257
350406
  if (!args3.skip_review) {
350258
350407
  const reviewStatusResult = getReviewStatus(args3.bead_id);
@@ -351638,6 +351787,26 @@ Before writing code:
351638
351787
  Begin work on your subtask now.`;
351639
351788
  var SUBTASK_PROMPT_V2 = `You are a swarm agent working on: **{subtask_title}**
351640
351789
 
351790
+ ╔═══════════════════════════════════════════════════════════════════════════════╗
351791
+ ║ ║
351792
+ ║ \uD83D\uDED1 STOP - READ THIS FIRST - BEFORE ANY EDIT OR WRITE \uD83D\uDED1 ║
351793
+ ║ ║
351794
+ ║ You MUST do these 3 things BEFORE your first Edit/Write call: ║
351795
+ ║ ║
351796
+ ║ 1️⃣ hivemind_find(query="<your task keywords>", limit=5, expand=true) ║
351797
+ ║ → Check if past agents already solved this ║
351798
+ ║ → Find gotchas, patterns, warnings ║
351799
+ ║ ║
351800
+ ║ 2️⃣ skills_list() then skills_use(name="<relevant>") ║
351801
+ ║ → testing-patterns, swarm-coordination, system-design ║
351802
+ ║ ║
351803
+ ║ 3️⃣ swarmmail_send(to=["coordinator"], ...) when blocked ║
351804
+ ║ → Don't spin >5min - ASK FOR HELP ║
351805
+ ║ ║
351806
+ ║ SKIPPING THESE = wasted time repeating solved problems ║
351807
+ ║ ║
351808
+ ╚═══════════════════════════════════════════════════════════════════════════════╝
351809
+
351641
351810
  ## [IDENTITY]
351642
351811
  Agent: (assigned at spawn)
351643
351812
  Cell: {bead_id}
@@ -353422,10 +353591,13 @@ async function executePresetQuery(db, presetName) {
353422
353591
  const sql3 = presetQueries[presetName];
353423
353592
  return executeQuery(db, sql3);
353424
353593
  }
353594
+ async function executeQueryCLI(projectPath, sql3) {
353595
+ const db = await createDbAdapter();
353596
+ return executeQuery(db, sql3);
353597
+ }
353425
353598
  async function executePreset(projectPath, presetName) {
353426
353599
  const db = await createDbAdapter();
353427
- const result = await executePresetQuery(db, presetName);
353428
- return result.rows;
353600
+ return executePresetQuery(db, presetName);
353429
353601
  }
353430
353602
  function formatAsTable(result) {
353431
353603
  const { rows, columns, rowCount, executionTimeMs } = result;
@@ -356594,12 +356766,16 @@ async function runGitCommand3(args5) {
356594
356766
  stdout: "pipe",
356595
356767
  stderr: "pipe"
356596
356768
  });
356597
- const [stdout, stderr] = await Promise.all([
356598
- new Response(proc.stdout).text(),
356599
- new Response(proc.stderr).text()
356600
- ]);
356601
- const exitCode = await proc.exited;
356602
- return { exitCode, stdout, stderr };
356769
+ try {
356770
+ const [stdout, stderr] = await Promise.all([
356771
+ new Response(proc.stdout).text(),
356772
+ new Response(proc.stderr).text()
356773
+ ]);
356774
+ const exitCode = await proc.exited;
356775
+ return { exitCode, stdout, stderr };
356776
+ } finally {
356777
+ proc.kill();
356778
+ }
356603
356779
  }
356604
356780
 
356605
356781
  class HiveError3 extends Error {
@@ -356756,9 +356932,9 @@ var hive_create3 = tool3({
356756
356932
  }
356757
356933
  });
356758
356934
  var hive_create_epic3 = tool3({
356759
- description: "Create epic with subtasks in one atomic operation",
356935
+ description: "Create epic with subtasks atomically. REQUIRED: epic_title, subtasks (array with {title, files?}). Use after swarm_validate_decomposition confirms your decomposition is valid. Each subtask should list files it will modify to enable parallel work without conflicts.",
356760
356936
  args: {
356761
- epic_title: tool3.schema.string().describe("Epic title"),
356937
+ epic_title: tool3.schema.string().describe("Epic title (e.g., 'Implement user auth')"),
356762
356938
  epic_description: tool3.schema.string().optional().describe("Epic description"),
356763
356939
  epic_id: tool3.schema.string().optional().describe("Custom ID for the epic (e.g., 'phase-0')"),
356764
356940
  subtasks: tool3.schema.array(tool3.schema.object({
@@ -356777,6 +356953,28 @@ var hive_create_epic3 = tool3({
356777
356953
  }).optional().describe("Recovery context from checkpoint compaction")
356778
356954
  },
356779
356955
  async execute(args5, ctx) {
356956
+ const missing = [];
356957
+ if (!args5.epic_title)
356958
+ missing.push("epic_title");
356959
+ if (!args5.subtasks || args5.subtasks.length === 0)
356960
+ missing.push("subtasks (array of subtask objects)");
356961
+ if (missing.length > 0) {
356962
+ return JSON.stringify({
356963
+ success: false,
356964
+ error: `Missing required parameters: ${missing.join(", ")}`,
356965
+ hint: "hive_create_epic creates an epic with subtasks atomically.",
356966
+ example: {
356967
+ epic_title: "Implement user authentication",
356968
+ epic_description: "Add login, logout, and session management",
356969
+ subtasks: [
356970
+ { title: "Create auth service", files: ["src/auth/service.ts"] },
356971
+ { title: "Add login endpoint", files: ["src/api/login.ts"] },
356972
+ { title: "Add session middleware", files: ["src/middleware/session.ts"] }
356973
+ ]
356974
+ },
356975
+ tip: "Each subtask should have a title and optionally files it will modify. This helps with file reservation and parallel execution."
356976
+ }, null, 2);
356977
+ }
356780
356978
  const validated = EpicCreateArgsSchema3.parse(args5);
356781
356979
  const projectKey = getHiveWorkingDirectory3();
356782
356980
  const adapter6 = await getHiveAdapter3(projectKey);
@@ -357604,13 +357802,17 @@ var toolCheckers2 = {
357604
357802
  stderr: "pipe"
357605
357803
  });
357606
357804
  const timeout7 = setTimeout(() => proc.kill(), BUNX_TIMEOUT_MS2);
357607
- const exitCode = await proc.exited;
357608
- clearTimeout(timeout7);
357609
- return {
357610
- available: exitCode === 0,
357611
- checkedAt: new Date().toISOString(),
357612
- version: "bunx"
357613
- };
357805
+ try {
357806
+ const exitCode = await proc.exited;
357807
+ return {
357808
+ available: exitCode === 0,
357809
+ checkedAt: new Date().toISOString(),
357810
+ version: "bunx"
357811
+ };
357812
+ } finally {
357813
+ clearTimeout(timeout7);
357814
+ proc.kill();
357815
+ }
357614
357816
  } catch (e) {
357615
357817
  return {
357616
357818
  available: false,
@@ -357683,13 +357885,17 @@ var toolCheckers2 = {
357683
357885
  stderr: "pipe"
357684
357886
  });
357685
357887
  const timeout7 = setTimeout(() => proc.kill(), BUNX_TIMEOUT_MS2);
357686
- const exitCode = await proc.exited;
357687
- clearTimeout(timeout7);
357688
- return {
357689
- available: exitCode === 0,
357690
- checkedAt: new Date().toISOString(),
357691
- version: "bunx-semantic-memory"
357692
- };
357888
+ try {
357889
+ const exitCode = await proc.exited;
357890
+ return {
357891
+ available: exitCode === 0,
357892
+ checkedAt: new Date().toISOString(),
357893
+ version: "bunx-semantic-memory"
357894
+ };
357895
+ } finally {
357896
+ clearTimeout(timeout7);
357897
+ proc.kill();
357898
+ }
357693
357899
  } catch (e) {
357694
357900
  return {
357695
357901
  available: false,
@@ -358010,17 +358216,20 @@ class SqliteRateLimiter {
358010
358216
  const MAX_BATCHES = 10;
358011
358217
  const cutoff = Date.now() - 7200000;
358012
358218
  let totalDeleted = 0;
358219
+ let batches = 0;
358013
358220
  for (let i = 0;i < MAX_BATCHES; i++) {
358014
- const result = this.db.run(`DELETE FROM rate_limits
358221
+ const result = this.db.run(`DELETE FROM rate_limits
358015
358222
  WHERE rowid IN (
358016
- SELECT rowid FROM rate_limits
358017
- WHERE timestamp < ?
358223
+ SELECT rowid FROM rate_limits
358224
+ WHERE timestamp < ?
358018
358225
  LIMIT ?
358019
358226
  )`, [cutoff, BATCH_SIZE]);
358020
358227
  totalDeleted += result.changes;
358228
+ batches++;
358021
358229
  if (result.changes < BATCH_SIZE)
358022
358230
  break;
358023
358231
  }
358232
+ return { totalDeleted, batches };
358024
358233
  }
358025
358234
  async recordRequest(agentName, endpoint) {
358026
358235
  const now4 = Date.now();
@@ -360161,14 +360370,27 @@ function formatCassHistoryForPrompt(history) {
360161
360370
  `);
360162
360371
  }
360163
360372
  var swarm_decompose = tool3({
360164
- description: "Generate decomposition prompt for breaking task into parallelizable subtasks. Optionally queries CASS for similar past tasks.",
360373
+ description: "Generate decomposition prompt for breaking task into parallelizable subtasks. REQUIRED: task (the work to decompose). Returns a prompt - use it to plan subtasks, then validate with swarm_validate_decomposition, then create with hive_create_epic.",
360165
360374
  args: {
360166
- task: tool3.schema.string().min(1).describe("Task description to decompose"),
360375
+ task: tool3.schema.string().min(1).describe("Task description (e.g., 'Add user authentication with login/logout')"),
360167
360376
  context: tool3.schema.string().optional().describe("Additional context (codebase info, constraints, etc.)"),
360168
360377
  query_cass: tool3.schema.boolean().optional().describe("Query CASS for similar past tasks (default: true)"),
360169
360378
  cass_limit: tool3.schema.number().int().min(1).optional().describe("Max CASS results to include (default: 3)")
360170
360379
  },
360171
360380
  async execute(args5) {
360381
+ if (!args5.task) {
360382
+ return JSON.stringify({
360383
+ success: false,
360384
+ error: "Missing required parameter: task",
360385
+ hint: "swarm_decompose generates a decomposition prompt for breaking a task into parallelizable subtasks.",
360386
+ example: {
360387
+ task: "Implement user authentication with login, logout, and session management",
360388
+ context: "This is a Next.js app using Prisma for database access",
360389
+ query_cass: true
360390
+ },
360391
+ tip: "Provide a clear task description. The tool will generate a prompt for decomposition and optionally query past similar tasks for patterns."
360392
+ }, null, 2);
360393
+ }
360172
360394
  const { formatMemoryQueryForDecomposition: formatMemoryQueryForDecomposition3 } = await Promise.resolve().then(() => (init_learning2(), exports_learning2));
360173
360395
  let cassContext = "";
360174
360396
  let cassResultInfo;
@@ -360221,9 +360443,9 @@ ${fullContext}` : `## Additional Context
360221
360443
  }
360222
360444
  });
360223
360445
  var swarm_validate_decomposition = tool3({
360224
- description: "Validate a decomposition response against CellTreeSchema and capture for eval",
360446
+ description: "Validate decomposition JSON before creating epic. REQUIRED: response (JSON string with {epic: {title, description}, subtasks: [{title, files, dependencies}]}). Checks for file conflicts and valid dependencies. Call after planning, before hive_create_epic.",
360225
360447
  args: {
360226
- response: tool3.schema.string().describe("JSON response from agent (CellTree format)"),
360448
+ response: tool3.schema.string().describe("JSON string with epic and subtasks (see example in error hint)"),
360227
360449
  project_path: tool3.schema.string().optional().describe("Project path for eval capture"),
360228
360450
  task: tool3.schema.string().optional().describe("Original task description for eval capture"),
360229
360451
  context: tool3.schema.string().optional().describe("Context provided for decomposition"),
@@ -360231,8 +360453,35 @@ var swarm_validate_decomposition = tool3({
360231
360453
  epic_id: tool3.schema.string().optional().describe("Epic ID for eval capture")
360232
360454
  },
360233
360455
  async execute(args5) {
360456
+ if (!args5.response) {
360457
+ return JSON.stringify({
360458
+ success: false,
360459
+ valid: false,
360460
+ error: "Missing required parameter: response",
360461
+ hint: "swarm_validate_decomposition validates a decomposition JSON. Pass the decomposition output as the 'response' parameter.",
360462
+ example: {
360463
+ response: JSON.stringify({
360464
+ epic: { title: "Epic title", description: "Epic description" },
360465
+ subtasks: [
360466
+ { title: "Subtask 1", description: "...", files: ["src/file.ts"], dependencies: [] }
360467
+ ]
360468
+ }),
360469
+ project_path: "/path/to/project",
360470
+ task: "Original task description"
360471
+ },
360472
+ tip: "This tool validates the JSON output from your decomposition planning. The 'response' should be a JSON string matching CellTreeSchema."
360473
+ }, null, 2);
360474
+ }
360234
360475
  try {
360235
- const parsed = JSON.parse(args5.response);
360476
+ let parsed;
360477
+ if (typeof args5.response === "string") {
360478
+ parsed = JSON.parse(args5.response);
360479
+ if (typeof parsed === "string") {
360480
+ parsed = JSON.parse(parsed);
360481
+ }
360482
+ } else {
360483
+ parsed = args5.response;
360484
+ }
360236
360485
  const validated = CellTreeSchema3.parse(parsed);
360237
360486
  const conflicts = detectFileConflicts(validated.subtasks);
360238
360487
  if (conflicts.length > 0) {
@@ -363303,17 +363552,41 @@ var swarm_status2 = tool3({
363303
363552
  }
363304
363553
  });
363305
363554
  var swarm_progress2 = tool3({
363306
- description: "Report progress on a subtask to coordinator",
363555
+ description: "Report progress on a subtask to coordinator. REQUIRED: project_key, agent_name, bead_id, status. Call periodically (every 25% or when blocked) to keep coordinator informed. Use status='blocked' with message explaining the blocker if you're stuck.",
363307
363556
  args: {
363308
- project_key: tool3.schema.string().describe("Project path"),
363309
- agent_name: tool3.schema.string().describe("Your Agent Mail name"),
363310
- bead_id: tool3.schema.string().describe("Subtask bead ID"),
363557
+ project_key: tool3.schema.string().describe("Project path (e.g., '/Users/name/project')"),
363558
+ agent_name: tool3.schema.string().describe("Your agent name from swarmmail_init"),
363559
+ bead_id: tool3.schema.string().describe("Task ID from your spawn prompt or hive cell"),
363311
363560
  status: tool3.schema.enum(["in_progress", "blocked", "completed", "failed"]).describe("Current status"),
363312
363561
  message: tool3.schema.string().optional().describe("Progress message or blockers"),
363313
363562
  progress_percent: tool3.schema.number().min(0).max(100).optional().describe("Completion percentage"),
363314
363563
  files_touched: tool3.schema.array(tool3.schema.string()).optional().describe("Files modified so far")
363315
363564
  },
363316
363565
  async execute(args5) {
363566
+ const missing = [];
363567
+ if (!args5.bead_id)
363568
+ missing.push("bead_id");
363569
+ if (!args5.project_key)
363570
+ missing.push("project_key");
363571
+ if (!args5.agent_name)
363572
+ missing.push("agent_name");
363573
+ if (!args5.status)
363574
+ missing.push("status");
363575
+ if (missing.length > 0) {
363576
+ return JSON.stringify({
363577
+ success: false,
363578
+ error: `Missing required parameters: ${missing.join(", ")}`,
363579
+ hint: "swarm_progress reports task progress to the coordinator.",
363580
+ example: {
363581
+ project_key: "/path/to/project",
363582
+ agent_name: "your-agent-name",
363583
+ bead_id: "your-task-id from spawn",
363584
+ status: "in_progress",
363585
+ progress_percent: 50,
363586
+ message: "Completed X, working on Y"
363587
+ }
363588
+ }, null, 2);
363589
+ }
363317
363590
  const progress = {
363318
363591
  bead_id: args5.bead_id,
363319
363592
  agent_name: args5.agent_name,
@@ -363439,12 +363712,12 @@ ${args5.files_affected.map((f) => `- \`${f}\``).join(`
363439
363712
  }
363440
363713
  });
363441
363714
  var swarm_complete2 = tool3({
363442
- description: "Mark subtask complete with Verification Gate. Runs typecheck and tests before allowing completion.",
363715
+ description: "Mark subtask complete with Verification Gate. REQUIRED: project_key, agent_name, bead_id (from your task assignment), summary, start_time (Date.now() from when you started). Before calling: 1) hivemind_store your learnings, 2) list files_touched for verification. Runs typecheck/tests before finalizing.",
363443
363716
  args: {
363444
- project_key: tool3.schema.string().describe("Project path"),
363445
- agent_name: tool3.schema.string().describe("Your Agent Mail name"),
363446
- bead_id: tool3.schema.string().describe("Subtask bead ID"),
363447
- summary: tool3.schema.string().describe("Brief summary of work done"),
363717
+ project_key: tool3.schema.string().describe("Project path (e.g., '/Users/name/project')"),
363718
+ agent_name: tool3.schema.string().describe("Your agent name from swarmmail_init"),
363719
+ bead_id: tool3.schema.string().describe("Task ID from your spawn prompt or hive cell"),
363720
+ summary: tool3.schema.string().describe("What you accomplished (1-3 sentences)"),
363448
363721
  evaluation: tool3.schema.string().optional().describe("Self-evaluation JSON (Evaluation schema)"),
363449
363722
  files_touched: tool3.schema.array(tool3.schema.string()).optional().describe("Files modified - will be verified (typecheck, tests)"),
363450
363723
  skip_verification: tool3.schema.boolean().optional().describe("Skip ALL verification (typecheck, tests). Use sparingly! (default: false)"),
@@ -363455,6 +363728,33 @@ var swarm_complete2 = tool3({
363455
363728
  skip_review: tool3.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review.")
363456
363729
  },
363457
363730
  async execute(args5, _ctx) {
363731
+ const missing = [];
363732
+ if (!args5.bead_id)
363733
+ missing.push("bead_id");
363734
+ if (!args5.project_key)
363735
+ missing.push("project_key");
363736
+ if (!args5.agent_name)
363737
+ missing.push("agent_name");
363738
+ if (!args5.summary)
363739
+ missing.push("summary");
363740
+ if (args5.start_time === undefined)
363741
+ missing.push("start_time");
363742
+ if (missing.length > 0) {
363743
+ return JSON.stringify({
363744
+ success: false,
363745
+ error: `Missing required parameters: ${missing.join(", ")}`,
363746
+ hint: "swarm_complete marks a subtask as done. All parameters are required.",
363747
+ example: {
363748
+ project_key: "/path/to/project",
363749
+ agent_name: "your-agent-name",
363750
+ bead_id: "epic-id.subtask-num OR cell-id from hive",
363751
+ summary: "Brief description of what you completed",
363752
+ start_time: Date.now(),
363753
+ files_touched: ["src/file1.ts", "src/file2.ts"]
363754
+ },
363755
+ tip: "The bead_id comes from swarm_spawn_subtask or hive_create. Check your task assignment for the correct ID."
363756
+ }, null, 2);
363757
+ }
363458
363758
  const epicId = args5.bead_id.includes(".") ? args5.bead_id.split(".")[0] : args5.bead_id;
363459
363759
  if (!args5.skip_review) {
363460
363760
  const reviewStatusResult = getReviewStatus2(args5.bead_id);
@@ -364791,6 +365091,26 @@ Before writing code:
364791
365091
  Begin work on your subtask now.`;
364792
365092
  var SUBTASK_PROMPT_V22 = `You are a swarm agent working on: **{subtask_title}**
364793
365093
 
365094
+ ╔═══════════════════════════════════════════════════════════════════════════════╗
365095
+ ║ ║
365096
+ ║ \uD83D\uDED1 STOP - READ THIS FIRST - BEFORE ANY EDIT OR WRITE \uD83D\uDED1 ║
365097
+ ║ ║
365098
+ ║ You MUST do these 3 things BEFORE your first Edit/Write call: ║
365099
+ ║ ║
365100
+ ║ 1️⃣ hivemind_find(query="<your task keywords>", limit=5, expand=true) ║
365101
+ ║ → Check if past agents already solved this ║
365102
+ ║ → Find gotchas, patterns, warnings ║
365103
+ ║ ║
365104
+ ║ 2️⃣ skills_list() then skills_use(name="<relevant>") ║
365105
+ ║ → testing-patterns, swarm-coordination, system-design ║
365106
+ ║ ║
365107
+ ║ 3️⃣ swarmmail_send(to=["coordinator"], ...) when blocked ║
365108
+ ║ → Don't spin >5min - ASK FOR HELP ║
365109
+ ║ ║
365110
+ ║ SKIPPING THESE = wasted time repeating solved problems ║
365111
+ ║ ║
365112
+ ╚═══════════════════════════════════════════════════════════════════════════════╝
365113
+
364794
365114
  ## [IDENTITY]
364795
365115
  Agent: (assigned at spawn)
364796
365116
  Cell: {bead_id}
@@ -370751,12 +371071,27 @@ async function claudeCommand() {
370751
371071
  case "user-prompt":
370752
371072
  await claudeUserPrompt();
370753
371073
  break;
371074
+ case "pre-edit":
371075
+ await claudePreEdit();
371076
+ break;
371077
+ case "pre-complete":
371078
+ await claudePreComplete();
371079
+ break;
371080
+ case "post-complete":
371081
+ await claudePostComplete();
371082
+ break;
370754
371083
  case "pre-compact":
370755
371084
  await claudePreCompact();
370756
371085
  break;
370757
371086
  case "session-end":
370758
371087
  await claudeSessionEnd();
370759
371088
  break;
371089
+ case "track-tool":
371090
+ await claudeTrackTool(Bun.argv[4]);
371091
+ break;
371092
+ case "compliance":
371093
+ await claudeCompliance();
371094
+ break;
370760
371095
  default:
370761
371096
  console.error(`Unknown subcommand: ${subcommand}`);
370762
371097
  showClaudeHelp();
@@ -370774,6 +371109,9 @@ Commands:
370774
371109
  init Create project-local .claude/ config
370775
371110
  session-start Hook: session start context (JSON output)
370776
371111
  user-prompt Hook: prompt submit context (JSON output)
371112
+ pre-edit Hook: pre-Edit/Write reminder (hivemind check)
371113
+ pre-complete Hook: pre-swarm_complete checklist
371114
+ post-complete Hook: post-swarm_complete learnings reminder
370777
371115
  pre-compact Hook: pre-compaction handler
370778
371116
  session-end Hook: session cleanup
370779
371117
  `);
@@ -371091,6 +371429,237 @@ async function claudeSessionEnd() {
371091
371429
  console.error(error56 instanceof Error ? error56.message : String(error56));
371092
371430
  }
371093
371431
  }
371432
+ async function claudePreEdit() {
371433
+ try {
371434
+ const input = await readHookInput();
371435
+ const projectPath = resolveClaudeProjectPath(input);
371436
+ const contextLines = [];
371437
+ contextLines.push("\u26A0\uFE0F **Before this edit**: Did you run `hivemind_find` to check for existing solutions?");
371438
+ contextLines.push("If you haven't queried hivemind yet, consider doing so to avoid re-solving problems.");
371439
+ writeClaudeHookOutput("PreToolUse:Edit", contextLines.join(`
371440
+ `), { suppressOutput: true });
371441
+ } catch (error56) {
371442
+ console.error(error56 instanceof Error ? error56.message : String(error56));
371443
+ }
371444
+ }
371445
+ async function claudePreComplete() {
371446
+ try {
371447
+ const input = await readHookInput();
371448
+ const projectPath = resolveClaudeProjectPath(input);
371449
+ const contextLines = [];
371450
+ const trackingDir = join57(projectPath, ".claude", ".worker-tracking");
371451
+ const sessionId = input.session_id || "";
371452
+ const sessionDir = join57(trackingDir, sessionId.slice(0, 8));
371453
+ const mandatoryTools = [
371454
+ { name: "swarmmail_init", label: "Initialize coordination" },
371455
+ { name: "hivemind_find", label: "Query past learnings" }
371456
+ ];
371457
+ const recommendedTools = [
371458
+ { name: "skills_use", label: "Load relevant skills" },
371459
+ { name: "hivemind_store", label: "Store new learnings" }
371460
+ ];
371461
+ const missing = [];
371462
+ const skippedRecommended = [];
371463
+ for (const tool5 of mandatoryTools) {
371464
+ const markerPath = join57(sessionDir, `${tool5.name}.marker`);
371465
+ if (!existsSync37(markerPath)) {
371466
+ missing.push(tool5.label);
371467
+ }
371468
+ }
371469
+ for (const tool5 of recommendedTools) {
371470
+ const markerPath = join57(sessionDir, `${tool5.name}.marker`);
371471
+ if (!existsSync37(markerPath)) {
371472
+ skippedRecommended.push(tool5.label);
371473
+ }
371474
+ }
371475
+ if (missing.length > 0) {
371476
+ contextLines.push("\u26A0\uFE0F **MANDATORY STEPS SKIPPED:**");
371477
+ for (const step5 of missing) {
371478
+ contextLines.push(` \u274C ${step5}`);
371479
+ }
371480
+ contextLines.push("");
371481
+ contextLines.push("These steps are critical for swarm coordination.");
371482
+ contextLines.push("Consider running `hivemind_find` before future completions.");
371483
+ }
371484
+ if (skippedRecommended.length > 0 && missing.length === 0) {
371485
+ contextLines.push("\uD83D\uDCDD **Recommended steps not observed:**");
371486
+ for (const step5 of skippedRecommended) {
371487
+ contextLines.push(` - ${step5}`);
371488
+ }
371489
+ }
371490
+ if (missing.length === 0 && skippedRecommended.length === 0) {
371491
+ contextLines.push("\u2705 **All mandatory and recommended steps completed!**");
371492
+ }
371493
+ try {
371494
+ const swarmMail = await getSwarmMailLibSQL2(projectPath);
371495
+ const db = await swarmMail.getDatabase(projectPath);
371496
+ await db.execute({
371497
+ sql: `INSERT INTO swarm_events (event_type, project_path, agent_name, epic_id, bead_id, payload, created_at)
371498
+ VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`,
371499
+ args: [
371500
+ "worker_compliance",
371501
+ projectPath,
371502
+ "worker",
371503
+ "",
371504
+ "",
371505
+ JSON.stringify({
371506
+ session_id: sessionId,
371507
+ mandatory_skipped: missing.length,
371508
+ recommended_skipped: skippedRecommended.length,
371509
+ score: Math.round((mandatoryTools.length - missing.length) / mandatoryTools.length * 100)
371510
+ })
371511
+ ]
371512
+ });
371513
+ } catch {}
371514
+ if (contextLines.length > 0) {
371515
+ writeClaudeHookOutput("PreToolUse:swarm_complete", contextLines.join(`
371516
+ `), { suppressOutput: missing.length === 0 });
371517
+ }
371518
+ } catch (error56) {
371519
+ console.error(error56 instanceof Error ? error56.message : String(error56));
371520
+ }
371521
+ }
371522
+ async function claudePostComplete() {
371523
+ try {
371524
+ const input = await readHookInput();
371525
+ const contextLines = [];
371526
+ contextLines.push("\u2705 Task completed. If you discovered anything valuable during this work:");
371527
+ contextLines.push("```");
371528
+ contextLines.push("hivemind_store(");
371529
+ contextLines.push(' information="<what you learned, WHY it matters>",');
371530
+ contextLines.push(' tags="<domain, pattern-type>"');
371531
+ contextLines.push(")");
371532
+ contextLines.push("```");
371533
+ contextLines.push("**The swarm's collective intelligence grows when agents share learnings.**");
371534
+ writeClaudeHookOutput("PostToolUse:swarm_complete", contextLines.join(`
371535
+ `), { suppressOutput: true });
371536
+ } catch (error56) {
371537
+ console.error(error56 instanceof Error ? error56.message : String(error56));
371538
+ }
371539
+ }
371540
+ async function claudeTrackTool(toolName) {
371541
+ if (!toolName)
371542
+ return;
371543
+ try {
371544
+ const input = await readHookInput();
371545
+ const projectPath = resolveClaudeProjectPath(input);
371546
+ const trackingDir = join57(projectPath, ".claude", ".worker-tracking");
371547
+ const sessionId = input.session_id || `unknown-${Date.now()}`;
371548
+ const sessionDir = join57(trackingDir, sessionId.slice(0, 8));
371549
+ if (!existsSync37(sessionDir)) {
371550
+ mkdirSync13(sessionDir, { recursive: true });
371551
+ }
371552
+ const markerPath = join57(sessionDir, `${toolName}.marker`);
371553
+ writeFileSync9(markerPath, new Date().toISOString());
371554
+ try {
371555
+ const swarmMail = await getSwarmMailLibSQL2(projectPath);
371556
+ const db = await swarmMail.getDatabase(projectPath);
371557
+ await db.execute({
371558
+ sql: `INSERT INTO swarm_events (event_type, project_path, agent_name, epic_id, bead_id, payload, created_at)
371559
+ VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`,
371560
+ args: [
371561
+ "worker_tool_call",
371562
+ projectPath,
371563
+ "worker",
371564
+ "",
371565
+ "",
371566
+ JSON.stringify({ tool: toolName, session_id: sessionId })
371567
+ ]
371568
+ });
371569
+ } catch {}
371570
+ } catch (error56) {
371571
+ console.error(`[track-tool] ${error56 instanceof Error ? error56.message : String(error56)}`);
371572
+ }
371573
+ }
371574
+ async function claudeCompliance() {
371575
+ try {
371576
+ const input = await readHookInput();
371577
+ const projectPath = resolveClaudeProjectPath(input);
371578
+ const trackingDir = join57(projectPath, ".claude", ".worker-tracking");
371579
+ const sessionId = input.session_id || "";
371580
+ const sessionDir = join57(trackingDir, sessionId.slice(0, 8));
371581
+ const mandatoryTools = ["swarmmail_init", "hivemind_find", "skills_use"];
371582
+ const recommendedTools = ["hivemind_store"];
371583
+ const compliance = {};
371584
+ for (const tool5 of [...mandatoryTools, ...recommendedTools]) {
371585
+ const markerPath = join57(sessionDir, `${tool5}.marker`);
371586
+ compliance[tool5] = existsSync37(markerPath);
371587
+ }
371588
+ const mandatoryCount = mandatoryTools.filter((t) => compliance[t]).length;
371589
+ const score = Math.round(mandatoryCount / mandatoryTools.length * 100);
371590
+ console.log(JSON.stringify({
371591
+ session_id: sessionId,
371592
+ compliance,
371593
+ mandatory_score: score,
371594
+ mandatory_met: mandatoryCount,
371595
+ mandatory_total: mandatoryTools.length,
371596
+ stored_learnings: compliance.hivemind_store
371597
+ }));
371598
+ } catch (error56) {
371599
+ console.error(error56 instanceof Error ? error56.message : String(error56));
371600
+ }
371601
+ }
371602
+ async function showWorkerCompliance() {
371603
+ const projectPath = process.cwd();
371604
+ try {
371605
+ const toolUsageSql = `SELECT
371606
+ json_extract(payload, '$.tool') as tool,
371607
+ COUNT(*) as count,
371608
+ COUNT(DISTINCT json_extract(payload, '$.session_id')) as sessions
371609
+ FROM swarm_events
371610
+ WHERE event_type = 'worker_tool_call'
371611
+ AND created_at > datetime('now', '-7 days')
371612
+ GROUP BY tool
371613
+ ORDER BY count DESC`;
371614
+ const toolResult = await executeQueryCLI(projectPath, toolUsageSql);
371615
+ const rows = toolResult.rows;
371616
+ console.log(yellow3(BANNER));
371617
+ console.log(cyan3(`
371618
+ \uD83D\uDCCA Worker Tool Usage (Last 7 Days)
371619
+ `));
371620
+ if (rows.length === 0) {
371621
+ console.log(dim4("No worker tool usage data found."));
371622
+ console.log(dim4("Data is collected when workers run with the Claude Code plugin."));
371623
+ return;
371624
+ }
371625
+ console.log(dim4("Tool Calls Sessions"));
371626
+ console.log(dim4("\u2500".repeat(45)));
371627
+ for (const row of rows) {
371628
+ const tool5 = String(row.tool).padEnd(22);
371629
+ const count11 = String(row.count).padStart(6);
371630
+ const sessions = String(row.sessions).padStart(8);
371631
+ console.log(`${tool5} ${count11} ${sessions}`);
371632
+ }
371633
+ const hivemindFinds = rows.find((r) => r.tool === "hivemind_find");
371634
+ const completesSql = `SELECT COUNT(*) as count FROM swarm_events
371635
+ WHERE event_type = 'worker_completed'
371636
+ AND created_at > datetime('now', '-7 days')`;
371637
+ const completesResult = await executeQueryCLI(projectPath, completesSql);
371638
+ const completes = Number(completesResult.rows[0]?.count || 0);
371639
+ const finds = Number(hivemindFinds?.count || 0);
371640
+ if (completes > 0) {
371641
+ const rate = Math.round(Math.min(finds, completes) / completes * 100);
371642
+ console.log(dim4(`
371643
+ \u2500`.repeat(45)));
371644
+ console.log(`
371645
+ ${green3("Hivemind compliance rate:")} ${rate}% (${finds} queries / ${completes} completions)`);
371646
+ }
371647
+ } catch (error56) {
371648
+ const msg = error56 instanceof Error ? error56.message : String(error56);
371649
+ if (msg.includes("no such table")) {
371650
+ console.log(yellow3(BANNER));
371651
+ console.log(cyan3(`
371652
+ \uD83D\uDCCA Worker Tool Usage
371653
+ `));
371654
+ console.log(dim4("No tracking data yet."));
371655
+ console.log(dim4("Compliance tracking starts when workers run with the Claude Code plugin hooks."));
371656
+ console.log(dim4(`
371657
+ The swarm_events table will be created on first tracked tool call.`));
371658
+ } else {
371659
+ console.error("Error fetching compliance data:", msg);
371660
+ }
371661
+ }
371662
+ }
371094
371663
  async function init3() {
371095
371664
  p4.intro("swarm init v" + VERSION6);
371096
371665
  const projectPath = process.cwd();
@@ -371347,13 +371916,13 @@ async function query() {
371347
371916
  p4.intro("swarm query");
371348
371917
  const projectPath = process.cwd();
371349
371918
  try {
371350
- let rows;
371919
+ let result;
371351
371920
  if (parsed.preset) {
371352
371921
  p4.log.step(`Executing preset: ${parsed.preset}`);
371353
- rows = await executePreset(projectPath, parsed.preset);
371922
+ result = await executePreset(projectPath, parsed.preset);
371354
371923
  } else if (parsed.query) {
371355
371924
  p4.log.step("Executing custom SQL");
371356
- rows = await executeQuery(projectPath, parsed.query);
371925
+ result = await executeQueryCLI(projectPath, parsed.query);
371357
371926
  } else {
371358
371927
  p4.log.error("No query specified. Use --sql or --preset");
371359
371928
  p4.outro("Aborted");
@@ -371362,20 +371931,20 @@ async function query() {
371362
371931
  let output;
371363
371932
  switch (parsed.format) {
371364
371933
  case "csv":
371365
- output = formatAsCSV(rows);
371934
+ output = formatAsCSV(result);
371366
371935
  break;
371367
371936
  case "json":
371368
- output = formatAsJSON(rows);
371937
+ output = formatAsJSON(result);
371369
371938
  break;
371370
371939
  case "table":
371371
371940
  default:
371372
- output = formatAsTable(rows);
371941
+ output = formatAsTable(result);
371373
371942
  break;
371374
371943
  }
371375
371944
  console.log();
371376
371945
  console.log(output);
371377
371946
  console.log();
371378
- p4.outro(`Found ${rows.length} result(s)`);
371947
+ p4.outro(`Found ${result.rowCount} result(s)`);
371379
371948
  } catch (error56) {
371380
371949
  p4.log.error("Query failed");
371381
371950
  p4.log.message(error56 instanceof Error ? error56.message : String(error56));
@@ -371652,6 +372221,7 @@ ${cyan3("Commands:")}
371652
372221
  swarm eval Eval-driven development commands
371653
372222
  swarm query SQL analytics with presets (--sql, --preset, --format)
371654
372223
  swarm dashboard Live terminal UI with worker status (--epic, --refresh)
372224
+ swarm compliance Worker tool usage compliance stats (hivemind, skills, etc)
371655
372225
  swarm replay Event replay with timing (--speed, --type, --agent, --since, --until)
371656
372226
  swarm export Export events (--format otlp/csv/json, --epic, --output)
371657
372227
  swarm tree Visualize cell hierarchy as ASCII tree (--status, --epic, --json)
@@ -371738,6 +372308,7 @@ ${cyan3("Observability Commands:")}
371738
372308
  swarm export --format csv Export as CSV
371739
372309
  swarm export --epic <id> Export specific epic only
371740
372310
  swarm export --output <file> Write to file instead of stdout
372311
+ swarm compliance Show worker tool usage compliance stats
371741
372312
  swarm tree Show all cells as tree
371742
372313
  swarm tree --status open Show only open cells
371743
372314
  swarm tree --epic <id> Show specific epic subtree
@@ -371762,6 +372333,11 @@ ${cyan3("Claude Code:")}
371762
372333
  swarm claude init Create project-local .claude config
371763
372334
  swarm claude session-start Hook: session start context
371764
372335
  swarm claude user-prompt Hook: prompt submit context
372336
+ swarm claude pre-edit Hook: pre-Edit/Write (hivemind reminder)
372337
+ swarm claude pre-complete Hook: pre-swarm_complete (compliance check)
372338
+ swarm claude post-complete Hook: post-swarm_complete (store learnings)
372339
+ swarm claude track-tool <name> Hook: track mandatory tool usage
372340
+ swarm claude compliance Hook: show session compliance data
371765
372341
  swarm claude pre-compact Hook: pre-compaction handler
371766
372342
  swarm claude session-end Hook: session cleanup
371767
372343
 
@@ -373648,6 +374224,9 @@ switch (command) {
373648
374224
  case "dashboard":
373649
374225
  await dashboard();
373650
374226
  break;
374227
+ case "compliance":
374228
+ await showWorkerCompliance();
374229
+ break;
373651
374230
  case "replay":
373652
374231
  await replay();
373653
374232
  break;