opencode-swarm 7.77.6 → 7.78.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.
package/dist/cli/index.js CHANGED
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "opencode-swarm",
55
- version: "7.77.6",
55
+ version: "7.78.0",
56
56
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
57
57
  main: "dist/index.js",
58
58
  types: "dist/index.d.ts",
@@ -150,6 +150,7 @@ export declare const RECEIPT_EVENT_TYPES: ReadonlySet<string>;
150
150
  export declare function resolveKnowledgeEventsPath(directory: string): string;
151
151
  /** Returns `.swarm/knowledge-counter-baseline.json` for folded event counters. */
152
152
  export declare function resolveKnowledgeCounterBaselinePath(directory: string): string;
153
+ export declare function resolveHiveEventsPath(): string;
153
154
  /** Returns `.swarm/knowledge-application.jsonl` for legacy v2 audit records. */
154
155
  export declare function resolveLegacyApplicationLogPath(directory: string): string;
155
156
  /** Generate a fresh trace id. One per retrieval; receipts reference it. */
@@ -169,12 +170,29 @@ export declare function appendKnowledgeEvent(directory: string, event: Knowledge
169
170
  * execution). Never throws; logs a warning and returns null on failure.
170
171
  */
171
172
  export declare function recordKnowledgeEvent(directory: string, event: KnowledgeEventInput): Promise<KnowledgeEvent | null>;
173
+ /**
174
+ * Append one event to the shared, cross-project hive events log. Use for audit
175
+ * tombstones of mutations to the hive store so any project can read why a hive
176
+ * entry was archived/quarantined/purged. Throws on I/O failure; hot paths should
177
+ * prefer {@link recordHiveKnowledgeEvent}.
178
+ */
179
+ export declare function appendHiveKnowledgeEvent(event: KnowledgeEventInput): Promise<KnowledgeEvent>;
180
+ /**
181
+ * Fail-open variant of {@link appendHiveKnowledgeEvent} for hot paths. Never
182
+ * throws; logs a warning and returns null on failure.
183
+ */
184
+ export declare function recordHiveKnowledgeEvent(event: KnowledgeEventInput): Promise<KnowledgeEvent | null>;
172
185
  /**
173
186
  * Read all events from the log. Skips corrupted JSONL lines (logging a warning
174
187
  * for each) and returns an empty array when the file does not exist — mirrors
175
188
  * `readKnowledge` in knowledge-store.ts.
176
189
  */
177
190
  export declare function readKnowledgeEvents(directory: string): Promise<KnowledgeEvent[]>;
