opencode-swarm-plugin 0.45.1 → 0.45.3

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.
@@ -17242,6 +17242,34 @@ import {
17242
17242
  sep as sep2
17243
17243
  } from "path";
17244
17244
  import { fileURLToPath } from "url";
17245
+ import { getSwarmMailLibSQL as getSwarmMailLibSQL2, createEvent as createEvent2 } from "swarm-mail";
17246
+ async function emitSkillLoadedEvent(data) {
17247
+ try {
17248
+ const projectPath = skillsProjectDirectory;
17249
+ const swarmMail = await getSwarmMailLibSQL2(projectPath);
17250
+ const event = createEvent2("skill_loaded", {
17251
+ project_key: projectPath,
17252
+ skill_name: data.skill_name,
17253
+ skill_source: data.skill_source,
17254
+ context_provided: data.context_provided,
17255
+ content_length: data.content_length
17256
+ });
17257
+ await swarmMail.appendEvent(event);
17258
+ } catch {}
17259
+ }
17260
+ async function emitSkillCreatedEvent(data) {
17261
+ try {
17262
+ const projectPath = skillsProjectDirectory;
17263
+ const swarmMail = await getSwarmMailLibSQL2(projectPath);
17264
+ const event = createEvent2("skill_created", {
17265
+ project_key: projectPath,
17266
+ skill_name: data.skill_name,
17267
+ skill_scope: data.skill_scope,
17268
+ description: data.description
17269
+ });
17270
+ await swarmMail.appendEvent(event);
17271
+ } catch {}
17272
+ }
17245
17273
  function setSkillsProjectDirectory(dir) {
17246
17274
  skillsProjectDirectory = dir;
17247
17275
  skillsCache = null;
@@ -17677,6 +17705,18 @@ If the skill has scripts, you can run them with skills_execute.`,
17677
17705
  const names = available.map((s) => s.name).join(", ");
17678
17706
  return `Skill '${args.name}' not found. Available skills: ${names || "none"}`;
17679
17707
  }
17708
+ let skillSource = "project";
17709
+ if (skill.path.includes(".config/opencode/skills") || skill.path.includes(".claude/skills")) {
17710
+ skillSource = "global";
17711
+ } else if (skill.path.includes("global-skills")) {
17712
+ skillSource = "bundled";
17713
+ }
17714
+ await emitSkillLoadedEvent({
17715
+ skill_name: skill.metadata.name,
17716
+ skill_source: skillSource,
17717
+ context_provided: true,
17718
+ content_length: skill.body.length
17719
+ });
17680
17720
  const includeScripts = args.include_scripts !== false;
17681
17721
  let output = `# Skill: ${skill.metadata.name}
17682
17722
 
@@ -17845,6 +17885,12 @@ Good skills have:
17845
17885
  const content = generateSkillContent(args.name, args.description, args.body, { tags: args.tags, tools: args.tools });
17846
17886
  await writeFile(skillPath, content, "utf-8");
17847
17887
  invalidateSkillsCache();
17888
+ const skillScope = args.directory === "global" || args.directory === "global-claude" ? "global" : "project";
17889
+ await emitSkillCreatedEvent({
17890
+ skill_name: args.name,
17891
+ skill_scope: skillScope,
17892
+ description: args.description
17893
+ });
17848
17894
  const response = {
17849
17895
  success: true,
17850
17896
  skill: args.name,
@@ -18080,6 +18126,12 @@ echo "Project directory: $1"
18080
18126
  createdFiles.push("references/guide.md");
18081
18127
  }
18082
18128
  invalidateSkillsCache();
18129
+ const skillScope = args.directory === "global" ? "global" : "project";
18130
+ await emitSkillCreatedEvent({
18131
+ skill_name: args.name,
18132
+ skill_scope: skillScope,
18133
+ description: args.description || "[TODO: Complete description]"
18134
+ });
18083
18135
  return JSON.stringify({
18084
18136
  success: true,
18085
18137
  skill: args.name,
@@ -20679,9 +20731,9 @@ import {
20679
20731
  releaseSwarmFiles,
20680
20732
  sendSwarmMessage as sendSwarmMessage2,
20681
20733
  getAgent,
20682
- createEvent as createEvent2,
20734
+ createEvent as createEvent3,
20683
20735
  appendEvent as appendEvent2,
20684
- getSwarmMailLibSQL as getSwarmMailLibSQL2
20736
+ getSwarmMailLibSQL as getSwarmMailLibSQL3
20685
20737
  } from "swarm-mail";
20686
20738
 
20687
20739
  // src/tool-availability.ts
@@ -21092,6 +21144,20 @@ var hive_create = tool({
21092
21144
  parent_id: validated.parent_id
21093
21145
  });
21094
21146
  await adapter.markDirty(projectKey, cell.id);
21147
+ try {
21148
+ const event = createEvent("cell_created", {
21149
+ project_key: projectKey,
21150
+ cell_id: cell.id,
21151
+ title: validated.title,
21152
+ description: validated.description,
21153
+ issue_type: validated.type || "task",
21154
+ priority: validated.priority ?? 2,
21155
+ parent_id: validated.parent_id
21156
+ });
21157
+ await appendEvent(event, projectKey);
21158
+ } catch (error45) {
21159
+ console.warn("[hive_create] Failed to emit cell_created event:", error45);
21160
+ }
21095
21161
  const formatted = formatCellForOutput(cell);
21096
21162
  return JSON.stringify(formatted, null, 2);
21097
21163
  } catch (error45) {
@@ -21151,6 +21217,19 @@ var hive_create_epic = tool({
21151
21217
  subtasks: created.slice(1).map((c) => formatCellForOutput(c))
21152
21218
  };
21153
21219
  const effectiveProjectKey = args.project_key || projectKey;
21220
+ try {
21221
+ const epicCreatedEvent = createEvent("epic_created", {
21222
+ project_key: effectiveProjectKey,
21223
+ epic_id: epic.id,
21224
+ title: validated.epic_title,
21225
+ description: validated.epic_description,
21226
+ subtask_count: validated.subtasks.length,
21227
+ subtask_ids: created.slice(1).map((c) => c.id)
21228
+ });
21229
+ await appendEvent(epicCreatedEvent, effectiveProjectKey);
21230
+ } catch (error45) {
21231
+ console.warn("[hive_create_epic] Failed to emit epic_created event:", error45);
21232
+ }
21154
21233
  try {
21155
21234
  const event = createEvent("decomposition_generated", {
21156
21235
  project_key: effectiveProjectKey,
@@ -21315,6 +21394,23 @@ var hive_update = tool({
21315
21394
  cell = existingCell;
21316
21395
  }
21317
21396
  await adapter.markDirty(projectKey, cellId);
21397
+ try {
21398
+ const fieldsChanged = [];
21399
+ if (validated.status)
21400
+ fieldsChanged.push("status");
21401
+ if (validated.description !== undefined)
21402
+ fieldsChanged.push("description");
21403
+ if (validated.priority !== undefined)
21404
+ fieldsChanged.push("priority");
21405
+ const event = createEvent("cell_updated", {
21406
+ project_key: projectKey,
21407
+ cell_id: cellId,
21408
+ fields_changed: fieldsChanged
21409
+ });
21410
+ await appendEvent(event, projectKey);
21411
+ } catch (error45) {
21412
+ console.warn("[hive_update] Failed to emit cell_updated event:", error45);
21413
+ }
21318
21414
  const formatted = formatCellForOutput(cell);
21319
21415
  return JSON.stringify(formatted, null, 2);
21320
21416
  } catch (error45) {
@@ -21431,6 +21527,16 @@ var hive_close = tool({
21431
21527
  console.warn("[hive_close] Failed to emit SwarmCompletedEvent:", error45);
21432
21528
  }
21433
21529
  }
21530
+ try {
21531
+ const event = createEvent("cell_closed", {
21532
+ project_key: projectKey,
21533
+ cell_id: cellId,
21534
+ reason: validated.reason
21535
+ });
21536
+ await appendEvent(event, projectKey);
21537
+ } catch (error45) {
21538
+ console.warn("[hive_close] Failed to emit cell_closed event:", error45);
21539
+ }
21434
21540
  return `Closed ${cell.id}: ${validated.reason}`;
21435
21541
  } catch (error45) {
21436
21542
  const message = error45 instanceof Error ? error45.message : String(error45);
@@ -21456,6 +21562,17 @@ var hive_start = tool({
21456
21562
  const cellId = await resolvePartialId(adapter, projectKey, args.id) || args.id;
21457
21563
  const cell = await adapter.changeCellStatus(projectKey, cellId, "in_progress");
21458
21564
  await adapter.markDirty(projectKey, cellId);
21565
+ try {
21566
+ const event = createEvent("cell_status_changed", {
21567
+ project_key: projectKey,
21568
+ cell_id: cellId,
21569
+ old_status: "open",
21570
+ new_status: "in_progress"
21571
+ });
21572
+ await appendEvent(event, projectKey);
21573
+ } catch (error45) {
21574
+ console.warn("[hive_start] Failed to emit cell_status_changed event:", error45);
21575
+ }
21459
21576
  return `Started: ${cell.id}`;
21460
21577
  } catch (error45) {
21461
21578
  const message = error45 instanceof Error ? error45.message : String(error45);
@@ -21644,11 +21761,25 @@ var hive_sync = tool({
21644
21761
  }
21645
21762
  const remoteCheckResult = await runGitCommand(["remote"]);
21646
21763
  const hasRemote = remoteCheckResult.stdout.trim() !== "";
21764
+ let pushSuccess = false;
21647
21765
  if (hasRemote) {
21648
21766
  const pushResult = await withTimeout(runGitCommand(["push"]), TIMEOUT_MS, "git push");
21649
21767
  if (pushResult.exitCode !== 0) {
21650
21768
  throw new HiveError(`Failed to push: ${pushResult.stderr}`, "git push", pushResult.exitCode);
21651
21769
  }
21770
+ pushSuccess = true;
21771
+ }
21772
+ try {
21773
+ const event = createEvent("hive_synced", {
21774
+ project_key: projectKey,
21775
+ cells_synced: flushResult.cellsExported,
21776
+ push_success: pushSuccess
21777
+ });
21778
+ await appendEvent(event, projectKey);
21779
+ } catch (error45) {
21780
+ console.warn("[hive_sync] Failed to emit hive_synced event:", error45);
21781
+ }
21782
+ if (hasRemote) {
21652
21783
  return "Hive synced and pushed successfully";
21653
21784
  } else {
21654
21785
  return "Hive synced successfully (no remote configured)";
@@ -22340,9 +22471,9 @@ var swarm_review = tool({
22340
22471
  downstream_tasks: downstreamTasks.length > 0 ? downstreamTasks : undefined
22341
22472
  });
22342
22473
  try {
22343
- const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
22474
+ const { createEvent: createEvent3, appendEvent: appendEvent2 } = await import("swarm-mail");
22344
22475
  const attempt = getReviewStatus(args.task_id).attempt_count || 1;
22345
- const reviewStartedEvent = createEvent2("review_started", {
22476
+ const reviewStartedEvent = createEvent3("review_started", {
22346
22477
  project_key: args.project_key,
22347
22478
  epic_id: args.epic_id,
22348
22479
  bead_id: args.task_id,
@@ -22431,9 +22562,9 @@ var swarm_review_feedback = tool({
22431
22562
  console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
22432
22563
  }
22433
22564
  try {
22434
- const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
22565
+ const { createEvent: createEvent3, appendEvent: appendEvent2 } = await import("swarm-mail");
22435
22566
  const attempt = getReviewStatus(args.task_id).attempt_count || 1;
22436
- const reviewCompletedEvent = createEvent2("review_completed", {
22567
+ const reviewCompletedEvent = createEvent3("review_completed", {
22437
22568
  project_key: args.project_key,
22438
22569
  epic_id: epicId,
22439
22570
  bead_id: args.task_id,
@@ -22502,9 +22633,9 @@ You may now complete the task with \`swarm_complete\`.`,
22502
22633
  console.warn("[swarm_review_feedback] Failed to trace review_decision:", error45);
22503
22634
  }
22504
22635
  try {
22505
- const { createEvent: createEvent2, appendEvent: appendEvent2 } = await import("swarm-mail");
22636
+ const { createEvent: createEvent3, appendEvent: appendEvent2 } = await import("swarm-mail");
22506
22637
  const status = remaining <= 0 ? "blocked" : "needs_changes";
22507
- const reviewCompletedEvent = createEvent2("review_completed", {
22638
+ const reviewCompletedEvent = createEvent3("review_completed", {
22508
22639
  project_key: args.project_key,
22509
22640
  epic_id: epicId,
22510
22641
  bead_id: args.task_id,
@@ -23056,7 +23187,7 @@ var swarm_progress = tool({
23056
23187
  }
23057
23188
  };
23058
23189
  const checkpointData = JSON.stringify(checkpoint);
23059
- const checkpointEvent = createEvent2("swarm_checkpointed", {
23190
+ const checkpointEvent = createEvent3("swarm_checkpointed", {
23060
23191
  project_key: args.project_key,
23061
23192
  ...checkpoint,
23062
23193
  checkpoint_size_bytes: Buffer.byteLength(checkpointData, "utf8"),
@@ -23064,7 +23195,7 @@ var swarm_progress = tool({
23064
23195
  });
23065
23196
  await appendEvent2(checkpointEvent, args.project_key);
23066
23197
  const checkpointId = `ckpt-${Date.now()}-${args.bead_id}`;
23067
- const createdEvent = createEvent2("checkpoint_created", {
23198
+ const createdEvent = createEvent3("checkpoint_created", {
23068
23199
  project_key: args.project_key,
23069
23200
  epic_id: epicId,
23070
23201
  bead_id: args.bead_id,
@@ -23317,7 +23448,7 @@ This will be recorded as a negative learning signal.`;
23317
23448
  let deferredResolved = false;
23318
23449
  let deferredError;
23319
23450
  try {
23320
- const swarmMail = await getSwarmMailLibSQL2(args.project_key);
23451
+ const swarmMail = await getSwarmMailLibSQL3(args.project_key);
23321
23452
  const db = await swarmMail.getDatabase();
23322
23453
  const deferredUrl = `deferred:${args.bead_id}`;
23323
23454
  const checkResult = await db.query(`SELECT url, resolved FROM deferred WHERE url = ? AND resolved = 0`, [deferredUrl]);
@@ -23346,16 +23477,16 @@ This will be recorded as a negative learning signal.`;
23346
23477
  syncError = error45 instanceof Error ? error45.message : String(error45);
23347
23478
  console.warn(`[swarm_complete] Auto-sync failed (non-fatal): ${syncError}`);
23348
23479
  }
23480
+ const completionDurationMs = args.start_time ? Date.now() - args.start_time : 0;
23481
+ const eventEpicId = cell.parent_id || (args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id);
23349
23482
  try {
23350
- const durationMs2 = args.start_time ? Date.now() - args.start_time : 0;
23351
- const eventEpicId = cell.parent_id || (args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id);
23352
- const event = createEvent2("subtask_outcome", {
23483
+ const event = createEvent3("subtask_outcome", {
23353
23484
  project_key: args.project_key,
23354
23485
  epic_id: eventEpicId,
23355
23486
  bead_id: args.bead_id,
23356
23487
  planned_files: args.planned_files || [],
23357
23488
  actual_files: args.files_touched || [],
23358
- duration_ms: durationMs2,
23489
+ duration_ms: completionDurationMs,
23359
23490
  error_count: args.error_count || 0,
23360
23491
  retry_count: args.retry_count || 0,
23361
23492
  success: true,
@@ -23366,8 +23497,21 @@ This will be recorded as a negative learning signal.`;
23366
23497
  } catch (error45) {
23367
23498
  console.warn("[swarm_complete] Failed to emit SubtaskOutcomeEvent:", error45);
23368
23499
  }
23500
+ try {
23501
+ const workerCompletedEvent = createEvent3("worker_completed", {
23502
+ project_key: args.project_key,
23503
+ epic_id: eventEpicId,
23504
+ bead_id: args.bead_id,
23505
+ worker_agent: args.agent_name,
23506
+ success: true,
23507
+ duration_ms: completionDurationMs,
23508
+ files_touched: args.files_touched || []
23509
+ });
23510
+ await appendEvent2(workerCompletedEvent, args.project_key);
23511
+ } catch (error45) {
23512
+ console.warn("[swarm_complete] Failed to emit worker_completed event:", error45);
23513
+ }
23369
23514
  let capturedStrategy;
23370
- const durationMs = args.start_time ? Date.now() - args.start_time : 0;
23371
23515
  const memoryInfo = formatMemoryStoreOnSuccess(args.bead_id, args.summary, args.files_touched || [], capturedStrategy);
23372
23516
  let memoryStored = false;
23373
23517
  let memoryError;
@@ -23484,7 +23628,7 @@ Files touched: ${args.files_touched?.join(", ") || "none recorded"}`,
23484
23628
  };
23485
23629
  try {
23486
23630
  const { captureSubtaskOutcome: captureSubtaskOutcome2 } = await Promise.resolve().then(() => (init_eval_capture(), exports_eval_capture));
23487
- const durationMs2 = args.start_time ? Date.now() - args.start_time : 0;
23631
+ const durationMs = args.start_time ? Date.now() - args.start_time : 0;
23488
23632
  const evalEpicId = cell.parent_id || epicId2;
23489
23633
  captureSubtaskOutcome2({
23490
23634
  epicId: evalEpicId,
@@ -23493,7 +23637,7 @@ Files touched: ${args.files_touched?.join(", ") || "none recorded"}`,
23493
23637
  title: cell.title,
23494
23638
  plannedFiles: args.planned_files || [],
23495
23639
  actualFiles: args.files_touched || [],
23496
- durationMs: durationMs2,
23640
+ durationMs,
23497
23641
  errorCount: args.error_count || 0,
23498
23642
  retryCount: args.retry_count || 0,
23499
23643
  success: true
@@ -23502,7 +23646,7 @@ Files touched: ${args.files_touched?.join(", ") || "none recorded"}`,
23502
23646
  console.warn("[swarm_complete] Failed to capture subtask outcome:", error45);
23503
23647
  }
23504
23648
  try {
23505
- const durationMs2 = args.start_time ? Date.now() - args.start_time : 0;
23649
+ const durationMs = args.start_time ? Date.now() - args.start_time : 0;
23506
23650
  captureCoordinatorEvent({
23507
23651
  session_id: _ctx.sessionID || "unknown",
23508
23652
  epic_id: epicId2,
@@ -23511,7 +23655,7 @@ Files touched: ${args.files_touched?.join(", ") || "none recorded"}`,
23511
23655
  outcome_type: "subtask_success",
23512
23656
  payload: {
23513
23657
  bead_id: args.bead_id,
23514
- duration_ms: durationMs2,
23658
+ duration_ms: durationMs,
23515
23659
  files_touched: args.files_touched || [],
23516
23660
  verification_passed: verificationResult?.passed ?? false,
23517
23661
  verification_skipped: args.skip_verification ?? false
@@ -23985,7 +24129,7 @@ var swarm_checkpoint = tool({
23985
24129
  }
23986
24130
  };
23987
24131
  const checkpointData = JSON.stringify(checkpoint);
23988
- const event = createEvent2("swarm_checkpointed", {
24132
+ const event = createEvent3("swarm_checkpointed", {
23989
24133
  project_key: args.project_key,
23990
24134
  epic_id: args.epic_id,
23991
24135
  bead_id: args.bead_id,
@@ -24027,8 +24171,8 @@ var swarm_recover = tool({
24027
24171
  },
24028
24172
  async execute(args) {
24029
24173
  try {
24030
- const { getSwarmMailLibSQL: getSwarmMailLibSQL3 } = await import("swarm-mail");
24031
- const swarmMail = await getSwarmMailLibSQL3(args.project_key);
24174
+ const { getSwarmMailLibSQL: getSwarmMailLibSQL4 } = await import("swarm-mail");
24175
+ const swarmMail = await getSwarmMailLibSQL4(args.project_key);
24032
24176
  const db = await swarmMail.getDatabase();
24033
24177
  const result = await db.query(`SELECT * FROM swarm_contexts
24034
24178
  WHERE epic_id = $1
@@ -24055,7 +24199,7 @@ var swarm_recover = tool({
24055
24199
  created_at: row.created_at,
24056
24200
  updated_at: row.updated_at
24057
24201
  };
24058
- const event = createEvent2("swarm_recovered", {
24202
+ const event = createEvent3("swarm_recovered", {
24059
24203
  project_key: args.project_key,
24060
24204
  epic_id: args.epic_id,
24061
24205
  bead_id: context.bead_id,
@@ -24214,7 +24358,7 @@ init_eval_capture();
24214
24358
 
24215
24359
  // src/memory-tools.ts
24216
24360
  init_dist();
24217
- import { getSwarmMailLibSQL as getSwarmMailLibSQL3 } from "swarm-mail";
24361
+ import { getSwarmMailLibSQL as getSwarmMailLibSQL4, createEvent as createEvent4, appendEvent as appendEvent3 } from "swarm-mail";
24218
24362
 
24219
24363
  // ../../node_modules/.bun/effect@3.19.12/node_modules/effect/dist/esm/Function.js
24220
24364
  var isFunction = (input) => typeof input === "function";
@@ -37831,7 +37975,7 @@ async function getMemoryAdapter(projectPath) {
37831
37975
  if (cachedAdapter && cachedProjectPath === path3) {
37832
37976
  return cachedAdapter;
37833
37977
  }
37834
- const swarmMail = await getSwarmMailLibSQL3(path3);
37978
+ const swarmMail = await getSwarmMailLibSQL4(path3);
37835
37979
  const dbAdapter = await swarmMail.getDatabase();
37836
37980
  cachedAdapter = await createMemoryAdapter(dbAdapter);
37837
37981
  cachedProjectPath = path3;
@@ -37852,6 +37996,21 @@ var semantic_memory_store = tool({
37852
37996
  async execute(args2, ctx) {
37853
37997
  const adapter = await getMemoryAdapter();
37854
37998
  const result = await adapter.store(args2);
37999
+ try {
38000
+ const projectKey = cachedProjectPath || process.cwd();
38001
+ const tags = args2.tags ? args2.tags.split(",").map((t) => t.trim()) : [];
38002
+ const event = createEvent4("memory_stored", {
38003
+ project_key: projectKey,
38004
+ memory_id: result.id,
38005
+ content_preview: args2.information.slice(0, 100),
38006
+ tags,
38007
+ auto_tagged: args2.autoTag,
38008
+ collection: args2.collection
38009
+ });
38010
+ await appendEvent3(event, projectKey);
38011
+ } catch (error45) {
38012
+ console.warn("[semantic_memory_store] Failed to emit memory_stored event:", error45);
38013
+ }
37855
38014
  return JSON.stringify(result, null, 2);
37856
38015
  }
37857
38016
  });
@@ -37865,8 +38024,25 @@ var semantic_memory_find = tool({
37865
38024
  fts: tool.schema.boolean().optional().describe("Use full-text search instead of vector search (default: false)")
37866
38025
  },
37867
38026
  async execute(args2, ctx) {
38027
+ const startTime = Date.now();
37868
38028
  const adapter = await getMemoryAdapter();
37869
38029
  const result = await adapter.find(args2);
38030
+ const duration3 = Date.now() - startTime;
38031
+ try {
38032
+ const projectKey = cachedProjectPath || process.cwd();
38033
+ const topScore = result.results.length > 0 ? result.results[0].score : undefined;
38034
+ const event = createEvent4("memory_found", {
38035
+ project_key: projectKey,
38036
+ query: args2.query,
38037
+ result_count: result.results.length,
38038
+ top_score: topScore,
38039
+ search_duration_ms: duration3,
38040
+ used_fts: args2.fts
38041
+ });
38042
+ await appendEvent3(event, projectKey);
38043
+ } catch (error45) {
38044
+ console.warn("[semantic_memory_find] Failed to emit memory_found event:", error45);
38045
+ }
37870
38046
  return JSON.stringify(result, null, 2);
37871
38047
  }
37872
38048
  });
@@ -37889,6 +38065,18 @@ var semantic_memory_remove = tool({
37889
38065
  async execute(args2, ctx) {
37890
38066
  const adapter = await getMemoryAdapter();
37891
38067
  const result = await adapter.remove(args2);
38068
+ if (result.success) {
38069
+ try {
38070
+ const projectKey = cachedProjectPath || process.cwd();
38071
+ const event = createEvent4("memory_deleted", {
38072
+ project_key: projectKey,
38073
+ memory_id: args2.id
38074
+ });
38075
+ await appendEvent3(event, projectKey);
38076
+ } catch (error45) {
38077
+ console.warn("[semantic_memory_remove] Failed to emit memory_deleted event:", error45);
38078
+ }
38079
+ }
37892
38080
  return JSON.stringify(result, null, 2);
37893
38081
  }
37894
38082
  });
@@ -37900,6 +38088,19 @@ var semantic_memory_validate = tool({
37900
38088
  async execute(args2, ctx) {
37901
38089
  const adapter = await getMemoryAdapter();
37902
38090
  const result = await adapter.validate(args2);
38091
+ if (result.success) {
38092
+ try {
38093
+ const projectKey = cachedProjectPath || process.cwd();
38094
+ const event = createEvent4("memory_validated", {
38095
+ project_key: projectKey,
38096
+ memory_id: args2.id,
38097
+ decay_reset: true
38098
+ });
38099
+ await appendEvent3(event, projectKey);
38100
+ } catch (error45) {
38101
+ console.warn("[semantic_memory_validate] Failed to emit memory_validated event:", error45);
38102
+ }
38103
+ }
37903
38104
  return JSON.stringify(result, null, 2);
37904
38105
  }
37905
38106
  });
@@ -37947,6 +38148,18 @@ var semantic_memory_upsert = tool({
37947
38148
  async execute(args2, ctx) {
37948
38149
  const adapter = await getMemoryAdapter();
37949
38150
  const result = await adapter.upsert(args2);
38151
+ try {
38152
+ const projectKey = cachedProjectPath || process.cwd();
38153
+ const event = createEvent4("memory_updated", {
38154
+ project_key: projectKey,
38155
+ memory_id: result.memoryId || "unknown",
38156
+ operation: result.operation,
38157
+ reason: result.reason
38158
+ });
38159
+ await appendEvent3(event, projectKey);
38160
+ } catch (error45) {
38161
+ console.warn("[semantic_memory_upsert] Failed to emit memory_updated event:", error45);
38162
+ }
37950
38163
  return JSON.stringify(result, null, 2);
37951
38164
  }
37952
38165
  });
@@ -39281,9 +39494,9 @@ var swarm_spawn_subtask = tool({
39281
39494
  }
39282
39495
  if (args2.project_path) {
39283
39496
  try {
39284
- const { createEvent: createEvent3, appendEvent: appendEvent3 } = await import("swarm-mail");
39497
+ const { createEvent: createEvent5, appendEvent: appendEvent4 } = await import("swarm-mail");
39285
39498
  const spawnOrder = 0;
39286
- const workerSpawnedEvent = createEvent3("worker_spawned", {
39499
+ const workerSpawnedEvent = createEvent5("worker_spawned", {
39287
39500
  project_key: args2.project_path,
39288
39501
  epic_id: args2.epic_id,
39289
39502
  bead_id: args2.bead_id,
@@ -39293,7 +39506,7 @@ var swarm_spawn_subtask = tool({
39293
39506
  spawn_order: spawnOrder,
39294
39507
  is_parallel: false
39295
39508
  });
39296
- await appendEvent3(workerSpawnedEvent, args2.project_path);
39509
+ await appendEvent4(workerSpawnedEvent, args2.project_path);
39297
39510
  } catch (error45) {
39298
39511
  console.warn("[swarm_spawn_subtask] Failed to emit WorkerSpawnedEvent:", error45);
39299
39512
  }
@@ -2344,6 +2344,97 @@ Extract from session context:
2344
2344
  **You are not waiting for instructions. You are the coordinator. Coordinate.**
2345
2345
  `;
2346
2346
 
2347
+ /**
2348
+ * Build dynamic swarm state section from snapshot
2349
+ *
2350
+ * This creates a concrete state summary with actual IDs and status
2351
+ * to prepend to the static compaction context.
2352
+ */
2353
+ function buildDynamicStateFromSnapshot(snapshot: SwarmStateSnapshot): string {
2354
+ if (!snapshot.epic) {
2355
+ return "";
2356
+ }
2357
+
2358
+ const parts: string[] = [];
2359
+
2360
+ // Header with epic info
2361
+ parts.push(`## 🐝 Current Swarm State\n`);
2362
+ parts.push(`**Epic:** ${snapshot.epic.id} - ${snapshot.epic.title}`);
2363
+ parts.push(`**Status:** ${snapshot.epic.status}`);
2364
+ parts.push(`**Project:** ${projectDirectory}\n`);
2365
+
2366
+ // Subtask breakdown
2367
+ const subtasks = snapshot.epic.subtasks || [];
2368
+ const completed = subtasks.filter(s => s.status === "closed");
2369
+ const inProgress = subtasks.filter(s => s.status === "in_progress");
2370
+ const blocked = subtasks.filter(s => s.status === "blocked");
2371
+ const pending = subtasks.filter(s => s.status === "open");
2372
+
2373
+ parts.push(`**Progress:** ${completed.length}/${subtasks.length} subtasks complete\n`);
2374
+
2375
+ // Immediate actions with real IDs
2376
+ parts.push(`## 1️⃣ IMMEDIATE ACTIONS (Do These FIRST)\n`);
2377
+ parts.push(`1. \`swarm_status(epic_id="${snapshot.epic.id}", project_key="${projectDirectory}")\` - Get current state`);
2378
+ parts.push(`2. \`swarmmail_inbox(limit=5)\` - Check for worker messages`);
2379
+
2380
+ if (inProgress.length > 0) {
2381
+ parts.push(`3. Review in-progress work when workers complete`);
2382
+ }
2383
+ if (pending.length > 0) {
2384
+ const next = pending[0];
2385
+ parts.push(`4. Spawn next subtask: \`swarm_spawn_subtask(bead_id="${next.id}", ...)\``);
2386
+ }
2387
+ if (blocked.length > 0) {
2388
+ parts.push(`5. Unblock: ${blocked.map(s => s.id).join(", ")}`);
2389
+ }
2390
+ parts.push("");
2391
+
2392
+ // Detailed subtask status
2393
+ if (inProgress.length > 0) {
2394
+ parts.push(`### 🚧 In Progress (${inProgress.length})`);
2395
+ for (const s of inProgress) {
2396
+ const files = s.files?.length ? ` (${s.files.slice(0, 3).join(", ")}${s.files.length > 3 ? "..." : ""})` : "";
2397
+ parts.push(`- ${s.id}: ${s.title}${files}`);
2398
+ }
2399
+ parts.push("");
2400
+ }
2401
+
2402
+ if (blocked.length > 0) {
2403
+ parts.push(`### 🚫 Blocked (${blocked.length})`);
2404
+ for (const s of blocked) {
2405
+ parts.push(`- ${s.id}: ${s.title}`);
2406
+ }
2407
+ parts.push("");
2408
+ }
2409
+
2410
+ if (pending.length > 0) {
2411
+ parts.push(`### ⏳ Ready to Spawn (${pending.length})`);
2412
+ for (const s of pending.slice(0, 5)) { // Show first 5
2413
+ const files = s.files?.length ? ` (${s.files.slice(0, 2).join(", ")}${s.files.length > 2 ? "..." : ""})` : "";
2414
+ parts.push(`- ${s.id}: ${s.title}${files}`);
2415
+ }
2416
+ if (pending.length > 5) {
2417
+ parts.push(`- ... and ${pending.length - 5} more`);
2418
+ }
2419
+ parts.push("");
2420
+ }
2421
+
2422
+ if (completed.length > 0) {
2423
+ parts.push(`### ✅ Completed (${completed.length})`);
2424
+ for (const s of completed.slice(-3)) { // Show last 3
2425
+ parts.push(`- ${s.id}: ${s.title} ✓`);
2426
+ }
2427
+ if (completed.length > 3) {
2428
+ parts.push(`- ... and ${completed.length - 3} more`);
2429
+ }
2430
+ parts.push("");
2431
+ }
2432
+
2433
+ parts.push("---\n");
2434
+
2435
+ return parts.join("\n");
2436
+ }
2437
+
2347
2438
  /**
2348
2439
  * Fallback detection prompt - tells the compactor what to look for
2349
2440
  *
@@ -2610,6 +2701,9 @@ const SwarmPlugin: Plugin = async (
2610
2701
  has_projection: !!sessionScan.projection?.isSwarm,
2611
2702
  });
2612
2703
 
2704
+ // Hoist snapshot outside try block so it's available in fallback path
2705
+ let snapshot: SwarmStateSnapshot | undefined;
2706
+
2613
2707
  try {
2614
2708
  // =======================================================================
2615
2709
  // PREFER PROJECTION (ground truth from events) OVER HIVE QUERY
@@ -2617,8 +2711,6 @@ const SwarmPlugin: Plugin = async (
2617
2711
  // The projection is derived from session events - it's the source of truth.
2618
2712
  // Hive query may show all cells closed even if swarm was active.
2619
2713
 
2620
- let snapshot: SwarmStateSnapshot;
2621
-
2622
2714
  if (sessionScan.projection?.isSwarm) {
2623
2715
  // Use projection as primary source - convert to snapshot format
2624
2716
  const proj = sessionScan.projection;
@@ -2801,9 +2893,12 @@ const SwarmPlugin: Plugin = async (
2801
2893
  });
2802
2894
  }
2803
2895
 
2804
- // Level 3: Fall back to static context
2896
+ // Level 3: Fall back to static context WITH dynamic state from snapshot
2805
2897
  const header = `[Swarm detected: ${detection.reasons.join(", ")}]\n\n`;
2806
- const staticContent = header + SWARM_COMPACTION_CONTEXT;
2898
+
2899
+ // Build dynamic state section if we have snapshot data
2900
+ const dynamicState = snapshot ? buildDynamicStateFromSnapshot(snapshot) : "";
2901
+ const staticContent = header + dynamicState + SWARM_COMPACTION_CONTEXT;
2807
2902
  output.context.push(staticContent);
2808
2903
 
2809
2904
  // =======================================================================
@@ -2811,13 +2906,16 @@ const SwarmPlugin: Plugin = async (
2811
2906
  // =======================================================================
2812
2907
  await captureCompaction(
2813
2908
  input.sessionID,
2814
- "unknown", // No snapshot available in this path
2909
+ snapshot?.epic?.id || "unknown",
2815
2910
  "context_injected",
2816
2911
  {
2817
2912
  full_content: staticContent,
2818
2913
  content_length: staticContent.length,
2819
2914
  injection_method: "output.context.push",
2820
- context_type: "static_swarm_context",
2915
+ context_type: "static_with_dynamic_state",
2916
+ has_dynamic_state: !!dynamicState,
2917
+ epic_id: snapshot?.epic?.id,
2918
+ subtask_count: snapshot?.epic?.subtasks?.length ?? 0,
2821
2919
  },
2822
2920
  );
2823
2921
 
@@ -2826,9 +2924,12 @@ const SwarmPlugin: Plugin = async (
2826
2924
  session_id: input.sessionID,
2827
2925
  total_duration_ms: totalDuration,
2828
2926
  confidence: detection.confidence,
2829
- context_type: "static_swarm_context",
2927
+ context_type: dynamicState ? "static_with_dynamic_state" : "static_swarm_context",
2830
2928
  content_length: staticContent.length,
2831
2929
  context_count_after: output.context.length,
2930
+ has_dynamic_state: !!dynamicState,
2931
+ epic_id: snapshot?.epic?.id,
2932
+ subtask_count: snapshot?.epic?.subtasks?.length ?? 0,
2832
2933
  });
2833
2934
  } else if (detection.confidence === "low") {
2834
2935
  // Level 4: Possible swarm - inject fallback detection prompt