@wrongstack/core 0.308.5 → 0.308.7

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/index.js CHANGED
@@ -1171,7 +1171,7 @@ __export(review_report_store_exports, {
1171
1171
  REPORT_STORE_FILE: () => REPORT_STORE_FILE,
1172
1172
  resolveReportStorePath: () => resolveReportStorePath
1173
1173
  });
1174
- import { randomUUID as randomUUID30 } from "node:crypto";
1174
+ import { randomUUID as randomUUID31 } from "node:crypto";
1175
1175
  import * as fsp35 from "node:fs/promises";
1176
1176
  import * as path76 from "node:path";
1177
1177
  function resolveReportStorePath(projectDir) {
@@ -1238,7 +1238,7 @@ var init_review_report_store = __esm({
1238
1238
  ...input.evidenceChecks !== void 0 ? { evidenceChecks: input.evidenceChecks } : {}
1239
1239
  };
1240
1240
  const createdEvent = {
1241
- id: randomUUID30(),
1241
+ id: randomUUID31(),
1242
1242
  reportId: report.id,
1243
1243
  eventType: "created",
1244
1244
  fromLifecycle: null,
@@ -1261,7 +1261,7 @@ var init_review_report_store = __esm({
1261
1261
  const from = this._materialize(entry).lifecycle;
1262
1262
  validateReportTransition(from, to);
1263
1263
  const event = {
1264
- id: randomUUID30(),
1264
+ id: randomUUID31(),
1265
1265
  reportId,
1266
1266
  eventType: reportEventTypeFor(to),
1267
1267
  fromLifecycle: from,
@@ -1304,7 +1304,7 @@ var init_review_report_store = __esm({
1304
1304
  if (!entry) throw new Error(`Review report not found: ${reportId}`);
1305
1305
  const materialized = this._materialize(entry);
1306
1306
  const event = {
1307
- id: randomUUID30(),
1307
+ id: randomUUID31(),
1308
1308
  reportId,
1309
1309
  eventType: "note_added",
1310
1310
  fromLifecycle: materialized.lifecycle,
@@ -1527,7 +1527,7 @@ __export(review_finding_store_exports, {
1527
1527
  JsonlFindingStore: () => JsonlFindingStore,
1528
1528
  resolveFindingStorePath: () => resolveFindingStorePath
1529
1529
  });
1530
- import { randomUUID as randomUUID40 } from "node:crypto";
1530
+ import { randomUUID as randomUUID41 } from "node:crypto";
1531
1531
  import * as fsp48 from "node:fs/promises";
1532
1532
  import * as path105 from "node:path";
1533
1533
  function resolveFindingStorePath(projectDir) {
@@ -1616,7 +1616,7 @@ var init_review_finding_store = __esm({
1616
1616
  validateTransition(from, to);
1617
1617
  validateResolution(to, opts?.outcome);
1618
1618
  const event = {
1619
- id: randomUUID40(),
1619
+ id: randomUUID41(),
1620
1620
  findingId,
1621
1621
  eventType: to === "resolved" ? "resolved" : to === "ignored" ? "ignored" : this._eventTypeFor(to),
1622
1622
  fromStatus: from,
@@ -1800,7 +1800,7 @@ var init_review_finding_store = __esm({
1800
1800
  }
1801
1801
  _makeEvent(findingId, eventType, fromStatus, toStatus, context) {
1802
1802
  return {
1803
- id: randomUUID40(),
1803
+ id: randomUUID41(),
1804
1804
  findingId,
1805
1805
  eventType,
1806
1806
  fromStatus,
@@ -21958,6 +21958,7 @@ function createProjectAgent(input, projectRoot) {
21958
21958
  var skillSet = (...names) => names;
21959
21959
  var ROLE_SKILL_SETS = {
21960
21960
  explore: skillSet("research-web", "node-modern", "typescript-strict"),
21961
+ "explore-companion": skillSet("node-modern", "typescript-strict"),
21961
21962
  search: skillSet("bug-hunter", "typescript-strict", "research-web"),
21962
21963
  research: skillSet("research-web", "tech-stack", "security-scanner", "api-design"),
21963
21964
  analyst: skillSet("sdd", "api-design", "testing", "security-scanner"),
@@ -30996,7 +30997,7 @@ function buildKanbanFleetTaskPrompt(board, task, lease) {
30996
30997
  const dependencyLines = (task.dependsOn ?? []).map((depId) => board.tasks.find((candidate) => candidate.id === depId)).filter((dep) => Boolean(dep)).map((dep) => `- ${dep.title} [${dep.status}] (${dep.id})`);
30997
30998
  const checks = task.successCriteria?.map((check) => `- ${check.description}`).join("\n");
30998
30999
  const metrics = task.goalMetrics?.map(
30999
- (metric) => `- ${metric.name}: ${metric.current ?? "n/a"}${metric.target !== void 0 ? ` / ${metric.target}` : ""}${metric.unit ? ` ${metric.unit}` : ""} [${metric.status}]`
31000
+ (metric) => `- ${metric.name}: ${metric.current ?? "n/a"}${metric.target !== void 0 ? ` / ${metric.direction === "at_most" ? "\u2264" : "\u2265"} ${metric.target}` : ""}${metric.unit ? ` ${metric.unit}` : ""} [${metric.status}]`
31000
31001
  ).join("\n");
31001
31002
  const chain = task.chain ? [
31002
31003
  `chainId: ${task.chain.chainId}`,
@@ -38805,6 +38806,28 @@ var SHADOW_AGENT = {
38805
38806
  ...defineAgent("shadow-agent", "Shadow"),
38806
38807
  skillNames: [...SHADOW_AGENT_SKILLS]
38807
38808
  };
38809
+ var EXPLORE_COMPANION_AGENT = {
38810
+ ...defineAgent("explore-companion", "Explore Companion"),
38811
+ tools: [...TOOLS.read, ...TOOLS.index],
38812
+ // Read-only, triple-enforced: allowlist has no write/bash, and the
38813
+ // disabled list blocks the escape hatches explicitly.
38814
+ disabledTools: [
38815
+ "write",
38816
+ "edit",
38817
+ "replace",
38818
+ "patch",
38819
+ "bash",
38820
+ "exec",
38821
+ "delegate",
38822
+ "spawn_subagent",
38823
+ "assign_task"
38824
+ ],
38825
+ skillNames: [...ROLE_SKILL_SETS["explore-companion"]],
38826
+ spawnBudgetExempt: true,
38827
+ // Findings travel via mailbox + submit_result, not the leader's stream.
38828
+ textStream: "silent",
38829
+ toolStream: "silent"
38830
+ };
38808
38831
  var CRITIC_AGENT = defineAgent("critic", "Critic");
38809
38832
  var GENERIC_AGENT = defineAgent("generic", "Generic Project Agent");
38810
38833
  function withDispatchMetadata(definition) {
@@ -38823,6 +38846,7 @@ var FLEET_ROSTER = {
38823
38846
  critic: CRITIC_AGENT,
38824
38847
  generic: GENERIC_AGENT,
38825
38848
  "shadow-agent": SHADOW_AGENT,
38849
+ "explore-companion": EXPLORE_COMPANION_AGENT,
38826
38850
  ...Object.fromEntries(
38827
38851
  ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, withDispatchMetadata(d)])
38828
38852
  )
@@ -38846,6 +38870,13 @@ var FLEET_ROSTER_BUDGETS = {
38846
38870
  maxTokens: 96e3,
38847
38871
  maxCostUsd: 0.5
38848
38872
  },
38873
+ "explore-companion": {
38874
+ idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
38875
+ maxIterations: 3e3,
38876
+ maxToolCalls: 8e3,
38877
+ maxTokens: 96e3,
38878
+ maxCostUsd: 0.5
38879
+ },
38849
38880
  ...Object.fromEntries(
38850
38881
  ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, d.budget])
38851
38882
  )
@@ -44017,6 +44048,334 @@ async function readSubagentPartial(opts, subagentId) {
44017
44048
  return void 0;
44018
44049
  }
44019
44050
 
44051
+ // src/coordination/explore-companion.ts
44052
+ import { randomUUID as randomUUID23 } from "node:crypto";
44053
+ var DEFAULT_EXPLORE_COMPANION_AGENT_ID = "explore-companion";
44054
+ var DEFAULT_PROBE_COOLDOWN_MS = 12e4;
44055
+ var DEFAULT_MAX_PENDING_PROBES = 8;
44056
+ var DEFAULT_MAILBOX_POLL_INTERVAL_MS = 5e3;
44057
+ var DEFAULT_EXPLORE_EDIT_TOOLS = [
44058
+ "edit",
44059
+ "write",
44060
+ "patch",
44061
+ "multi_edit",
44062
+ "multiedit",
44063
+ "str_replace"
44064
+ ];
44065
+ var DEFAULT_EXPLORE_SEARCH_TOOLS = [
44066
+ "search",
44067
+ "grep",
44068
+ "codebase-search"
44069
+ ];
44070
+ function buildProbeTaskText(probe2) {
44071
+ const payload = { probe: probe2.probe };
44072
+ if (probe2.hint) payload.hint = probe2.hint;
44073
+ if (probe2.context) payload.context = probe2.context;
44074
+ return JSON.stringify(payload, null, 2);
44075
+ }
44076
+ function extractedPath(input) {
44077
+ if (!input || typeof input !== "object") return void 0;
44078
+ const rec = input;
44079
+ const candidate = typeof rec["path"] === "string" ? rec["path"] : typeof rec["file"] === "string" ? rec["file"] : void 0;
44080
+ return candidate && candidate.length > 0 ? candidate : void 0;
44081
+ }
44082
+ function looksEmpty(e) {
44083
+ if (typeof e.outputLines === "number" && e.outputLines === 0) return true;
44084
+ const out = e.output ?? "";
44085
+ return /(?:^|\n)(?:no |0 )(?:matches|results|files? found|occurrences)/i.test(out) || /total\s*:\s*0\b/i.test(out);
44086
+ }
44087
+ function extractSubjectTokens(text2) {
44088
+ const out = [];
44089
+ const fileRe = /([\w@./-]+\.(?:[cm]?[jt]sx?|json|md|py|go|rs|ya?ml))\b/g;
44090
+ for (const m of text2.matchAll(fileRe)) {
44091
+ const value = m[1];
44092
+ if (value) out.push({ kind: "file", value });
44093
+ }
44094
+ const symRe = /\b[A-Z][A-Za-z0-9_]{2,}\b/g;
44095
+ for (const m of text2.matchAll(symRe)) {
44096
+ out.push({ kind: "symbol", value: m[0] });
44097
+ }
44098
+ return out;
44099
+ }
44100
+ var ExploreCompanion = class {
44101
+ constructor(opts) {
44102
+ this.opts = opts;
44103
+ this.cfg = this.resolveConfig(opts);
44104
+ }
44105
+ opts;
44106
+ unsubscribers = [];
44107
+ /** Paths the leader has read (readSet) — feeds edit-unread + unfamiliar-read. */
44108
+ readSet = /* @__PURE__ */ new Set();
44109
+ /** subject → last probe time; cooldown gate. Survives detach/reconfigure. */
44110
+ probedAt = /* @__PURE__ */ new Map();
44111
+ /** todo id → last observed status, per leader agent. */
44112
+ todoSeen = /* @__PURE__ */ new Map();
44113
+ pending = [];
44114
+ inFlight = false;
44115
+ pollTimer;
44116
+ running = false;
44117
+ hostStarted = false;
44118
+ cfg;
44119
+ resolveConfig(opts) {
44120
+ const signals = opts.signals ?? {};
44121
+ return {
44122
+ enabled: opts.enabled ?? true,
44123
+ cooldownMs: opts.cooldownMs ?? DEFAULT_PROBE_COOLDOWN_MS,
44124
+ maxPending: opts.maxPending ?? DEFAULT_MAX_PENDING_PROBES,
44125
+ pollIntervalMs: opts.pollIntervalMs ?? DEFAULT_MAILBOX_POLL_INTERVAL_MS,
44126
+ companionAgentId: opts.companionAgentId ?? DEFAULT_EXPLORE_COMPANION_AGENT_ID,
44127
+ signals: {
44128
+ editUnreadFile: signals.editUnreadFile ?? true,
44129
+ searchZeroHits: signals.searchZeroHits ?? true,
44130
+ unfamiliarRead: signals.unfamiliarRead ?? true,
44131
+ todoInProgress: signals.todoInProgress ?? true,
44132
+ errorSymbol: signals.errorSymbol ?? true,
44133
+ mailboxAsk: signals.mailboxAsk ?? true
44134
+ },
44135
+ fileEditTools: new Set(
44136
+ (opts.fileEditTools ?? DEFAULT_EXPLORE_EDIT_TOOLS).map((t2) => t2.toLowerCase())
44137
+ ),
44138
+ searchTools: new Set(
44139
+ (opts.searchTools ?? DEFAULT_EXPLORE_SEARCH_TOOLS).map((t2) => t2.toLowerCase())
44140
+ )
44141
+ };
44142
+ }
44143
+ /** Resolve the leader's own session id for event filtering. */
44144
+ resolveLeaderSessionId() {
44145
+ const sid = this.opts.leaderSessionId;
44146
+ return typeof sid === "function" ? sid() : sid;
44147
+ }
44148
+ /** Resolve the leader's agent id for todo diffing (optional signal). */
44149
+ resolveLeaderAgentId() {
44150
+ const aid = this.opts.leaderAgentId;
44151
+ if (!aid) return void 0;
44152
+ return typeof aid === "function" ? aid() : aid;
44153
+ }
44154
+ /** Re-apply tunables to a (possibly running) companion. */
44155
+ reconfigure(next) {
44156
+ const merged = { ...this.opts, ...next };
44157
+ const nextCfg = this.resolveConfig(merged);
44158
+ const changed = nextCfg.enabled !== this.cfg.enabled || nextCfg.cooldownMs !== this.cfg.cooldownMs || nextCfg.maxPending !== this.cfg.maxPending || nextCfg.pollIntervalMs !== this.cfg.pollIntervalMs || nextCfg.companionAgentId !== this.cfg.companionAgentId || Object.keys(nextCfg.signals).some(
44159
+ (k) => nextCfg.signals[k] !== this.cfg.signals[k]
44160
+ );
44161
+ this.cfg = nextCfg;
44162
+ if (!changed) return false;
44163
+ if (this.hostStarted) {
44164
+ this.detach();
44165
+ this.attach();
44166
+ }
44167
+ return true;
44168
+ }
44169
+ /** Begin watching. Idempotent; a disabled companion records intent only. */
44170
+ start() {
44171
+ this.hostStarted = true;
44172
+ this.attach();
44173
+ }
44174
+ /** Stop watching and drop the host's intent to watch. */
44175
+ stop() {
44176
+ this.hostStarted = false;
44177
+ this.detach();
44178
+ }
44179
+ /** True while the watchers are attached. */
44180
+ isRunning() {
44181
+ return this.running;
44182
+ }
44183
+ /** Number of probes queued but not yet dispatched (for status surfaces). */
44184
+ pendingCount() {
44185
+ return this.pending.length;
44186
+ }
44187
+ attach() {
44188
+ if (!this.cfg.enabled || this.running) return;
44189
+ this.running = true;
44190
+ this.unsubscribers.push(
44191
+ this.opts.events.on("tool.executed", (e) => {
44192
+ const lsid = this.resolveLeaderSessionId();
44193
+ if (lsid && e.sessionId && e.sessionId !== lsid) return;
44194
+ this.trackToolExecuted(e);
44195
+ })
44196
+ );
44197
+ if (this.cfg.signals.todoInProgress && this.resolveLeaderAgentId()) {
44198
+ this.unsubscribers.push(
44199
+ this.opts.events.on("session.agents_updated", (e) => {
44200
+ const lsid = this.resolveLeaderSessionId();
44201
+ if (lsid && e.sessionId && e.sessionId !== lsid) return;
44202
+ this.trackAgentTodos(e.agents);
44203
+ })
44204
+ );
44205
+ }
44206
+ if (this.cfg.signals.errorSymbol) {
44207
+ this.unsubscribers.push(
44208
+ this.opts.events.on("error", (e) => {
44209
+ const lsid = this.resolveLeaderSessionId();
44210
+ if (lsid && e.sessionId && e.sessionId !== lsid) return;
44211
+ this.trackError(e.err);
44212
+ })
44213
+ );
44214
+ }
44215
+ if (this.cfg.signals.mailboxAsk) {
44216
+ this.pollTimer = setInterval(() => {
44217
+ void this.pollMailbox();
44218
+ }, this.cfg.pollIntervalMs);
44219
+ this.pollTimer.unref?.();
44220
+ }
44221
+ }
44222
+ /** Tear down watchers without touching host intent. Cooldowns survive. */
44223
+ detach() {
44224
+ for (const unsub of this.unsubscribers.splice(0)) unsub();
44225
+ if (this.pollTimer) {
44226
+ clearInterval(this.pollTimer);
44227
+ this.pollTimer = void 0;
44228
+ }
44229
+ this.running = false;
44230
+ }
44231
+ // ── signal handlers ──────────────────────────────────────────────────────
44232
+ trackToolExecuted(e) {
44233
+ const tool = e.name.toLowerCase();
44234
+ const path131 = extractedPath(e.input);
44235
+ if (e.ok && this.cfg.signals.editUnreadFile && this.cfg.fileEditTools.has(tool) && path131) {
44236
+ if (!this.readSet.has(path131)) {
44237
+ this.engage({
44238
+ id: randomUUID23(),
44239
+ probe: `Map file ${path131}: role, exports, dependencies, and callers \u2014 the leader is about to edit it.`,
44240
+ hint: { file: path131 },
44241
+ context: `Leader edited ${path131} without reading it first.`,
44242
+ source: "edit_unread_file",
44243
+ subject: `file:${path131}`,
44244
+ createdAt: this.now()
44245
+ });
44246
+ }
44247
+ return;
44248
+ }
44249
+ if (e.ok && this.cfg.signals.unfamiliarRead && tool === "read" && path131) {
44250
+ if (!this.readSet.has(path131)) {
44251
+ this.readSet.add(path131);
44252
+ this.engage({
44253
+ id: randomUUID23(),
44254
+ probe: `Skeleton + callers + dependents of ${path131}: what it exports, who imports it, and how it fits the feature flow.`,
44255
+ hint: { file: path131 },
44256
+ context: `Leader read unfamiliar file ${path131}.`,
44257
+ source: "unfamiliar_read",
44258
+ subject: `file:${path131}`,
44259
+ createdAt: this.now()
44260
+ });
44261
+ }
44262
+ return;
44263
+ }
44264
+ if (e.ok && this.cfg.signals.searchZeroHits && this.cfg.searchTools.has(tool) && looksEmpty(e)) {
44265
+ const input = e.input ?? {};
44266
+ const query = typeof input["query"] === "string" ? input["query"] : typeof input["pattern"] === "string" ? input["pattern"] : "";
44267
+ this.engage({
44268
+ id: randomUUID23(),
44269
+ probe: query ? `Locate "${query}" \u2014 the leader's ${e.name} returned no hits. Try synonyms, a refreshed index, and lexical fallbacks.` : `The leader's ${e.name} returned no results. Find where the concept actually lives.`,
44270
+ hint: query ? { symbol: query } : void 0,
44271
+ context: `${e.name} for "${query}" returned zero results.`,
44272
+ source: "search_zero_hits",
44273
+ subject: `search:${query}`,
44274
+ createdAt: this.now()
44275
+ });
44276
+ }
44277
+ }
44278
+ trackAgentTodos(agents) {
44279
+ const leaderId = this.resolveLeaderAgentId();
44280
+ if (!leaderId) return;
44281
+ const leader = agents.find((a) => a.id === leaderId);
44282
+ if (!leader?.todos) return;
44283
+ for (const todo of leader.todos) {
44284
+ const prev = this.todoSeen.get(todo.id);
44285
+ if (prev !== "in_progress" && todo.status === "in_progress") {
44286
+ const mentions = extractSubjectTokens(todo.content);
44287
+ const first = mentions[0];
44288
+ this.engage({
44289
+ id: randomUUID23(),
44290
+ probe: `Pre-map the files/symbols behind this in-progress todo: "${todo.content.slice(0, 160)}".`,
44291
+ hint: first ? { [first.kind]: first.value } : void 0,
44292
+ context: `Todo "${todo.content.slice(0, 120)}" flipped to in_progress.`,
44293
+ source: "todo_in_progress",
44294
+ subject: `todo:${todo.id}`,
44295
+ createdAt: this.now()
44296
+ });
44297
+ }
44298
+ this.todoSeen.set(todo.id, todo.status);
44299
+ }
44300
+ }
44301
+ trackError(err) {
44302
+ const tokens = extractSubjectTokens(err.message);
44303
+ for (const token of tokens.slice(0, 2)) {
44304
+ this.engage({
44305
+ id: randomUUID23(),
44306
+ probe: `What is ${token.value}, where does it live, and who uses it? The leader hit an error naming it.`,
44307
+ hint: { [token.kind]: token.value },
44308
+ context: `Error: ${err.message.slice(0, 300)}`,
44309
+ source: "error_symbol",
44310
+ subject: `token:${token.value}`,
44311
+ createdAt: this.now()
44312
+ });
44313
+ }
44314
+ }
44315
+ async pollMailbox() {
44316
+ if (!this.cfg.enabled || !this.cfg.signals.mailboxAsk) return;
44317
+ try {
44318
+ const messages = await this.opts.mailbox.query({
44319
+ unreadBy: this.cfg.companionAgentId,
44320
+ limit: 20
44321
+ });
44322
+ const lsid = this.resolveLeaderSessionId();
44323
+ for (const msg of messages) {
44324
+ if (msg.type !== "ask" && msg.type !== "assign") continue;
44325
+ const fromLeader = isMailboxLeader(msg.from) || lsid != null && msg.senderSessionId === lsid;
44326
+ if (!fromLeader) continue;
44327
+ this.engage({
44328
+ id: randomUUID23(),
44329
+ probe: msg.body.trim().slice(0, 2e3) || msg.subject,
44330
+ context: `Direct ask from ${msg.from}: ${msg.subject}`,
44331
+ source: "mailbox_ask",
44332
+ subject: `mail:${msg.id}`,
44333
+ createdAt: this.now()
44334
+ });
44335
+ await this.opts.mailbox.ack({
44336
+ messageId: msg.id,
44337
+ readerId: this.cfg.companionAgentId,
44338
+ read: true,
44339
+ completed: true
44340
+ }).catch(() => {
44341
+ });
44342
+ }
44343
+ } catch {
44344
+ }
44345
+ }
44346
+ // ── engagement ───────────────────────────────────────────────────────────
44347
+ cooldownOk(subject2) {
44348
+ const last = this.probedAt.get(subject2);
44349
+ return last === void 0 || this.now() - last >= this.cfg.cooldownMs;
44350
+ }
44351
+ now() {
44352
+ return this.opts.now ? this.opts.now() : Date.now();
44353
+ }
44354
+ engage(probe2) {
44355
+ if (!this.cfg.enabled) return;
44356
+ if (!this.cooldownOk(probe2.subject)) return;
44357
+ this.probedAt.set(probe2.subject, this.now());
44358
+ if (this.pending.length >= this.cfg.maxPending) {
44359
+ this.pending.shift();
44360
+ }
44361
+ this.pending.push(probe2);
44362
+ void this.drain();
44363
+ }
44364
+ async drain() {
44365
+ if (this.inFlight) return;
44366
+ const probe2 = this.pending.shift();
44367
+ if (!probe2) return;
44368
+ this.inFlight = true;
44369
+ try {
44370
+ await this.opts.onProbe(probe2);
44371
+ } catch {
44372
+ } finally {
44373
+ this.inFlight = false;
44374
+ if (this.pending.length > 0) void this.drain();
44375
+ }
44376
+ }
44377
+ };
44378
+
44020
44379
  // src/coordination/mailbox-codecs.ts
44021
44380
  var MailboxValidationError = class extends Error {
44022
44381
  code;
@@ -47867,7 +48226,7 @@ function createAgentMonitorService(opts) {
47867
48226
  }
47868
48227
 
47869
48228
  // src/coordination/autonomous-brain.ts
47870
- import { randomUUID as randomUUID23 } from "node:crypto";
48229
+ import { randomUUID as randomUUID24 } from "node:crypto";
47871
48230
  var AutonomousBrain = class {
47872
48231
  graph;
47873
48232
  // Fleet bus for emitting decisions — null-safe, no-op if not provided
@@ -47973,7 +48332,7 @@ var AutonomousBrain = class {
47973
48332
  consequence: i === 0 ? `Spawn the most appropriate agent for: ${taskDescription.slice(0, 80)}` : `Spawn an alternative agent for the same task`
47974
48333
  }));
47975
48334
  return this.decideAuto({
47976
- id: randomUUID23(),
48335
+ id: randomUUID24(),
47977
48336
  source,
47978
48337
  decisionType: "spawn",
47979
48338
  question: `Should we spawn a subagent for this task?`,
@@ -48016,7 +48375,7 @@ var AutonomousBrain = class {
48016
48375
  }
48017
48376
  ];
48018
48377
  return this.decideAuto({
48019
- id: randomUUID23(),
48378
+ id: randomUUID24(),
48020
48379
  source,
48021
48380
  decisionType: "approve_change",
48022
48381
  question: `Should we approve the change "${change.title}"?`,
@@ -48075,7 +48434,7 @@ var AutonomousBrain = class {
48075
48434
  consequence: "Break the task into smaller sub-tasks"
48076
48435
  });
48077
48436
  return this.decideAuto({
48078
- id: randomUUID23(),
48437
+ id: randomUUID24(),
48079
48438
  source,
48080
48439
  decisionType: "escalate_task",
48081
48440
  question: `Task failed: ${error2.slice(0, 100)}. How should we proceed?`,
@@ -48209,12 +48568,12 @@ ${ctx.error}`);
48209
48568
  };
48210
48569
 
48211
48570
  // src/coordination/autonomous-coordinator.ts
48212
- import { randomUUID as randomUUID26 } from "node:crypto";
48571
+ import { randomUUID as randomUUID27 } from "node:crypto";
48213
48572
 
48214
48573
  // src/coordination/knowledge-graph.ts
48215
48574
  init_file_permissions();
48216
48575
  init_atomic_write();
48217
- import { randomUUID as randomUUID24 } from "node:crypto";
48576
+ import { randomUUID as randomUUID25 } from "node:crypto";
48218
48577
  import * as fsp34 from "node:fs/promises";
48219
48578
  import * as path73 from "node:path";
48220
48579
  var DEFAULT_MAX_NODES = 2e3;
@@ -48262,7 +48621,7 @@ var KnowledgeGraph = class _KnowledgeGraph {
48262
48621
  * Returns the node with its assigned id.
48263
48622
  */
48264
48623
  async add(node) {
48265
- const full = { id: randomUUID24(), ...node };
48624
+ const full = { id: randomUUID25(), ...node };
48266
48625
  this.nodes.set(full.id, full);
48267
48626
  this._trackSeq(full.id);
48268
48627
  this._addToIndex(full, this._indexKeys(full));
@@ -48391,8 +48750,8 @@ var KnowledgeGraph = class _KnowledgeGraph {
48391
48750
  if (this.subs.size >= MAX_SUBSCRIPTIONS) {
48392
48751
  throw new Error(`Knowledge graph subscription limit reached (${MAX_SUBSCRIPTIONS})`);
48393
48752
  }
48394
- const channel2 = randomUUID24();
48395
- const sub = { id: randomUUID24(), agentId, filter, channel: channel2 };
48753
+ const channel2 = randomUUID25();
48754
+ const sub = { id: randomUUID25(), agentId, filter, channel: channel2 };
48396
48755
  this.subs.set(channel2, sub);
48397
48756
  this.pendingDeliveries.set(channel2, []);
48398
48757
  return channel2;
@@ -48873,7 +49232,7 @@ var TaskDAG = class {
48873
49232
  };
48874
49233
 
48875
49234
  // src/coordination/task-auctioneer.ts
48876
- import { randomUUID as randomUUID25 } from "node:crypto";
49235
+ import { randomUUID as randomUUID26 } from "node:crypto";
48877
49236
  function isTerminalGoalStatus(status) {
48878
49237
  return status === "done" || status === "failed";
48879
49238
  }
@@ -48996,7 +49355,7 @@ var TaskAuctioneer = class {
48996
49355
  const score = dispatchResult.confidence * (dispatchResult.role === agent.agentRole ? 1.2 : 1);
48997
49356
  if (score < this.minConfidence) return false;
48998
49357
  const bid = {
48999
- id: randomUUID25(),
49358
+ id: randomUUID26(),
49000
49359
  taskId,
49001
49360
  agentId: agent.agentId,
49002
49361
  agentName: agent.agentName,
@@ -49933,7 +50292,7 @@ var AutonomousCoordinator = class _AutonomousCoordinator {
49933
50292
  break;
49934
50293
  }
49935
50294
  const decision = await this.brain.decideAuto({
49936
- id: randomUUID26(),
50295
+ id: randomUUID27(),
49937
50296
  source: "system",
49938
50297
  decisionType: "prioritize_goals",
49939
50298
  question: `What should we work on next? Open goals: ${dispatchable.map((g) => g.title).join(", ")}`,
@@ -50848,7 +51207,7 @@ var TOKENS = {
50848
51207
  init_errors();
50849
51208
 
50850
51209
  // src/hq/factory.ts
50851
- import { createHash as createHash24, randomUUID as randomUUID29 } from "node:crypto";
51210
+ import { createHash as createHash24, randomUUID as randomUUID30 } from "node:crypto";
50852
51211
  import * as fs30 from "node:fs";
50853
51212
  import { hostname as hostname3 } from "node:os";
50854
51213
  import { basename as basename15 } from "node:path";
@@ -50856,7 +51215,7 @@ import { basename as basename15 } from "node:path";
50856
51215
  // src/hq/auth-store.ts
50857
51216
  init_file_permissions();
50858
51217
  init_atomic_write();
50859
- import { createHash as createHash23, randomBytes as randomBytes4, randomUUID as randomUUID27, scrypt, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
51218
+ import { createHash as createHash23, randomBytes as randomBytes4, randomUUID as randomUUID28, scrypt, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
50860
51219
  import * as syncFs from "node:fs";
50861
51220
  import * as fs29 from "node:fs/promises";
50862
51221
  import * as path75 from "node:path";
@@ -51183,8 +51542,8 @@ function mintHqToken(labelOrOptions) {
51183
51542
  const at = opts.now ?? Date.now();
51184
51543
  const createdAtIso = new Date(at).toISOString();
51185
51544
  return {
51186
- id: randomUUID27(),
51187
- token: randomUUID27().replace(/-/g, "") + randomUUID27().replace(/-/g, ""),
51545
+ id: randomUUID28(),
51546
+ token: randomUUID28().replace(/-/g, "") + randomUUID28().replace(/-/g, ""),
51188
51547
  createdAt: createdAtIso,
51189
51548
  ...opts.label ? { label: opts.label } : {},
51190
51549
  ...opts.ttlMs !== void 0 && Number.isFinite(opts.ttlMs) && opts.ttlMs > 0 ? { expiresAt: new Date(at + opts.ttlMs).toISOString() } : {}
@@ -51244,7 +51603,7 @@ function watchHqAuthFile(dataDir, onChange, opts = {}) {
51244
51603
  }
51245
51604
 
51246
51605
  // src/hq/publisher.ts
51247
- import { randomUUID as randomUUID28 } from "node:crypto";
51606
+ import { randomUUID as randomUUID29 } from "node:crypto";
51248
51607
  import * as v82 from "node:v8";
51249
51608
 
51250
51609
  // src/hq/protocol/governance.ts
@@ -52318,7 +52677,7 @@ var HqPublisher = class {
52318
52677
  this.options = options;
52319
52678
  this.socketFactory = options.socketFactory ?? defaultSocketFactory;
52320
52679
  this.now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
52321
- this.idFactory = options.idFactory ?? randomUUID28;
52680
+ this.idFactory = options.idFactory ?? randomUUID29;
52322
52681
  this.capabilities = options.capabilities ?? [
52323
52682
  "telemetry.publish",
52324
52683
  "mailbox.summary",
@@ -52902,7 +53261,7 @@ function createHqPublisherFromEnv(options) {
52902
53261
  const projectAlias = config.projectAlias?.trim() || void 0;
52903
53262
  const projectName = projectAlias ?? options.projectName ?? (basename15(options.projectRoot) || "unknown");
52904
53263
  const client = {
52905
- clientId: `${machineId}:${options.clientKind}:${process.pid}:${randomUUID29().slice(0, 8)}`,
53264
+ clientId: `${machineId}:${options.clientKind}:${process.pid}:${randomUUID30().slice(0, 8)}`,
52906
53265
  kind: options.clientKind,
52907
53266
  machineId,
52908
53267
  ...host ? { hostname: host } : {},
@@ -54187,7 +54546,7 @@ async function getPromptJournalEntries(projectRoot, filter = {}) {
54187
54546
  init_errors();
54188
54547
 
54189
54548
  // src/core/streaming-response-builder.ts
54190
- import { randomUUID as randomUUID31 } from "node:crypto";
54549
+ import { randomUUID as randomUUID32 } from "node:crypto";
54191
54550
  var STREAM_DRAIN_TIMEOUT_MS = 500;
54192
54551
  function buildResponse(state) {
54193
54552
  const content = [];
@@ -54247,7 +54606,7 @@ function handleContentBlockStart(state, ev) {
54247
54606
  state.textBuffers.push("");
54248
54607
  state.blockOrder.push({ kind: "text", idx: state.currentTextIndex });
54249
54608
  } else if (kind === "tool_use") {
54250
- const id = ev.id ?? randomUUID31();
54609
+ const id = ev.id ?? randomUUID32();
54251
54610
  state.tools.set(id, { name: ev.name ?? "unknown", partial: "" });
54252
54611
  state.blockOrder.push({ kind: "tool", id });
54253
54612
  state.currentTextIndex = -1;
@@ -54482,7 +54841,7 @@ async function streamProviderToResponse(provider, req, signal, ctx, events, logg
54482
54841
 
54483
54842
  // src/observability/network-telemetry.ts
54484
54843
  import { AsyncLocalStorage } from "node:async_hooks";
54485
- import { createHash as createHash25, randomUUID as randomUUID32 } from "node:crypto";
54844
+ import { createHash as createHash25, randomUUID as randomUUID33 } from "node:crypto";
54486
54845
  import { channel } from "node:diagnostics_channel";
54487
54846
  var storage = new AsyncLocalStorage();
54488
54847
  var requests = /* @__PURE__ */ new WeakMap();
@@ -54519,7 +54878,7 @@ function subscribe() {
54519
54878
  const requestBytes = numberField2(request, "contentLength");
54520
54879
  const state = {
54521
54880
  ...context,
54522
- requestId: randomUUID32(),
54881
+ requestId: randomUUID33(),
54523
54882
  ...target,
54524
54883
  ...requestBytes !== void 0 ? { requestBytes } : {},
54525
54884
  startedAt,
@@ -54654,7 +55013,7 @@ function hash3(value) {
54654
55013
  }
54655
55014
 
54656
55015
  // src/core/provider-runner.ts
54657
- import { randomUUID as randomUUID33 } from "node:crypto";
55016
+ import { randomUUID as randomUUID34 } from "node:crypto";
54658
55017
  function scrubProviderBody(body) {
54659
55018
  if (!body) return void 0;
54660
55019
  return {
@@ -54676,11 +55035,11 @@ function providerLogCtx(p, r) {
54676
55035
  }
54677
55036
  async function runProviderWithRetry(opts) {
54678
55037
  const { provider, request, signal, ctx, events, retry, logger, tracer } = opts;
54679
- const logicalRequestId = randomUUID33();
55038
+ const logicalRequestId = randomUUID34();
54680
55039
  const promptManifest = createChroniclePromptManifest(request);
54681
55040
  let attempt = 0;
54682
55041
  for (; ; ) {
54683
- const attemptId = randomUUID33();
55042
+ const attemptId = randomUUID34();
54684
55043
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
54685
55044
  const startedNs = process.hrtime.bigint();
54686
55045
  const correlation = {
@@ -62133,7 +62492,7 @@ ${summaryText}` : summaryText;
62133
62492
 
62134
62493
  // src/execution/parallel-eternal-engine.ts
62135
62494
  init_error();
62136
- import { randomUUID as randomUUID34 } from "node:crypto";
62495
+ import { randomUUID as randomUUID35 } from "node:crypto";
62137
62496
  var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
62138
62497
  var ParallelEternalEngine = class {
62139
62498
  constructor(opts) {
@@ -62210,7 +62569,7 @@ var ParallelEternalEngine = class {
62210
62569
  this.state = "running";
62211
62570
  await this.persistState("running");
62212
62571
  const config = {
62213
- coordinatorId: `parallel-${randomUUID34().slice(0, 8)}`,
62572
+ coordinatorId: `parallel-${randomUUID35().slice(0, 8)}`,
62214
62573
  maxConcurrent: this.slots,
62215
62574
  doneCondition: { type: "all_tasks_done" }
62216
62575
  };
@@ -62264,7 +62623,7 @@ var ParallelEternalEngine = class {
62264
62623
  }
62265
62624
  if (!this.coordinator) {
62266
62625
  const config = {
62267
- coordinatorId: `parallel-${randomUUID34().slice(0, 8)}`,
62626
+ coordinatorId: `parallel-${randomUUID35().slice(0, 8)}`,
62268
62627
  maxConcurrent: this.slots,
62269
62628
  doneCondition: { type: "all_tasks_done" }
62270
62629
  };
@@ -62350,7 +62709,7 @@ ${recentJournal}` : "No prior iterations.",
62350
62709
  const task = expectDefined(tasks[i]);
62351
62710
  const route = routes[i] ?? null;
62352
62711
  const subagentId = `parallel-${this.iterations}-${i}`;
62353
- const taskId = randomUUID34();
62712
+ const taskId = randomUUID35();
62354
62713
  const personaLine = route ? `Acting agent: ${route.definition.config.name} \u2014 ${route.definition.capability.summary}
62355
62714
  ` : "";
62356
62715
  const spec = {
@@ -63978,7 +64337,7 @@ function readPolicy(ctx) {
63978
64337
  }
63979
64338
 
63980
64339
  // src/execution/tool-executor.ts
63981
- import { randomUUID as randomUUID37 } from "node:crypto";
64340
+ import { randomUUID as randomUUID38 } from "node:crypto";
63982
64341
  import * as fs38 from "node:fs/promises";
63983
64342
  import * as path85 from "node:path";
63984
64343
  init_errors();
@@ -64000,7 +64359,7 @@ var ToolErrorCategory = /* @__PURE__ */ ((ToolErrorCategory2) => {
64000
64359
  })(ToolErrorCategory || {});
64001
64360
 
64002
64361
  // src/execution/tool-executor-support.ts
64003
- import { createHash as createHash29, randomUUID as randomUUID35 } from "node:crypto";
64362
+ import { createHash as createHash29, randomUUID as randomUUID36 } from "node:crypto";
64004
64363
  import * as fs37 from "node:fs/promises";
64005
64364
  import * as path83 from "node:path";
64006
64365
  init_errors();
@@ -64132,7 +64491,7 @@ async function maybePersistLargeToolOutput(toolName, content, budget) {
64132
64491
  await fs37.mkdir(dir, { recursive: true });
64133
64492
  const safeTool = toolName.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40) || "tool";
64134
64493
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
64135
- const filePath = path83.join(dir, `${stamp}-${safeTool}-${randomUUID35()}.log`);
64494
+ const filePath = path83.join(dir, `${stamp}-${safeTool}-${randomUUID36()}.log`);
64136
64495
  await fs37.writeFile(filePath, content, "utf8");
64137
64496
  const marker = `[full tool output: ${bytes} bytes at ${filePath}; read/grep that file selectively instead of re-running or requesting more output]`;
64138
64497
  const fixedBytes = Buffer.byteLength(marker + TOOL_OUTPUT_ARTIFACT_OMISSION, "utf8");
@@ -64682,7 +65041,7 @@ ${errorDetails}`,
64682
65041
  }
64683
65042
 
64684
65043
  // src/execution/tool-executor-runner.ts
64685
- import { randomUUID as randomUUID36 } from "node:crypto";
65044
+ import { randomUUID as randomUUID37 } from "node:crypto";
64686
65045
 
64687
65046
  // src/observability/process-telemetry.ts
64688
65047
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
@@ -64906,7 +65265,7 @@ async function runToolWithTimeout(tool, input, parentSignal, ctx, opts, config,
64906
65265
  progressTailChars: config.progressTailChars,
64907
65266
  progressHeadChars: config.progressHeadChars
64908
65267
  }) : (async () => tool.execute(input, ctx, { signal: combined }))();
64909
- const telemetryToolCallId = toolUseId ?? `nested-${randomUUID36()}`;
65268
+ const telemetryToolCallId = toolUseId ?? `nested-${randomUUID37()}`;
64910
65269
  const toolPromise = opts.events ? runWithNetworkTelemetry(
64911
65270
  {
64912
65271
  events: opts.events,
@@ -65299,7 +65658,7 @@ ${post.additionalContext}`;
65299
65658
  const bridge = async (toolName, input) => {
65300
65659
  const nestedUse = {
65301
65660
  type: "tool_use",
65302
- id: `nested-${randomUUID37()}`,
65661
+ id: `nested-${randomUUID38()}`,
65303
65662
  name: toolName,
65304
65663
  input
65305
65664
  };
@@ -69148,7 +69507,7 @@ function deepFreeze(obj) {
69148
69507
  init_errors();
69149
69508
  init_atomic_write();
69150
69509
  init_error();
69151
- import { randomUUID as randomUUID38 } from "node:crypto";
69510
+ import { randomUUID as randomUUID39 } from "node:crypto";
69152
69511
  import * as fsp38 from "node:fs/promises";
69153
69512
  function assertPlanMutationInvariants(previous, updated) {
69154
69513
  const ids = updated.items.map((item) => item.id);
@@ -69270,7 +69629,7 @@ function emptyPlan(sessionId, title) {
69270
69629
  function addPlanItem(plan, title, details) {
69271
69630
  const now = (/* @__PURE__ */ new Date()).toISOString();
69272
69631
  const item = {
69273
- id: `plan_${Date.now()}_${randomUUID38().slice(0, 6)}`,
69632
+ id: `plan_${Date.now()}_${randomUUID39().slice(0, 6)}`,
69274
69633
  title,
69275
69634
  details,
69276
69635
  status: "open",
@@ -69342,7 +69701,7 @@ function deriveTodosFromPlanItem(plan, idOrIndex, subtasks) {
69342
69701
  if (subtasks && subtasks.length > 0) {
69343
69702
  for (const st of subtasks) {
69344
69703
  todos.push({
69345
- id: `todo_${Date.now()}_${randomUUID38().slice(0, 6)}`,
69704
+ id: `todo_${Date.now()}_${randomUUID39().slice(0, 6)}`,
69346
69705
  content: st,
69347
69706
  status: "pending",
69348
69707
  promotedFromPlan: item.id
@@ -75244,6 +75603,13 @@ var PhaseOrchestrator = class {
75244
75603
  events;
75245
75604
  stopped = false;
75246
75605
  paused = false;
75606
+ /**
75607
+ * Run-wide abort source. stop() aborts it; every in-flight
75608
+ * ctx.executeTask call observes the abort through its per-task signal
75609
+ * (composed from this controller and the task's own timeout controller).
75610
+ * Recreated by start() so a stopped orchestrator can be reused.
75611
+ */
75612
+ stopController = new AbortController();
75247
75613
  runningPhases = /* @__PURE__ */ new Set();
75248
75614
  tickInterval = null;
75249
75615
  trackerCache = /* @__PURE__ */ new Map();
@@ -75286,6 +75652,7 @@ var PhaseOrchestrator = class {
75286
75652
  async start() {
75287
75653
  this.stopped = false;
75288
75654
  this.paused = false;
75655
+ this.stopController = new AbortController();
75289
75656
  this.normalizeForResume();
75290
75657
  this.graph.startedAt = Date.now();
75291
75658
  this.graph.updatedAt = Date.now();
@@ -75345,6 +75712,7 @@ var PhaseOrchestrator = class {
75345
75712
  /** Stop completely, including active phases. */
75346
75713
  stop() {
75347
75714
  this.stopped = true;
75715
+ this.stopController.abort();
75348
75716
  if (this.tickInterval) {
75349
75717
  clearInterval(this.tickInterval);
75350
75718
  this.tickInterval = null;
@@ -75421,6 +75789,7 @@ var PhaseOrchestrator = class {
75421
75789
  return;
75422
75790
  }
75423
75791
  await this.executePhaseTasks(phase);
75792
+ if (this.stopped) return;
75424
75793
  const failedTasks = this.getFailedTaskCount(phase);
75425
75794
  const completedTasks = this.getCompletedTaskCount(phase);
75426
75795
  this.emit("phase.allTasksDone", {
@@ -75580,34 +75949,47 @@ var PhaseOrchestrator = class {
75580
75949
  agentName: task.assignee
75581
75950
  });
75582
75951
  const handle = this.phaseWorktrees.get(phase.id);
75583
- const taskPromise = this.ctx.executeTask(task, phase.id, {
75584
- cwd: handle?.dir,
75585
- branch: handle?.branch
75586
- });
75587
- if (this.opts.taskTimeoutMs > 0) {
75588
- const timeoutMs = this.opts.taskTimeoutMs;
75589
- const timedOut = /* @__PURE__ */ Symbol("timed_out");
75590
- const result = await Promise.race([
75591
- taskPromise,
75592
- new Promise((resolve57) => {
75593
- const timer = setTimeout(() => resolve57(timedOut), timeoutMs);
75594
- taskPromise.then(() => clearTimeout(timer)).catch(() => clearTimeout(timer));
75595
- })
75596
- ]);
75597
- if (result === timedOut) {
75598
- this.emit("phase.taskTimedOut", {
75599
- phaseId: phase.id,
75600
- taskId: task.id,
75601
- taskTitle: task.title,
75602
- timeoutMs
75603
- });
75604
- throw new Error(
75605
- `Task "${task.title}" (${task.id}) exceeded timeout of ${timeoutMs} ms`
75606
- );
75607
- }
75608
- return result;
75609
- }
75610
- return taskPromise;
75952
+ const timeoutController = this.opts.taskTimeoutMs > 0 ? new AbortController() : void 0;
75953
+ const signal = timeoutController ? AbortSignal.any([this.stopController.signal, timeoutController.signal]) : this.stopController.signal;
75954
+ const taskPromise = this.ctx.executeTask(
75955
+ task,
75956
+ phase.id,
75957
+ { cwd: handle?.dir, branch: handle?.branch },
75958
+ signal
75959
+ );
75960
+ if (!timeoutController) return taskPromise;
75961
+ const timeoutMs = this.opts.taskTimeoutMs;
75962
+ const timedOut = /* @__PURE__ */ Symbol("timed_out");
75963
+ const result = await Promise.race([
75964
+ taskPromise,
75965
+ new Promise((resolve57) => {
75966
+ const timer = setTimeout(() => {
75967
+ timeoutController.abort();
75968
+ resolve57(timedOut);
75969
+ }, timeoutMs);
75970
+ taskPromise.then(() => clearTimeout(timer)).catch(() => clearTimeout(timer));
75971
+ })
75972
+ ]);
75973
+ if (result !== timedOut) return result;
75974
+ this.emit("phase.taskTimedOut", {
75975
+ phaseId: phase.id,
75976
+ taskId: task.id,
75977
+ taskTitle: task.title,
75978
+ timeoutMs
75979
+ });
75980
+ const settled = taskPromise.then(
75981
+ () => void 0,
75982
+ () => void 0
75983
+ );
75984
+ const grace = new Promise((resolve57) => {
75985
+ const timer = setTimeout(resolve57, 5e3);
75986
+ timer.unref?.();
75987
+ void settled.then(() => clearTimeout(timer));
75988
+ });
75989
+ await Promise.race([settled, grace]);
75990
+ throw new Error(
75991
+ `Task "${task.title}" (${task.id}) exceeded timeout of ${timeoutMs} ms`
75992
+ );
75611
75993
  }
75612
75994
  markTaskCompleted(phase, task) {
75613
75995
  const tracker = this.getTrackerForPhase(phase);
@@ -75622,6 +76004,10 @@ var PhaseOrchestrator = class {
75622
76004
  const tracker = this.getTrackerForPhase(phase);
75623
76005
  const taskKey = `${phase.id}:${task.id}`;
75624
76006
  const currentRetries = this.taskRetryCounts.get(taskKey) ?? 0;
76007
+ if (this.stopped) {
76008
+ tracker.updateNodeStatus(task.id, "pending", "Stopped before completion");
76009
+ return;
76010
+ }
75625
76011
  if (currentRetries < this.opts.maxRetries) {
75626
76012
  this.taskRetryCounts.set(taskKey, currentRetries + 1);
75627
76013
  tracker.updateNodeStatus(
@@ -80934,7 +81320,8 @@ async function loadPlugins(plugins, opts) {
80934
81320
  plugin,
80935
81321
  resolution.options
80936
81322
  );
80937
- const api = plugin.capabilities ? wrapApiForCapabilityCheck(plugin, rawApi, opts.log, opts.enforceCapabilities) : rawApi;
81323
+ const enforceForPlugin = typeof opts.enforceCapabilities === "function" ? opts.enforceCapabilities(plugin) : opts.enforceCapabilities ?? false;
81324
+ const api = plugin.capabilities ? wrapApiForCapabilityCheck(plugin, rawApi, opts.log, enforceForPlugin) : rawApi;
80938
81325
  registration = {
80939
81326
  plugin,
80940
81327
  api,
@@ -81765,7 +82152,7 @@ async function snapshotChangedFiles(cwd) {
81765
82152
  }
81766
82153
 
81767
82154
  // src/plugins/review-claim-registry.ts
81768
- import { createHash as createHash33, randomUUID as randomUUID39 } from "node:crypto";
82155
+ import { createHash as createHash33, randomUUID as randomUUID40 } from "node:crypto";
81769
82156
  import * as fsp46 from "node:fs/promises";
81770
82157
  import { hostname as hostname5 } from "node:os";
81771
82158
  import * as path103 from "node:path";
@@ -81828,7 +82215,7 @@ async function breakStaleLock(lockPath) {
81828
82215
  return false;
81829
82216
  }
81830
82217
  async function breakLockAtomically(lockPath) {
81831
- const tombstone = `${lockPath}.stale-${randomUUID39()}.tmp`;
82218
+ const tombstone = `${lockPath}.stale-${randomUUID40()}.tmp`;
81832
82219
  try {
81833
82220
  await fsp46.rename(lockPath, tombstone);
81834
82221
  } catch {
@@ -81888,7 +82275,7 @@ async function withStoreLock(storeDir, fn, waitMs = LOCK_WAIT_MS) {
81888
82275
  }
81889
82276
  }
81890
82277
  var MAX_LEDGER_LINES = 1e4;
81891
- var HOST_SID = randomUUID39();
82278
+ var HOST_SID = randomUUID40();
81892
82279
  var claimsByEventBus = /* @__PURE__ */ new WeakMap();
81893
82280
  var startedReviews = /* @__PURE__ */ new WeakMap();
81894
82281
  var pendingStartedReviews = /* @__PURE__ */ new WeakMap();
@@ -81969,7 +82356,7 @@ async function compactLedger(storeDir, active) {
81969
82356
  );
81970
82357
  }
81971
82358
  }
81972
- const tmp = `${claimsFilePath(storeDir)}.tmp-${randomUUID39()}`;
82359
+ const tmp = `${claimsFilePath(storeDir)}.tmp-${randomUUID40()}`;
81973
82360
  await fsp46.writeFile(tmp, lines.length > 0 ? `${lines.join("\n")}
81974
82361
  ` : "", "utf8");
81975
82362
  let replaced = false;
@@ -82898,7 +83285,7 @@ init_review_finding_store();
82898
83285
 
82899
83286
  // src/plugins/review-finding-parser.ts
82900
83287
  init_review_finding_types();
82901
- import { randomUUID as randomUUID41 } from "node:crypto";
83288
+ import { randomUUID as randomUUID42 } from "node:crypto";
82902
83289
  var SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low"]);
82903
83290
  var CATEGORIES = /* @__PURE__ */ new Set([
82904
83291
  "bug",
@@ -82970,7 +83357,7 @@ function parseChimeraReviewReport(reportText, context = {}) {
82970
83357
  }
82971
83358
  const structured = extractStructuredFindingsBlock(reportText);
82972
83359
  if (structured) {
82973
- const reportId2 = context.reportId ?? randomUUID41();
83360
+ const reportId2 = context.reportId ?? randomUUID42();
82974
83361
  const findings2 = structured.findings.map(
82975
83362
  (item) => buildFindingFromStructuredItem(item, { ...context, reportId: reportId2 })
82976
83363
  );
@@ -82982,7 +83369,7 @@ function parseChimeraReviewReport(reportText, context = {}) {
82982
83369
  };
82983
83370
  }
82984
83371
  const findings = [];
82985
- const reportId = context.reportId ?? randomUUID41();
83372
+ const reportId = context.reportId ?? randomUUID42();
82986
83373
  let unparseableCount = 0;
82987
83374
  let durationSeconds;
82988
83375
  let currentSeverity = null;
@@ -83083,7 +83470,7 @@ function parseFindingSegment(segment, severity, context) {
83083
83470
  const fullDesc = suggestions.length > 0 ? cleanDesc + "\n" + suggestions.map((s) => " \u2192 " + s).join("\n") : cleanDesc;
83084
83471
  const suggestedFix = suggestions.length > 0 ? suggestions.join("\n") : void 0;
83085
83472
  return {
83086
- id: randomUUID41(),
83473
+ id: randomUUID42(),
83087
83474
  fingerprint: computeFindingFingerprint(file ?? "", line ?? null, title),
83088
83475
  severity,
83089
83476
  source: normalizeFindingSource(context.reviewType),
@@ -83094,7 +83481,7 @@ function parseFindingSegment(segment, severity, context) {
83094
83481
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
83095
83482
  status: "active",
83096
83483
  originReport: {
83097
- reportId: context.reportId ?? randomUUID41(),
83484
+ reportId: context.reportId ?? randomUUID42(),
83098
83485
  sessionId: context.sessionId ?? "",
83099
83486
  agentId: context.agentId ?? "",
83100
83487
  reviewerModel: context.reviewerModel ?? ""
@@ -83118,7 +83505,7 @@ function buildFindingFromStructuredItem(item, context) {
83118
83505
  const title = item.title;
83119
83506
  const description = item.description ?? title;
83120
83507
  return {
83121
- id: randomUUID41(),
83508
+ id: randomUUID42(),
83122
83509
  fingerprint: computeFindingFingerprint(file ?? "", line ?? null, title),
83123
83510
  severity: item.severity,
83124
83511
  source: normalizeFindingSource(context.reviewType),
@@ -83131,7 +83518,7 @@ function buildFindingFromStructuredItem(item, context) {
83131
83518
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
83132
83519
  status: "active",
83133
83520
  originReport: {
83134
- reportId: context.reportId ?? randomUUID41(),
83521
+ reportId: context.reportId ?? randomUUID42(),
83135
83522
  sessionId: context.sessionId ?? "",
83136
83523
  agentId: context.agentId ?? "",
83137
83524
  reviewerModel: context.reviewerModel ?? ""
@@ -88782,7 +89169,7 @@ var ReplayProviderRunner = class {
88782
89169
  };
88783
89170
 
88784
89171
  // src/session-catalog/store.ts
88785
- import { randomBytes as randomBytes8, randomUUID as randomUUID42 } from "node:crypto";
89172
+ import { randomBytes as randomBytes8, randomUUID as randomUUID43 } from "node:crypto";
88786
89173
  import * as fs59 from "node:fs";
88787
89174
  import * as path119 from "node:path";
88788
89175
  init_atomic_write();
@@ -89133,7 +89520,7 @@ var SessionCatalogStore = class {
89133
89520
  if (!Number.isSafeInteger(entry.pid) || entry.pid <= 0)
89134
89521
  throw new TypeError("Invalid owner pid");
89135
89522
  const now = Date.now();
89136
- const leaseId = randomUUID42();
89523
+ const leaseId = randomUUID43();
89137
89524
  const leaseSecret = randomBytes8(32).toString("hex");
89138
89525
  const expiresAt = now + boundedMs(leaseMs, SESSION_CATALOG_DEFAULT_LEASE_MS, MAX_LEASE_MS);
89139
89526
  this.db.prepare(`INSERT INTO session_leases(
@@ -89205,7 +89592,7 @@ var SessionCatalogStore = class {
89205
89592
  const catalog = this.db.prepare("SELECT 1 AS yes FROM sessions WHERE session_id=?").get(targetSessionId);
89206
89593
  if (!catalog && !fs59.existsSync(this.containedPath(`${targetSessionId}.jsonl`)))
89207
89594
  throw new Error(`Session not found: ${targetSessionId}`);
89208
- const reservationId = randomUUID42();
89595
+ const reservationId = randomUUID43();
89209
89596
  const now = Date.now();
89210
89597
  const expiresAt = now + boundedMs(reservationMs, SESSION_CATALOG_DEFAULT_RESERVATION_MS, MAX_RESERVATION_MS);
89211
89598
  try {
@@ -89501,7 +89888,7 @@ var SessionCatalogStore = class {
89501
89888
  "SELECT 1 AS yes FROM resume_reservations WHERE target_session_id=? AND expires_at>?"
89502
89889
  ).get(sessionId, Date.now());
89503
89890
  if (reservation) throw conflict(`Session ${sessionId} is reserved for resume`);
89504
- const leaseId = randomUUID42();
89891
+ const leaseId = randomUUID43();
89505
89892
  const now = Date.now();
89506
89893
  const expiresAt = now + boundedMs(leaseMs, 6e4, MAX_MAINTENANCE_MS);
89507
89894
  try {
@@ -90459,7 +90846,7 @@ import * as fs62 from "node:fs/promises";
90459
90846
  import * as path122 from "node:path";
90460
90847
 
90461
90848
  // src/session-registry-atomic-file.ts
90462
- import { randomUUID as randomUUID43 } from "node:crypto";
90849
+ import { randomUUID as randomUUID44 } from "node:crypto";
90463
90850
  import * as fs61 from "node:fs/promises";
90464
90851
  import { hostname as hostname6 } from "node:os";
90465
90852
  import * as path121 from "node:path";
@@ -90532,7 +90919,7 @@ async function breakStaleLockVerified2(lockPath, verify) {
90532
90919
  return await breakLockAtomically2(lockPath) === true;
90533
90920
  }
90534
90921
  async function breakLockAtomically2(lockPath) {
90535
- const tombstone = `${lockPath}.stale-${randomUUID43()}.tmp`;
90922
+ const tombstone = `${lockPath}.stale-${randomUUID44()}.tmp`;
90536
90923
  try {
90537
90924
  await fs61.rename(lockPath, tombstone);
90538
90925
  } catch {
@@ -90544,7 +90931,7 @@ async function breakLockAtomically2(lockPath) {
90544
90931
  async function writeAtomicFile(filePath, registry2) {
90545
90932
  const tmp = path121.join(
90546
90933
  path121.dirname(filePath),
90547
- `.${path121.basename(filePath)}.${randomUUID43().slice(0, 8)}.tmp`
90934
+ `.${path121.basename(filePath)}.${randomUUID44().slice(0, 8)}.tmp`
90548
90935
  );
90549
90936
  let tmpPersisted = false;
90550
90937
  try {
@@ -91107,7 +91494,7 @@ var SessionRegistry = class {
91107
91494
  init_errors();
91108
91495
  init_atomic_write();
91109
91496
  init_error();
91110
- import { randomUUID as randomUUID44 } from "node:crypto";
91497
+ import { randomUUID as randomUUID45 } from "node:crypto";
91111
91498
  import * as fs63 from "node:fs/promises";
91112
91499
  var FILE_VERSION = 1;
91113
91500
  var MAX_TEXT_LENGTH = 2e3;
@@ -91205,7 +91592,7 @@ var AnnotationsStore = class {
91205
91592
  });
91206
91593
  }
91207
91594
  const annotation = {
91208
- id: randomUUID44(),
91595
+ id: randomUUID45(),
91209
91596
  sessionId: input.sessionId,
91210
91597
  atEventIndex: input.atEventIndex,
91211
91598
  authorId: input.authorId,
@@ -91558,7 +91945,7 @@ var InputHistoryStore = class {
91558
91945
 
91559
91946
  // src/storage/memory-backend.ts
91560
91947
  init_file_permissions();
91561
- import { randomUUID as randomUUID45 } from "node:crypto";
91948
+ import { randomUUID as randomUUID46 } from "node:crypto";
91562
91949
  import * as fs65 from "node:fs/promises";
91563
91950
  import * as path124 from "node:path";
91564
91951
 
@@ -91786,7 +92173,7 @@ var FileMemoryBackend = class {
91786
92173
  }
91787
92174
  async remember(scope, entry, filePath) {
91788
92175
  const file = this.resolveFile(filePath, scope);
91789
- const id = `mem_${Date.now()}_${randomUUID45().slice(0, 8)}`;
92176
+ const id = `mem_${Date.now()}_${randomUUID46().slice(0, 8)}`;
91790
92177
  const meta = formatMetadata(entry);
91791
92178
  const line = `- [${entry.ts}] ${id}${meta} ${entry.text.replace(/\n/g, " ")}
91792
92179
  `;
@@ -93800,7 +94187,7 @@ async function mutateTasks(filePath, sessionId, fn, events, traceId) {
93800
94187
  init_file_permissions();
93801
94188
  init_atomic_write();
93802
94189
  init_error();
93803
- import { createHash as createHash39, randomUUID as randomUUID46 } from "node:crypto";
94190
+ import { createHash as createHash39, randomUUID as randomUUID47 } from "node:crypto";
93804
94191
  import * as fs70 from "node:fs/promises";
93805
94192
  var GENESIS_PREV = "0".repeat(64);
93806
94193
  var DEFAULT_FSYNC_EVERY = 100;
@@ -93845,7 +94232,7 @@ var ToolAuditLog = class {
93845
94232
  const tip = await this._resolveChainTip(input.sessionId, fp);
93846
94233
  const prevHash = tip.prevHash;
93847
94234
  const index = tip.nextIndex;
93848
- const id = randomUUID46();
94235
+ const id = randomUUID47();
93849
94236
  const ts = (/* @__PURE__ */ new Date()).toISOString();
93850
94237
  const content = {
93851
94238
  id,
@@ -97240,11 +97627,17 @@ export {
97240
97627
  DEFAULT_DIRECTOR_PREAMBLE,
97241
97628
  DEFAULT_DISPATCH_ROLE,
97242
97629
  DEFAULT_EAGER_SKILL_LIMIT,
97630
+ DEFAULT_EXPLORE_COMPANION_AGENT_ID,
97631
+ DEFAULT_EXPLORE_EDIT_TOOLS,
97632
+ DEFAULT_EXPLORE_SEARCH_TOOLS,
97243
97633
  DEFAULT_FILE_EDIT_TOOLS,
97244
97634
  DEFAULT_HQ_REDACTION_POLICY,
97635
+ DEFAULT_MAILBOX_POLL_INTERVAL_MS,
97245
97636
  DEFAULT_MAX_FLEET_SPAWNS,
97246
97637
  DEFAULT_MAX_ITERATIONS,
97638
+ DEFAULT_MAX_PENDING_PROBES,
97247
97639
  DEFAULT_MODES,
97640
+ DEFAULT_PROBE_COOLDOWN_MS,
97248
97641
  DEFAULT_QUALITY_CHECKS,
97249
97642
  DEFAULT_REFINER_RETRY_FEEDBACK,
97250
97643
  DEFAULT_SESSION_LOGGING_CONFIG,
@@ -97304,6 +97697,7 @@ export {
97304
97697
  EscalationRoutingBrainArbiter,
97305
97698
  EternalAutonomyEngine,
97306
97699
  EventBus,
97700
+ ExploreCompanion,
97307
97701
  ExtensionRegistry,
97308
97702
  FALLBACK_CHAIN_MANAGE_TOOL_NAME,
97309
97703
  FALLBACK_PROFILE_MANAGE_TOOL_NAME,
@@ -97604,6 +97998,7 @@ export {
97604
97998
  buildNamespacePayloads,
97605
97999
  buildOtlpMetricsRequest,
97606
98000
  buildOtlpTracesRequest,
98001
+ buildProbeTaskText,
97607
98002
  buildProjectContextualizedPrompt,
97608
98003
  buildQueuedMessagesBlock,
97609
98004
  buildRecoveryAlert,