191
+ /**
192
+ * Read all events from the shared, cross-project hive events log. Skips
193
+ * corrupted JSONL lines and returns an empty array when the file does not exist.
194
+ */
195
+ export declare function readHiveKnowledgeEvents(): Promise<KnowledgeEvent[]>;
178
196
  /**
179
197
  * Read legacy knowledge-application audit records. Corrupt lines are skipped so
180
198
  * stale telemetry cannot break search, promotion, or manual recall.
@@ -292,5 +310,9 @@ export declare const _internals: {
292
310
  applyKnowledgeVerdictFeedback: typeof applyKnowledgeVerdictFeedback;
293
311
  newTraceId: typeof newTraceId;
294
312
  newEventId: typeof newEventId;
313
+ resolveHiveEventsPath: typeof resolveHiveEventsPath;
314
+ appendHiveKnowledgeEvent: typeof appendHiveKnowledgeEvent;
315
+ recordHiveKnowledgeEvent: typeof recordHiveKnowledgeEvent;
316
+ readHiveKnowledgeEvents: typeof readHiveKnowledgeEvents;
295
317
  };
296
318
  export {};
@@ -6,6 +6,7 @@ export declare function resolveSwarmRejectedPath(directory: string): string;
6
6
  export declare function resolveSwarmRetractionsPath(directory: string): string;
7
7
  export declare function resolveHiveKnowledgePath(): string;
8
8
  export declare function resolveHiveRejectedPath(): string;
9
+ export declare function resolveHiveEventsPath(): string;
9
10
  export declare function readKnowledge<T>(filePath: string): Promise<T[]>;
10
11
  export declare function normalizeEntry<T>(raw: T): T;
11
12
  export declare function readRejectedLessons(directory: string): Promise<RejectedLesson[]>;
@@ -73,6 +74,7 @@ export declare const _internals: {
73
74
  resolveSwarmRejectedPath: typeof resolveSwarmRejectedPath;
74
75
  resolveHiveKnowledgePath: typeof resolveHiveKnowledgePath;
75
76
  resolveHiveRejectedPath: typeof resolveHiveRejectedPath;
77
+ resolveHiveEventsPath: typeof resolveHiveEventsPath;
76
78
  readKnowledge: typeof readKnowledge;
77
79
  readRejectedLessons: typeof readRejectedLessons;
78
80
  appendKnowledge: typeof appendKnowledge;
package/dist/index.js CHANGED
@@ -69,7 +69,7 @@ var package_default;
69
69
  var init_package = __esm(() => {
70
70
  package_default = {
71
71
  name: "opencode-swarm",
72
- version: "7.77.6",
72
+ version: "7.78.0",
73
73
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
74
74
  main: "dist/index.js",
75
75
  types: "dist/index.d.ts",
@@ -59678,6 +59678,7 @@ __export(exports_knowledge_store, {
59678
59678
  resolveSwarmKnowledgePath: () => resolveSwarmKnowledgePath,
59679
59679
  resolveHiveRejectedPath: () => resolveHiveRejectedPath,
59680
59680
  resolveHiveKnowledgePath: () => resolveHiveKnowledgePath,
59681
+ resolveHiveEventsPath: () => resolveHiveEventsPath,
59681
59682
  readRetractionRecords: () => readRetractionRecords,
59682
59683
  readRejectedLessons: () => readRejectedLessons,
59683
59684
  readKnowledge: () => readKnowledge,
@@ -59739,6 +59740,10 @@ function resolveHiveRejectedPath() {
59739
59740
  const hivePath = resolveHiveKnowledgePath();
59740
59741
  return path31.join(path31.dirname(hivePath), "shared-learnings-rejected.jsonl");
59741
59742
  }
59743
+ function resolveHiveEventsPath() {
59744
+ const hivePath = resolveHiveKnowledgePath();
59745
+ return path31.join(path31.dirname(hivePath), "shared-knowledge-events.jsonl");
59746
+ }
59742
59747
  async function readKnowledge(filePath) {
59743
59748
  if (!existsSync13(filePath))
59744
59749
  return [];
@@ -60181,6 +60186,7 @@ var init_knowledge_store = __esm(() => {
60181
60186
  resolveSwarmRejectedPath,
60182
60187
  resolveHiveKnowledgePath,
60183
60188
  resolveHiveRejectedPath,
60189
+ resolveHiveEventsPath,
60184
60190
  readKnowledge,
60185
60191
  readRejectedLessons,
60186
60192
  appendKnowledge,
@@ -60208,11 +60214,14 @@ __export(exports_knowledge_events, {
60208
60214
  resolveLegacyApplicationLogPath: () => resolveLegacyApplicationLogPath,
60209
60215
  resolveKnowledgeEventsPath: () => resolveKnowledgeEventsPath,
60210
60216
  resolveKnowledgeCounterBaselinePath: () => resolveKnowledgeCounterBaselinePath,
60217
+ resolveHiveEventsPath: () => resolveHiveEventsPath2,
60211
60218
  recordKnowledgeEvent: () => recordKnowledgeEvent,
60219
+ recordHiveKnowledgeEvent: () => recordHiveKnowledgeEvent,
60212
60220
  recomputeCounters: () => recomputeCounters,
60213
60221
  readLegacyApplicationRecords: () => readLegacyApplicationRecords,
60214
60222
  readKnowledgeEvents: () => readKnowledgeEvents,
60215
60223
  readKnowledgeCounterRollups: () => readKnowledgeCounterRollups,
60224
+ readHiveKnowledgeEvents: () => readHiveKnowledgeEvents,
60216
60225
  newTraceId: () => newTraceId,
60217
60226
  newEventId: () => newEventId,
60218
60227
  effectiveRetrievalOutcomes: () => effectiveRetrievalOutcomes,
@@ -60220,6 +60229,7 @@ __export(exports_knowledge_events, {
60220
60229
  countEntryViolationsInWindow: () => countEntryViolationsInWindow,
60221
60230
  applyKnowledgeVerdictFeedback: () => applyKnowledgeVerdictFeedback,
60222
60231
  appendKnowledgeEvent: () => appendKnowledgeEvent,
60232
+ appendHiveKnowledgeEvent: () => appendHiveKnowledgeEvent,
60223
60233
  _internals: () => _internals24,
60224
60234
  RECEIPT_EVENT_TYPES: () => RECEIPT_EVENT_TYPES,
60225
60235
  MAX_VIOLATION_TIMESTAMPS: () => MAX_VIOLATION_TIMESTAMPS,
@@ -60229,6 +60239,7 @@ __export(exports_knowledge_events, {
60229
60239
  import { randomUUID as randomUUID2 } from "node:crypto";
60230
60240
  import { existsSync as existsSync14 } from "node:fs";
60231
60241
  import { appendFile as appendFile4, mkdir as mkdir5, readFile as readFile5, stat as stat4 } from "node:fs/promises";
60242
+ import * as os10 from "node:os";
60232
60243
  import * as path32 from "node:path";
60233
60244
  function resolveKnowledgeEventsPath(directory) {
60234
60245
  return path32.join(directory, ".swarm", "knowledge-events.jsonl");
@@ -60236,6 +60247,19 @@ function resolveKnowledgeEventsPath(directory) {
60236
60247
  function resolveKnowledgeCounterBaselinePath(directory) {
60237
60248
  return path32.join(directory, ".swarm", "knowledge-counter-baseline.json");
60238
60249
  }
60250
+ function resolveHiveEventsPath2() {
60251
+ const platform = process.platform;
60252
+ const home = process.env.HOME || os10.homedir();
60253
+ let dir;
60254
+ if (platform === "win32") {
60255
+ dir = path32.join(process.env.LOCALAPPDATA || path32.join(home, "AppData", "Local"), "opencode-swarm", "Data");
60256
+ } else if (platform === "darwin") {
60257
+ dir = path32.join(home, "Library", "Application Support", "opencode-swarm");
60258
+ } else {
60259
+ dir = path32.join(process.env.XDG_DATA_HOME || path32.join(home, ".local", "share"), "opencode-swarm");
60260
+ }
60261
+ return path32.join(dir, "shared-knowledge-events.jsonl");
60262
+ }
60239
60263
  function resolveLegacyApplicationLogPath(directory) {
60240
60264
  return path32.join(directory, ".swarm", "knowledge-application.jsonl");
60241
60265
  }
@@ -60294,6 +60318,45 @@ async function recordKnowledgeEvent(directory, event) {
60294
60318
  return null;
60295
60319
  }
60296
60320
  }
60321
+ async function appendHiveKnowledgeEvent(event) {
60322
+ const populated = withDefaults(event);
60323
+ const filePath = resolveHiveEventsPath2();
60324
+ const dirPath = path32.dirname(filePath);
60325
+ await mkdir5(dirPath, { recursive: true });
60326
+ let release;
60327
+ try {
60328
+ release = await import_proper_lockfile4.default.lock(dirPath, {
60329
+ retries: { retries: 200, minTimeout: 10, maxTimeout: 100 }
60330
+ });
60331
+ await appendFile4(filePath, `${JSON.stringify(populated)}
60332
+ `, "utf-8");
60333
+ try {
60334
+ const content = await readFile5(filePath, "utf-8");
60335
+ const lines = content.split(`
60336
+ `).filter((line) => line.trim().length > 0);
60337
+ if (lines.length > MAX_EVENT_LOG_ENTRIES) {
60338
+ const trimmed = lines.slice(lines.length - MAX_EVENT_LOG_ENTRIES);
60339
+ await atomicWriteFile(filePath, `${trimmed.join(`
60340
+ `)}
60341
+ `);
60342
+ }
60343
+ } catch (err2) {
60344
+ warn(`[knowledge-events] hive cap trim failed (non-fatal): ${err2 instanceof Error ? err2.message : String(err2)}`);
60345
+ }
60346
+ } finally {
60347
+ if (release)
60348
+ await release().catch(() => {});
60349
+ }
60350
+ return populated;
60351
+ }
60352
+ async function recordHiveKnowledgeEvent(event) {
60353
+ try {
60354
+ return await appendHiveKnowledgeEvent(event);
60355
+ } catch (err2) {
60356
+ warn(`[knowledge-events] recordHiveKnowledgeEvent failed: ${err2 instanceof Error ? err2.message : String(err2)}`);
60357
+ return null;
60358
+ }
60359
+ }
60297
60360
  async function readKnowledgeEvents(directory) {
60298
60361
  const filePath = resolveKnowledgeEventsPath(directory);
60299
60362
  if (!existsSync14(filePath))
@@ -60302,6 +60365,14 @@ async function readKnowledgeEvents(directory) {
60302
60365
  return parseEventLines(content.split(`
60303
60366
  `), filePath);
60304
60367
  }
60368
+ async function readHiveKnowledgeEvents() {
60369
+ const filePath = resolveHiveEventsPath2();
60370
+ if (!existsSync14(filePath))
60371
+ return [];
60372
+ const content = await readFile5(filePath, "utf-8");
60373
+ return parseEventLines(content.split(`
60374
+ `), filePath);
60375
+ }
60305
60376
  async function readLegacyApplicationRecords(directory) {
60306
60377
  const filePath = resolveLegacyApplicationLogPath(directory);
60307
60378
  if (!existsSync14(filePath))
@@ -60704,7 +60775,11 @@ var init_knowledge_events = __esm(() => {
60704
60775
  recomputeCounters,
60705
60776
  applyKnowledgeVerdictFeedback,
60706
60777
  newTraceId,
60707
- newEventId
60778
+ newEventId,
60779
+ resolveHiveEventsPath: resolveHiveEventsPath2,
60780
+ appendHiveKnowledgeEvent,
60781
+ recordHiveKnowledgeEvent,
60782
+ readHiveKnowledgeEvents
60708
60783
  };
60709
60784
  });
60710
60785
 
@@ -70219,10 +70294,10 @@ var init_concurrency = __esm(() => {
70219
70294
  });
70220
70295
 
70221
70296
  // src/commands/config.ts
70222
- import * as os10 from "node:os";
70297
+ import * as os11 from "node:os";
70223
70298
  import * as path50 from "node:path";
70224
70299
  function getUserConfigDir2() {
70225
- return process.env.XDG_CONFIG_HOME || path50.join(os10.homedir(), ".config");
70300
+ return process.env.XDG_CONFIG_HOME || path50.join(os11.homedir(), ".config");
70226
70301
  }
70227
70302
  async function handleConfigCommand(directory, _args) {
70228
70303
  const config3 = loadPluginConfig(directory);
@@ -71358,13 +71433,13 @@ var init_design_docs = __esm(() => {
71358
71433
  });
71359
71434
 
71360
71435
  // src/config/cache-paths.ts
71361
- import * as os11 from "node:os";
71436
+ import * as os12 from "node:os";
71362
71437
  import * as path54 from "node:path";
71363
71438
  function getPluginConfigDir() {
71364
- return path54.join(process.env.XDG_CONFIG_HOME || path54.join(os11.homedir(), ".config"), "opencode");
71439
+ return path54.join(process.env.XDG_CONFIG_HOME || path54.join(os12.homedir(), ".config"), "opencode");
71365
71440
  }
71366
71441
  function getPluginCachePaths() {
71367
- const cacheBase = process.env.XDG_CACHE_HOME || path54.join(os11.homedir(), ".cache");
71442
+ const cacheBase = process.env.XDG_CACHE_HOME || path54.join(os12.homedir(), ".cache");
71368
71443
  const configDir = getPluginConfigDir();
71369
71444
  const paths = [
71370
71445
  path54.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
@@ -71372,12 +71447,12 @@ function getPluginCachePaths() {
71372
71447
  path54.join(configDir, "node_modules", "opencode-swarm")
71373
71448
  ];
71374
71449
  if (process.platform === "darwin") {
71375
- const libCaches = path54.join(os11.homedir(), "Library", "Caches");
71450
+ const libCaches = path54.join(os12.homedir(), "Library", "Caches");
71376
71451
  paths.push(path54.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path54.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
71377
71452
  }
71378
71453
  if (process.platform === "win32") {
71379
- const localAppData = process.env.LOCALAPPDATA || path54.join(os11.homedir(), "AppData", "Local");
71380
- const appData = process.env.APPDATA || path54.join(os11.homedir(), "AppData", "Roaming");
71454
+ const localAppData = process.env.LOCALAPPDATA || path54.join(os12.homedir(), "AppData", "Local");
71455
+ const appData = process.env.APPDATA || path54.join(os12.homedir(), "AppData", "Roaming");
71381
71456
  paths.push(path54.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path54.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path54.join(appData, "opencode", "node_modules", "opencode-swarm"));
71382
71457
  }
71383
71458
  return paths;
@@ -71500,11 +71575,11 @@ var init_gate_bridge = __esm(() => {
71500
71575
 
71501
71576
  // src/services/version-check.ts
71502
71577
  import { existsSync as existsSync28, mkdirSync as mkdirSync16, readFileSync as readFileSync13, writeFileSync as writeFileSync9 } from "node:fs";
71503
- import { homedir as homedir6 } from "node:os";
71578
+ import { homedir as homedir7 } from "node:os";
71504
71579
  import { join as join43 } from "node:path";
71505
71580
  function cacheDir() {
71506
71581
  const xdg = process.env.XDG_CACHE_HOME;
71507
- const base = xdg && xdg.length > 0 ? xdg : join43(homedir6(), ".cache");
71582
+ const base = xdg && xdg.length > 0 ? xdg : join43(homedir7(), ".cache");
71508
71583
  return join43(base, "opencode-swarm");
71509
71584
  }
71510
71585
  function cacheFile() {
@@ -72660,7 +72735,7 @@ __export(exports_config_doctor, {
72660
72735
  });
72661
72736
  import * as crypto5 from "node:crypto";
72662
72737
  import * as fs24 from "node:fs";
72663
- import * as os12 from "node:os";
72738
+ import * as os13 from "node:os";
72664
72739
  import * as path56 from "node:path";
72665
72740
  function levenshteinDistance(a, b) {
72666
72741
  const al = a.length;
@@ -72694,7 +72769,7 @@ function emitObjectTypeMismatch(key, value, findings) {
72694
72769
  }
72695
72770
  }
72696
72771
  function getUserConfigDir3() {
72697
- return process.env.XDG_CONFIG_HOME || path56.join(os12.homedir(), ".config");
72772
+ return process.env.XDG_CONFIG_HOME || path56.join(os13.homedir(), ".config");
72698
72773
  }
72699
72774
  function getConfigPaths(directory) {
72700
72775
  const userConfigPath = path56.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
@@ -77779,7 +77854,7 @@ var KNOWLEDGE_SCHEMA_VERSION = 2;
77779
77854
  import { randomUUID as randomUUID6 } from "node:crypto";
77780
77855
  import { existsSync as existsSync34, readFileSync as readFileSync18 } from "node:fs";
77781
77856
  import { mkdir as mkdir16, readFile as readFile18, writeFile as writeFile14 } from "node:fs/promises";
77782
- import * as os13 from "node:os";
77857
+ import * as os14 from "node:os";
77783
77858
  import * as path60 from "node:path";
77784
77859
  async function migrateKnowledgeToExternal(_directory, _config) {
77785
77860
  return {
@@ -78131,7 +78206,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
78131
78206
  }
78132
78207
  function resolveLegacyHiveKnowledgePath() {
78133
78208
  const platform = process.platform;
78134
- const home = process.env.HOME || os13.homedir();
78209
+ const home = process.env.HOME || os14.homedir();
78135
78210
  let dataDir;
78136
78211
  if (platform === "win32") {
78137
78212
  dataDir = path60.join(process.env.LOCALAPPDATA || path60.join(home, "AppData", "Local"), "opencode-swarm", "Data");
@@ -81404,7 +81479,7 @@ var init_gateway = __esm(() => {
81404
81479
 
81405
81480
  // src/memory/evaluation.ts
81406
81481
  import * as fs27 from "node:fs/promises";
81407
- import * as os14 from "node:os";
81482
+ import * as os15 from "node:os";
81408
81483
  import * as path65 from "node:path";
81409
81484
  async function evaluateMemoryRecallFixtures(options) {
81410
81485
  const fixtureDirectory = path65.resolve(options.fixtureDirectory);
@@ -81416,7 +81491,7 @@ async function evaluateMemoryRecallFixtures(options) {
81416
81491
  for (const fixture of fixtures) {
81417
81492
  const materialized = materializeFixture(fixture);
81418
81493
  for (const providerName of providers) {
81419
- const tempRoot = await fs27.realpath(await fs27.mkdtemp(path65.join(os14.tmpdir(), "swarm-memory-eval-")));
81494
+ const tempRoot = await fs27.realpath(await fs27.mkdtemp(path65.join(os15.tmpdir(), "swarm-memory-eval-")));
81420
81495
  const provider = createEvaluationProvider(providerName, tempRoot);
81421
81496
  try {
81422
81497
  await provider.initialize?.();
@@ -105641,7 +105716,9 @@ async function dispatchFullAutoOversight(input) {
105641
105716
  const oversightAgent = createCriticAutonomousOversightAgent(input.criticModel, buildOversightPrompt(input));
105642
105717
  log(`[full-auto/oversight] Dispatching ${oversightAgent.name} via ${input.oversightAgentName} (model=${input.criticModel}, trigger=${input.triggerSource})`);
105643
105718
  let ephemeralSessionId;
105719
+ const promptController = new AbortController;
105644
105720
  const cleanup = () => {
105721
+ promptController.abort();
105645
105722
  if (ephemeralSessionId) {
105646
105723
  const id = ephemeralSessionId;
105647
105724
  ephemeralSessionId = undefined;
@@ -105670,7 +105747,8 @@ async function dispatchFullAutoOversight(input) {
105670
105747
  agent: input.oversightAgentName,
105671
105748
  tools: { write: false, edit: false, patch: false },
105672
105749
  parts: [{ type: "text", text: buildOversightPrompt(input) }]
105673
- }
105750
+ },
105751
+ signal: promptController.signal
105674
105752
  });
105675
105753
  if (!promptResult.data) {
105676
105754
  throw new Error(`Critic prompt failed: ${JSON.stringify(promptResult.error)}`);
@@ -107582,7 +107660,9 @@ async function dispatchCriticAndWriteEvent(directory, architectOutput, criticCon
107582
107660
  const oversightAgent = createCriticAutonomousOversightAgent(criticModel, criticContext);
107583
107661
  log(`[full-auto-intercept] Dispatching critic: ${oversightAgent.name} using model ${criticModel}`);
107584
107662
  let ephemeralSessionId;
107663
+ const promptController = new AbortController;
107585
107664
  const cleanup = () => {
107665
+ promptController.abort();
107586
107666
  if (ephemeralSessionId) {
107587
107667
  const id = ephemeralSessionId;
107588
107668
  ephemeralSessionId = undefined;
@@ -107608,7 +107688,8 @@ async function dispatchCriticAndWriteEvent(directory, architectOutput, criticCon
107608
107688
  agent: oversightAgentName,
107609
107689
  tools: { write: false, edit: false, patch: false },
107610
107690
  parts: [{ type: "text", text: criticContext }]
107611
- }
107691
+ },
107692
+ signal: promptController.signal
107612
107693
  });
107613
107694
  if (!promptResult.data) {
107614
107695
  throw new Error(`Critic LLM prompt failed: ${JSON.stringify(promptResult.error)}`);
@@ -108157,7 +108238,7 @@ init_path_security();
108157
108238
  import * as fsSync7 from "node:fs";
108158
108239
  import { existsSync as existsSync63, realpathSync as realpathSync13 } from "node:fs";
108159
108240
  import * as fsPromises5 from "node:fs/promises";
108160
- import * as os15 from "node:os";
108241
+ import * as os16 from "node:os";
108161
108242
  import * as path108 from "node:path";
108162
108243
 
108163
108244
  // src/tools/symbols.ts
@@ -109460,8 +109541,8 @@ function isRefusedWorkspaceRoot(target) {
109460
109541
  refused.add(path108.resolve(p));
109461
109542
  }
109462
109543
  };
109463
- add2(os15.homedir());
109464
- add2(os15.tmpdir());
109544
+ add2(os16.homedir());
109545
+ add2(os16.tmpdir());
109465
109546
  add2("/");
109466
109547
  add2("/Users");
109467
109548
  add2("/home");
@@ -114189,6 +114270,8 @@ async function defaultDispatchReviewerAgent(directory, reviewPackage, agentName,
114189
114270
  throw new Error("Failed to create reviewer session");
114190
114271
  }
114191
114272
  const sessionId = sessionResult.data.id;
114273
+ const promptController = new AbortController;
114274
+ let timeoutHandle;
114192
114275
  try {
114193
114276
  const promptText = `You are a read-only phase reviewer for Lean Turbo execution.
114194
114277
 
@@ -114233,16 +114316,23 @@ Be specific and evidence-based. Do not approve a phase with unresolved degraded
114233
114316
  agent: agentName,
114234
114317
  tools: { write: false, edit: false, patch: false },
114235
114318
  parts: [{ type: "text", text: promptText }]
114236
- }
114319
+ },
114320
+ signal: promptController.signal
114237
114321
  }),
114238
- new Promise((_, reject) => setTimeout(() => reject(new Error(`Reviewer dispatch timed out after ${timeoutMs}ms`)), timeoutMs))
114322
+ new Promise((_, reject) => {
114323
+ timeoutHandle = setTimeout(() => {
114324
+ promptController.abort();
114325
+ reject(new Error(`Reviewer dispatch timed out after ${timeoutMs}ms`));
114326
+ }, timeoutMs);
114327
+ })
114239
114328
  ]) : await client.session.prompt({
114240
114329
  path: { id: sessionId },
114241
114330
  body: {
114242
114331
  agent: agentName,
114243
114332
  tools: { write: false, edit: false, patch: false },
114244
114333
  parts: [{ type: "text", text: promptText }]
114245
- }
114334
+ },
114335
+ signal: promptController.signal
114246
114336
  });
114247
114337
  if (!response.data) {
114248
114338
  throw new Error("Reviewer session returned no data");
@@ -114251,6 +114341,9 @@ Be specific and evidence-based. Do not approve a phase with unresolved degraded
114251
114341
  `);
114252
114342
  return textParts;
114253
114343
  } finally {
114344
+ if (timeoutHandle !== undefined)
114345
+ clearTimeout(timeoutHandle);
114346
+ promptController.abort();
114254
114347
  client.session.delete({ path: { id: sessionId } }).catch(() => {});
114255
114348
  }
114256
114349
  }
@@ -114534,6 +114627,7 @@ async function dispatchReviewer(directory, prompt, agentName, timeoutMs) {
114534
114627
  throw new Error("Failed to create auto-review session");
114535
114628
  }
114536
114629
  const sessionId = createResult.data.id;
114630
+ const promptController = new AbortController;
114537
114631
  let timeoutHandle;
114538
114632
  try {
114539
114633
  const promptCall = client.session.prompt({
@@ -114542,12 +114636,16 @@ async function dispatchReviewer(directory, prompt, agentName, timeoutMs) {
114542
114636
  agent: agentName,
114543
114637
  tools: { write: false, edit: false, patch: false },
114544
114638
  parts: [{ type: "text", text: prompt }]
114545
- }
114639
+ },
114640
+ signal: promptController.signal
114546
114641
  });
114547
114642
  const response = await Promise.race([
114548
114643
  promptCall,
114549
114644
  new Promise((_, reject) => {
114550
- timeoutHandle = setTimeout(() => reject(new Error(`auto-review timed out after ${timeoutMs}ms`)), timeoutMs);
114645
+ timeoutHandle = setTimeout(() => {
114646
+ promptController.abort();
114647
+ reject(new Error(`auto-review timed out after ${timeoutMs}ms`));
114648
+ }, timeoutMs);
114551
114649
  })
114552
114650
  ]);
114553
114651
  if (!response.data) {
@@ -114558,6 +114656,7 @@ async function dispatchReviewer(directory, prompt, agentName, timeoutMs) {
114558
114656
  } finally {
114559
114657
  if (timeoutHandle !== undefined)
114560
114658
  clearTimeout(timeoutHandle);
114659
+ promptController.abort();
114561
114660
  client.session.delete({ path: { id: sessionId } }).catch(() => {});
114562
114661
  }
114563
114662
  }
@@ -124901,6 +125000,7 @@ async function runLane(session, dispatcher, lane, directory, timeoutMs, context)
124901
125000
  error: `dispatcher ${decision.action}: ${decision.reason}`
124902
125001
  };
124903
125002
  }
125003
+ const promptController = new AbortController;
124904
125004
  let sessionId;
124905
125005
  try {
124906
125006
  const createTimeoutMessage = `Lane "${lane.id}" session.create timed out after ${timeoutMs}ms`;
@@ -124929,8 +125029,9 @@ async function runLane(session, dispatcher, lane, directory, timeoutMs, context)
124929
125029
  agent: lane.agent,
124930
125030
  tools: buildReadOnlyTools(),
124931
125031
  parts: [{ type: "text", text: lane.prompt }]
124932
- }
124933
- }), timeoutMs, `Lane "${lane.id}" session.prompt timed out after ${timeoutMs}ms`);
125032
+ },
125033
+ signal: promptController.signal
125034
+ }), timeoutMs, `Lane "${lane.id}" session.prompt timed out after ${timeoutMs}ms`, promptController);
124934
125035
  if (!promptResult.data) {
124935
125036
  return failedLane(lane, role, startedAt, `session.prompt failed: ${formatError3(promptResult.error)}`, decision.slot.slotId, decision.slot.runId, sessionId);
124936
125037
  }
@@ -124951,6 +125052,7 @@ async function runLane(session, dispatcher, lane, directory, timeoutMs, context)
124951
125052
  return failedLane(lane, role, startedAt, formatError3(error93), decision.slot.slotId, decision.slot.runId, sessionId);
124952
125053
  } finally {
124953
125054
  dispatcher.releaseSlot(decision.slot.slotId);
125055
+ promptController.abort();
124954
125056
  if (sessionId) {
124955
125057
  scheduleSessionCleanup(session, sessionId);
124956
125058
  }
@@ -125088,13 +125190,19 @@ function scheduleSessionCleanup(session, sessionId) {
125088
125190
  return;
125089
125191
  });
125090
125192
  }
125091
- async function withTimeout2(promise3, timeoutMs, message) {
125193
+ async function withTimeout2(promise3, timeoutMs, message, controller) {
125092
125194
  let timeout;
125093
125195
  try {
125094
125196
  return await Promise.race([
125095
125197
  promise3,
125096
125198
  new Promise((_, reject) => {
125097
- timeout = setTimeout(() => reject(new Error(message)), timeoutMs);
125199
+ timeout = setTimeout(() => {
125200
+ controller?.abort();
125201
+ reject(new Error(message));
125202
+ }, timeoutMs);
125203
+ if (typeof timeout.unref === "function") {
125204
+ timeout.unref();
125205
+ }
125098
125206
  })
125099
125207
  ]);
125100
125208
  } finally {
@@ -127367,7 +127475,9 @@ async function generateMutants(files, ctx) {
127367
127475
  }
127368
127476
  const directory = ctx.directory ?? process.cwd();
127369
127477
  let ephemeralSessionId;
127478
+ const promptController = new AbortController;
127370
127479
  const cleanup = () => {
127480
+ promptController.abort();
127371
127481
  if (ephemeralSessionId) {
127372
127482
  const id = ephemeralSessionId;
127373
127483
  ephemeralSessionId = undefined;
@@ -127414,7 +127524,8 @@ Return ONLY a valid JSON array. No markdown, no code fences, no explanation. Sta
127414
127524
  agent: undefined,
127415
127525
  tools: { write: false, edit: false, patch: false },
127416
127526
  parts: [{ type: "text", text: promptText }]
127417
- }
127527
+ },
127528
+ signal: promptController.signal
127418
127529
  });
127419
127530
  if (!promptResult.data) {
127420
127531
  console.warn(`[generateMutants] LLM prompt failed: ${JSON.stringify(promptResult.error)}; returning empty patch set`);
@@ -128966,7 +129077,7 @@ var knowledge_archive = createSwarmTool({
128966
129077
  if (!found) {
128967
129078
  return JSON.stringify({ success: false, message: "entry not found" });
128968
129079
  }
128969
- await recordKnowledgeEvent(directory, {
129080
+ const tombstone = {
128970
129081
  type: "archived",
128971
129082
  entry_id: id,
128972
129083
  tier,
@@ -128975,7 +129086,12 @@ var knowledge_archive = createSwarmTool({
128975
129086
  mode,
128976
129087
  evidence,
128977
129088
  previous_status: previousStatus
128978
- });
129089
+ };
129090
+ if (tier === "hive") {
129091
+ await recordHiveKnowledgeEvent(tombstone);
129092
+ } else {
129093
+ await recordKnowledgeEvent(directory, tombstone);
129094
+ }
128979
129095
  return JSON.stringify({
128980
129096
  success: true,
128981
129097
  id,
@@ -130342,10 +130458,17 @@ class LeanTurboRunner {
130342
130458
  if (!session) {
130343
130459
  return { ok: false, error: "NO_CLIENT" };
130344
130460
  }
130345
- const dispatchPromise = this._doDispatch(session, lane, agentName, worktreeDirectory);
130461
+ const promptController = new AbortController;
130462
+ const dispatchPromise = this._doDispatch(session, lane, agentName, worktreeDirectory, promptController);
130346
130463
  const timeoutMs = LeanTurboRunner._internals.laneDispatchTimeoutMs;
130347
130464
  if (timeoutMs !== undefined && timeoutMs > 0) {
130348
- const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error(`Lane dispatch timed out after ${timeoutMs}ms`)), timeoutMs));
130465
+ let timeoutHandle;
130466
+ const timeoutPromise = new Promise((_, reject) => {
130467
+ timeoutHandle = setTimeout(() => {
130468
+ promptController.abort();
130469
+ reject(new Error(`Lane dispatch timed out after ${timeoutMs}ms`));
130470
+ }, timeoutMs);
130471
+ });
130349
130472
  try {
130350
130473
  return await Promise.race([dispatchPromise, timeoutPromise]);
130351
130474
  } catch (err2) {
@@ -130369,11 +130492,15 @@ class LeanTurboRunner {
130369
130492
  return { ok: false, error: err2.message };
130370
130493
  }
130371
130494
  throw err2;
130495
+ } finally {
130496
+ if (timeoutHandle !== undefined)
130497
+ clearTimeout(timeoutHandle);
130372
130498
  }
130373
130499
  }
130374
130500
  return dispatchPromise;
130375
130501
  }
130376
- async _doDispatch(session, lane, agentName, worktreeDirectory) {
130502
+ async _doDispatch(session, lane, agentName, worktreeDirectory, abortController) {
130503
+ let sessionId;
130377
130504
  try {
130378
130505
  const effectiveDirectory = worktreeDirectory ?? this._directory;
130379
130506
  const createResult = await session.create({
@@ -130391,7 +130518,7 @@ class LeanTurboRunner {
130391
130518
  error: `session.create failed: ${typeof createResult.error === "string" ? createResult.error : JSON.stringify(createResult.error)}`
130392
130519
  };
130393
130520
  }
130394
- const sessionId = createResult.data.id;
130521
+ sessionId = createResult.data.id;
130395
130522
  const promptText = this._buildLanePrompt(lane);
130396
130523
  const promptResult = await session.prompt({
130397
130524
  path: { id: sessionId },
@@ -130399,9 +130526,11 @@ class LeanTurboRunner {
130399
130526
  agent: agentName,
130400
130527
  tools: { write: true, edit: true, patch: true },
130401
130528
  parts: [{ type: "text", text: promptText }]
130402
- }
130529
+ },
130530
+ signal: abortController?.signal
130403
130531
  });
130404
130532
  if (!promptResult.data) {
130533
+ abortController?.abort();
130405
130534
  session.delete({ path: { id: sessionId } }).catch(() => {});
130406
130535
  return {
130407
130536
  ok: false,
@@ -130410,6 +130539,10 @@ class LeanTurboRunner {
130410
130539
  }
130411
130540
  return { ok: true, sessionId };
130412
130541
  } catch (err2) {
130542
+ if (sessionId) {
130543
+ abortController?.abort();
130544
+ session.delete({ path: { id: sessionId } }).catch(() => {});
130545
+ }
130413
130546
  const msg = err2 instanceof Error ? err2.message : String(err2);
130414
130547
  return { ok: false, error: msg };
130415
130548
  }
@@ -69,6 +69,7 @@ export interface SessionOps {
69
69
  text: string;
70
70
  }>;
71
71
  };
72
+ signal?: AbortSignal;
72
73
  }): Promise<{
73
74
  data?: {
74
75
  parts?: Array<{
@@ -10,6 +10,10 @@
10
10
  * - 'archive' (default): set status='archived' — TTL-exempt, hidden from recall.
11
11
  * - 'quarantine': set status='quarantined' — suspected-bad, hidden from recall.
12
12
  * - 'purge': hard-delete the JSONL line. Requires allow_purge:true.
13
+ *
14
+ * Tiers:
15
+ * - 'swarm' (default): archives a project-local swarm entry.
16
+ * - 'hive': archives a shared hive entry (cross-project knowledge).
13
17
  */
14
18
  import { createSwarmTool } from './create-tool.js';
15
19
  export declare const knowledge_archive: ReturnType<typeof createSwarmTool>;
@@ -63,6 +63,7 @@ interface SessionClient {
63
63
  text: string;
64
64
  }>;
65
65
  };
66
+ signal?: AbortSignal;
66
67
  }): Promise<{
67
68
  data: {
68
69
  parts: Array<{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.77.6",
3
+ "version": "7.78.0",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",