@wrongstack/core 0.308.6 → 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.
@@ -2862,6 +2862,7 @@ function inferRuntimeCapabilities(toolNames) {
2862
2862
  var skillSet = (...names) => names;
2863
2863
  var ROLE_SKILL_SETS = {
2864
2864
  explore: skillSet("research-web", "node-modern", "typescript-strict"),
2865
+ "explore-companion": skillSet("node-modern", "typescript-strict"),
2865
2866
  search: skillSet("bug-hunter", "typescript-strict", "research-web"),
2866
2867
  research: skillSet("research-web", "tech-stack", "security-scanner", "api-design"),
2867
2868
  analyst: skillSet("sdd", "api-design", "testing", "security-scanner"),
@@ -10389,6 +10390,28 @@ var SHADOW_AGENT = {
10389
10390
  ...defineAgent("shadow-agent", "Shadow"),
10390
10391
  skillNames: [...SHADOW_AGENT_SKILLS]
10391
10392
  };
10393
+ var EXPLORE_COMPANION_AGENT = {
10394
+ ...defineAgent("explore-companion", "Explore Companion"),
10395
+ tools: [...TOOLS.read, ...TOOLS.index],
10396
+ // Read-only, triple-enforced: allowlist has no write/bash, and the
10397
+ // disabled list blocks the escape hatches explicitly.
10398
+ disabledTools: [
10399
+ "write",
10400
+ "edit",
10401
+ "replace",
10402
+ "patch",
10403
+ "bash",
10404
+ "exec",
10405
+ "delegate",
10406
+ "spawn_subagent",
10407
+ "assign_task"
10408
+ ],
10409
+ skillNames: [...ROLE_SKILL_SETS["explore-companion"]],
10410
+ spawnBudgetExempt: true,
10411
+ // Findings travel via mailbox + submit_result, not the leader's stream.
10412
+ textStream: "silent",
10413
+ toolStream: "silent"
10414
+ };
10392
10415
  var CRITIC_AGENT = defineAgent("critic", "Critic");
10393
10416
  var GENERIC_AGENT = defineAgent("generic", "Generic Project Agent");
10394
10417
  function withDispatchMetadata(definition) {
@@ -10407,6 +10430,7 @@ var FLEET_ROSTER = {
10407
10430
  critic: CRITIC_AGENT,
10408
10431
  generic: GENERIC_AGENT,
10409
10432
  "shadow-agent": SHADOW_AGENT,
10433
+ "explore-companion": EXPLORE_COMPANION_AGENT,
10410
10434
  ...Object.fromEntries(
10411
10435
  ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, withDispatchMetadata(d)])
10412
10436
  )
@@ -10430,6 +10454,13 @@ var FLEET_ROSTER_BUDGETS = {
10430
10454
  maxTokens: 96e3,
10431
10455
  maxCostUsd: 0.5
10432
10456
  },
10457
+ "explore-companion": {
10458
+ idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
10459
+ maxIterations: 3e3,
10460
+ maxToolCalls: 8e3,
10461
+ maxTokens: 96e3,
10462
+ maxCostUsd: 0.5
10463
+ },
10433
10464
  ...Object.fromEntries(
10434
10465
  ALL_AGENT_DEFINITIONS.map((d) => [d.config.role, d.budget])
10435
10466
  )
@@ -11168,6 +11199,565 @@ async function readSubagentPartial(opts, subagentId) {
11168
11199
  return void 0;
11169
11200
  }
11170
11201
 
11202
+ // src/coordination/explore-companion.ts
11203
+ import { randomUUID as randomUUID6 } from "node:crypto";
11204
+
11205
+ // src/coordination/mailbox-type-properties.ts
11206
+ var MAILBOX_TYPE_PROPERTIES = {
11207
+ note: {
11208
+ category: "informational",
11209
+ expectsReply: false,
11210
+ requiresAction: false,
11211
+ backgroundEligible: false,
11212
+ outOfBand: false,
11213
+ renderPriority: 20,
11214
+ recipientObligation: "Read for context; no reply needed.",
11215
+ senderGuidance: "General-purpose FYI. Use when no more specific type applies."
11216
+ },
11217
+ ask: {
11218
+ category: "actionable",
11219
+ expectsReply: true,
11220
+ requiresAction: true,
11221
+ backgroundEligible: true,
11222
+ outOfBand: false,
11223
+ renderPriority: 10,
11224
+ recipientObligation: "Answer as soon as possible \u2014 the sender is waiting.",
11225
+ senderGuidance: "Blocking question. Only use when you need an answer to proceed."
11226
+ },
11227
+ assign: {
11228
+ category: "actionable",
11229
+ expectsReply: false,
11230
+ requiresAction: true,
11231
+ backgroundEligible: true,
11232
+ outOfBand: false,
11233
+ renderPriority: 10,
11234
+ recipientObligation: "Accept or decline; act on it when current operation allows.",
11235
+ senderGuidance: 'Task delegation. Must be directed to a specific recipient (not "*").'
11236
+ },
11237
+ steer: {
11238
+ category: "actionable",
11239
+ expectsReply: false,
11240
+ requiresAction: true,
11241
+ backgroundEligible: true,
11242
+ outOfBand: false,
11243
+ renderPriority: 0,
11244
+ // Always rendered first
11245
+ recipientObligation: "Pause current approach, adjust per instruction, then resume.",
11246
+ senderGuidance: "Mid-task direction change. The recipient is already working on something."
11247
+ },
11248
+ btw: {
11249
+ category: "informational",
11250
+ expectsReply: false,
11251
+ requiresAction: false,
11252
+ backgroundEligible: false,
11253
+ outOfBand: false,
11254
+ renderPriority: 30,
11255
+ recipientObligation: "Absorb the information and stay on current task; no reply needed.",
11256
+ senderGuidance: "Low-priority aside. Non-urgent info that can wait."
11257
+ },
11258
+ broadcast: {
11259
+ category: "routing",
11260
+ expectsReply: false,
11261
+ requiresAction: false,
11262
+ backgroundEligible: false,
11263
+ outOfBand: false,
11264
+ renderPriority: 20,
11265
+ recipientObligation: 'Read if addressed to you (direct recipient, alias, or "*").',
11266
+ senderGuidance: 'Multi-recipient envelope. Auto-selected when to is "*" or "@session".'
11267
+ },
11268
+ status: {
11269
+ category: "informational",
11270
+ expectsReply: false,
11271
+ requiresAction: false,
11272
+ backgroundEligible: false,
11273
+ outOfBand: false,
11274
+ renderPriority: 40,
11275
+ recipientObligation: "Use to avoid redundant work; never act on as a task or question.",
11276
+ senderGuidance: "Agent/system status update. Machine-generated, not for human-originated messages."
11277
+ },
11278
+ result: {
11279
+ category: "informational",
11280
+ expectsReply: false,
11281
+ requiresAction: false,
11282
+ backgroundEligible: true,
11283
+ outOfBand: false,
11284
+ renderPriority: 10,
11285
+ recipientObligation: "Factor into next decision; treat as evidence, not a new task.",
11286
+ senderGuidance: "Task completion notice. Share the outcome of finished work."
11287
+ },
11288
+ review: {
11289
+ category: "actionable",
11290
+ expectsReply: false,
11291
+ requiresAction: true,
11292
+ backgroundEligible: true,
11293
+ outOfBand: false,
11294
+ renderPriority: 10,
11295
+ recipientObligation: "Inspect when convenient; no immediate reply required.",
11296
+ senderGuidance: "Passive review request (code/doc/PR). No reply required."
11297
+ },
11298
+ control: {
11299
+ category: "control_signal",
11300
+ expectsReply: false,
11301
+ requiresAction: false,
11302
+ backgroundEligible: false,
11303
+ outOfBand: true,
11304
+ renderPriority: 999,
11305
+ // Never rendered
11306
+ recipientObligation: 'Handled by the agent loop, NOT folded into conversation. "interrupt" causes cooperative halt.',
11307
+ senderGuidance: "RESERVED for runtime use. Agents must NOT send control messages."
11308
+ }
11309
+ };
11310
+
11311
+ // src/coordination/mailbox-auth-types.ts
11312
+ var MAILBOX_CAPABILITY_IMPLICATIONS = {
11313
+ "mail.read.all": ["mail.read.self"],
11314
+ "mail.events.all": ["mail.events.self"],
11315
+ "mail.send.directive": ["mail.send.actionable", "mail.send.informational"],
11316
+ "mail.send.actionable": ["mail.send.informational"],
11317
+ // Leaf capabilities imply nothing further.
11318
+ "mail.send.informational": [],
11319
+ "mail.read.self": [],
11320
+ "mail.ack.self": [],
11321
+ "mail.events.self": [],
11322
+ "mail.presence.register.self": [],
11323
+ "mail.presence.heartbeat.self": [],
11324
+ "mail.presence.deregister.self": [],
11325
+ "mail.presence.read": [],
11326
+ "mail.retention.purge": [],
11327
+ "mail.retention.clear": [],
11328
+ "mail.admin.receipts": []
11329
+ };
11330
+ function expandMailboxCapabilities(caps) {
11331
+ const result = /* @__PURE__ */ new Set();
11332
+ const queue = [...caps];
11333
+ while (queue.length > 0) {
11334
+ const cap = queue.pop();
11335
+ if (result.has(cap)) continue;
11336
+ result.add(cap);
11337
+ const implied = MAILBOX_CAPABILITY_IMPLICATIONS[cap];
11338
+ if (implied) queue.push(...implied);
11339
+ }
11340
+ return result;
11341
+ }
11342
+ function hasMailboxCapability(actor, cap) {
11343
+ if (actor.capabilities.has(cap)) return true;
11344
+ const expanded = expandMailboxCapabilities(actor.capabilities);
11345
+ return expanded.has(cap);
11346
+ }
11347
+
11348
+ // src/coordination/mailbox-predicates.ts
11349
+ function mailboxIdentityBase(agentId) {
11350
+ return agentId.split(/[@#]/, 1)[0].trim().toLowerCase();
11351
+ }
11352
+ function isMailboxLeader(agentId, role) {
11353
+ return mailboxIdentityBase(agentId) === "leader" || role?.trim().toLowerCase() === "leader";
11354
+ }
11355
+ function isMailboxSenderInFamily(senderId, family) {
11356
+ const base = mailboxIdentityBase(senderId);
11357
+ const normalizedFamily = family.trim().toLowerCase();
11358
+ if (normalizedFamily.length === 0) return false;
11359
+ return base === normalizedFamily || base.startsWith(`${normalizedFamily}-`);
11360
+ }
11361
+ function isMailboxMessageVisibleTo(message, agentId, role) {
11362
+ return message.audience !== "leaders" || isMailboxLeader(agentId, role);
11363
+ }
11364
+ function validateSendType(type, to) {
11365
+ if (type === "control") {
11366
+ throw new TypeError('Type "control" is reserved for runtime use and cannot be set by agents');
11367
+ }
11368
+ const isMultiRecipient = to === "*" || to.startsWith("@session:");
11369
+ if (type === "assign" && isMultiRecipient) {
11370
+ throw new TypeError(
11371
+ `Type "assign" requires a specific recipient \u2014 multi-recipient target "${to}" is ambiguous`
11372
+ );
11373
+ }
11374
+ if (type === "steer" && isMultiRecipient) {
11375
+ throw new TypeError(
11376
+ `Type "steer" requires a specific recipient \u2014 multi-recipient target "${to}" is ambiguous`
11377
+ );
11378
+ }
11379
+ }
11380
+ var SESSION_RECIPIENT_PREFIX = "@session:";
11381
+ function sessionRecipient(sessionId) {
11382
+ const normalizedSessionId = sessionId.trim();
11383
+ if (!normalizedSessionId) {
11384
+ throw new TypeError('sessionId is required for the "@session" recipient');
11385
+ }
11386
+ return `${SESSION_RECIPIENT_PREFIX}${normalizedSessionId}`;
11387
+ }
11388
+ function normalizeRecipient(to, sessionId) {
11389
+ const trimmed = to.trim();
11390
+ const normalized = trimmed.toLowerCase();
11391
+ if (normalized === "all") return "*";
11392
+ if (normalized === "@session") return sessionRecipient(sessionId ?? "");
11393
+ return trimmed;
11394
+ }
11395
+ function isActionRequiredForActor(message, projection) {
11396
+ if (projection.legacyGlobalCompletion) return false;
11397
+ if (message.deletedAt !== void 0) return false;
11398
+ if (projection.completedByMe) return false;
11399
+ return MAILBOX_TYPE_PROPERTIES[message.type]?.requiresAction === true;
11400
+ }
11401
+
11402
+ // src/coordination/mailbox-session-sync.ts
11403
+ function isAffectedBySessionAffinity(message) {
11404
+ return message.sessionAffinity !== void 0;
11405
+ }
11406
+ async function acceptMailboxMessageForSession(message, currentSessionId, ctx) {
11407
+ if (!isAffectedBySessionAffinity(message)) return true;
11408
+ const affinity = message.sessionAffinity;
11409
+ if (affinity === null || typeof affinity !== "object" || Array.isArray(affinity)) {
11410
+ return false;
11411
+ }
11412
+ if (affinity.sessionId !== void 0 && typeof affinity.sessionId !== "string" || affinity.reportId !== void 0 && typeof affinity.reportId !== "string") {
11413
+ return false;
11414
+ }
11415
+ if (!currentSessionId) {
11416
+ return ctx?.allowUnscoped === true;
11417
+ }
11418
+ if (typeof affinity.sessionId === "string" && affinity.sessionId.length > 0) {
11419
+ if (affinity.sessionId !== currentSessionId) return false;
11420
+ return true;
11421
+ }
11422
+ if (affinity.reportId && ctx?.resolveChimeraReportSessionId) {
11423
+ try {
11424
+ const resolved = await ctx.resolveChimeraReportSessionId(affinity.reportId);
11425
+ if (resolved === currentSessionId) return true;
11426
+ if (resolved !== void 0) return false;
11427
+ } catch {
11428
+ }
11429
+ }
11430
+ if (ctx?.allowUnscoped === true) return true;
11431
+ return false;
11432
+ }
11433
+
11434
+ // src/coordination/explore-companion.ts
11435
+ var DEFAULT_EXPLORE_COMPANION_AGENT_ID = "explore-companion";
11436
+ var DEFAULT_PROBE_COOLDOWN_MS = 12e4;
11437
+ var DEFAULT_MAX_PENDING_PROBES = 8;
11438
+ var DEFAULT_MAILBOX_POLL_INTERVAL_MS = 5e3;
11439
+ var DEFAULT_EXPLORE_EDIT_TOOLS = [
11440
+ "edit",
11441
+ "write",
11442
+ "patch",
11443
+ "multi_edit",
11444
+ "multiedit",
11445
+ "str_replace"
11446
+ ];
11447
+ var DEFAULT_EXPLORE_SEARCH_TOOLS = [
11448
+ "search",
11449
+ "grep",
11450
+ "codebase-search"
11451
+ ];
11452
+ function buildProbeTaskText(probe) {
11453
+ const payload = { probe: probe.probe };
11454
+ if (probe.hint) payload.hint = probe.hint;
11455
+ if (probe.context) payload.context = probe.context;
11456
+ return JSON.stringify(payload, null, 2);
11457
+ }
11458
+ function extractedPath(input) {
11459
+ if (!input || typeof input !== "object") return void 0;
11460
+ const rec = input;
11461
+ const candidate = typeof rec["path"] === "string" ? rec["path"] : typeof rec["file"] === "string" ? rec["file"] : void 0;
11462
+ return candidate && candidate.length > 0 ? candidate : void 0;
11463
+ }
11464
+ function looksEmpty(e) {
11465
+ if (typeof e.outputLines === "number" && e.outputLines === 0) return true;
11466
+ const out = e.output ?? "";
11467
+ return /(?:^|\n)(?:no |0 )(?:matches|results|files? found|occurrences)/i.test(out) || /total\s*:\s*0\b/i.test(out);
11468
+ }
11469
+ function extractSubjectTokens(text) {
11470
+ const out = [];
11471
+ const fileRe = /([\w@./-]+\.(?:[cm]?[jt]sx?|json|md|py|go|rs|ya?ml))\b/g;
11472
+ for (const m of text.matchAll(fileRe)) {
11473
+ const value = m[1];
11474
+ if (value) out.push({ kind: "file", value });
11475
+ }
11476
+ const symRe = /\b[A-Z][A-Za-z0-9_]{2,}\b/g;
11477
+ for (const m of text.matchAll(symRe)) {
11478
+ out.push({ kind: "symbol", value: m[0] });
11479
+ }
11480
+ return out;
11481
+ }
11482
+ var ExploreCompanion = class {
11483
+ constructor(opts) {
11484
+ this.opts = opts;
11485
+ this.cfg = this.resolveConfig(opts);
11486
+ }
11487
+ opts;
11488
+ unsubscribers = [];
11489
+ /** Paths the leader has read (readSet) — feeds edit-unread + unfamiliar-read. */
11490
+ readSet = /* @__PURE__ */ new Set();
11491
+ /** subject → last probe time; cooldown gate. Survives detach/reconfigure. */
11492
+ probedAt = /* @__PURE__ */ new Map();
11493
+ /** todo id → last observed status, per leader agent. */
11494
+ todoSeen = /* @__PURE__ */ new Map();
11495
+ pending = [];
11496
+ inFlight = false;
11497
+ pollTimer;
11498
+ running = false;
11499
+ hostStarted = false;
11500
+ cfg;
11501
+ resolveConfig(opts) {
11502
+ const signals = opts.signals ?? {};
11503
+ return {
11504
+ enabled: opts.enabled ?? true,
11505
+ cooldownMs: opts.cooldownMs ?? DEFAULT_PROBE_COOLDOWN_MS,
11506
+ maxPending: opts.maxPending ?? DEFAULT_MAX_PENDING_PROBES,
11507
+ pollIntervalMs: opts.pollIntervalMs ?? DEFAULT_MAILBOX_POLL_INTERVAL_MS,
11508
+ companionAgentId: opts.companionAgentId ?? DEFAULT_EXPLORE_COMPANION_AGENT_ID,
11509
+ signals: {
11510
+ editUnreadFile: signals.editUnreadFile ?? true,
11511
+ searchZeroHits: signals.searchZeroHits ?? true,
11512
+ unfamiliarRead: signals.unfamiliarRead ?? true,
11513
+ todoInProgress: signals.todoInProgress ?? true,
11514
+ errorSymbol: signals.errorSymbol ?? true,
11515
+ mailboxAsk: signals.mailboxAsk ?? true
11516
+ },
11517
+ fileEditTools: new Set(
11518
+ (opts.fileEditTools ?? DEFAULT_EXPLORE_EDIT_TOOLS).map((t) => t.toLowerCase())
11519
+ ),
11520
+ searchTools: new Set(
11521
+ (opts.searchTools ?? DEFAULT_EXPLORE_SEARCH_TOOLS).map((t) => t.toLowerCase())
11522
+ )
11523
+ };
11524
+ }
11525
+ /** Resolve the leader's own session id for event filtering. */
11526
+ resolveLeaderSessionId() {
11527
+ const sid = this.opts.leaderSessionId;
11528
+ return typeof sid === "function" ? sid() : sid;
11529
+ }
11530
+ /** Resolve the leader's agent id for todo diffing (optional signal). */
11531
+ resolveLeaderAgentId() {
11532
+ const aid = this.opts.leaderAgentId;
11533
+ if (!aid) return void 0;
11534
+ return typeof aid === "function" ? aid() : aid;
11535
+ }
11536
+ /** Re-apply tunables to a (possibly running) companion. */
11537
+ reconfigure(next) {
11538
+ const merged = { ...this.opts, ...next };
11539
+ const nextCfg = this.resolveConfig(merged);
11540
+ 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(
11541
+ (k) => nextCfg.signals[k] !== this.cfg.signals[k]
11542
+ );
11543
+ this.cfg = nextCfg;
11544
+ if (!changed) return false;
11545
+ if (this.hostStarted) {
11546
+ this.detach();
11547
+ this.attach();
11548
+ }
11549
+ return true;
11550
+ }
11551
+ /** Begin watching. Idempotent; a disabled companion records intent only. */
11552
+ start() {
11553
+ this.hostStarted = true;
11554
+ this.attach();
11555
+ }
11556
+ /** Stop watching and drop the host's intent to watch. */
11557
+ stop() {
11558
+ this.hostStarted = false;
11559
+ this.detach();
11560
+ }
11561
+ /** True while the watchers are attached. */
11562
+ isRunning() {
11563
+ return this.running;
11564
+ }
11565
+ /** Number of probes queued but not yet dispatched (for status surfaces). */
11566
+ pendingCount() {
11567
+ return this.pending.length;
11568
+ }
11569
+ attach() {
11570
+ if (!this.cfg.enabled || this.running) return;
11571
+ this.running = true;
11572
+ this.unsubscribers.push(
11573
+ this.opts.events.on("tool.executed", (e) => {
11574
+ const lsid = this.resolveLeaderSessionId();
11575
+ if (lsid && e.sessionId && e.sessionId !== lsid) return;
11576
+ this.trackToolExecuted(e);
11577
+ })
11578
+ );
11579
+ if (this.cfg.signals.todoInProgress && this.resolveLeaderAgentId()) {
11580
+ this.unsubscribers.push(
11581
+ this.opts.events.on("session.agents_updated", (e) => {
11582
+ const lsid = this.resolveLeaderSessionId();
11583
+ if (lsid && e.sessionId && e.sessionId !== lsid) return;
11584
+ this.trackAgentTodos(e.agents);
11585
+ })
11586
+ );
11587
+ }
11588
+ if (this.cfg.signals.errorSymbol) {
11589
+ this.unsubscribers.push(
11590
+ this.opts.events.on("error", (e) => {
11591
+ const lsid = this.resolveLeaderSessionId();
11592
+ if (lsid && e.sessionId && e.sessionId !== lsid) return;
11593
+ this.trackError(e.err);
11594
+ })
11595
+ );
11596
+ }
11597
+ if (this.cfg.signals.mailboxAsk) {
11598
+ this.pollTimer = setInterval(() => {
11599
+ void this.pollMailbox();
11600
+ }, this.cfg.pollIntervalMs);
11601
+ this.pollTimer.unref?.();
11602
+ }
11603
+ }
11604
+ /** Tear down watchers without touching host intent. Cooldowns survive. */
11605
+ detach() {
11606
+ for (const unsub of this.unsubscribers.splice(0)) unsub();
11607
+ if (this.pollTimer) {
11608
+ clearInterval(this.pollTimer);
11609
+ this.pollTimer = void 0;
11610
+ }
11611
+ this.running = false;
11612
+ }
11613
+ // ── signal handlers ──────────────────────────────────────────────────────
11614
+ trackToolExecuted(e) {
11615
+ const tool = e.name.toLowerCase();
11616
+ const path42 = extractedPath(e.input);
11617
+ if (e.ok && this.cfg.signals.editUnreadFile && this.cfg.fileEditTools.has(tool) && path42) {
11618
+ if (!this.readSet.has(path42)) {
11619
+ this.engage({
11620
+ id: randomUUID6(),
11621
+ probe: `Map file ${path42}: role, exports, dependencies, and callers \u2014 the leader is about to edit it.`,
11622
+ hint: { file: path42 },
11623
+ context: `Leader edited ${path42} without reading it first.`,
11624
+ source: "edit_unread_file",
11625
+ subject: `file:${path42}`,
11626
+ createdAt: this.now()
11627
+ });
11628
+ }
11629
+ return;
11630
+ }
11631
+ if (e.ok && this.cfg.signals.unfamiliarRead && tool === "read" && path42) {
11632
+ if (!this.readSet.has(path42)) {
11633
+ this.readSet.add(path42);
11634
+ this.engage({
11635
+ id: randomUUID6(),
11636
+ probe: `Skeleton + callers + dependents of ${path42}: what it exports, who imports it, and how it fits the feature flow.`,
11637
+ hint: { file: path42 },
11638
+ context: `Leader read unfamiliar file ${path42}.`,
11639
+ source: "unfamiliar_read",
11640
+ subject: `file:${path42}`,
11641
+ createdAt: this.now()
11642
+ });
11643
+ }
11644
+ return;
11645
+ }
11646
+ if (e.ok && this.cfg.signals.searchZeroHits && this.cfg.searchTools.has(tool) && looksEmpty(e)) {
11647
+ const input = e.input ?? {};
11648
+ const query = typeof input["query"] === "string" ? input["query"] : typeof input["pattern"] === "string" ? input["pattern"] : "";
11649
+ this.engage({
11650
+ id: randomUUID6(),
11651
+ 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.`,
11652
+ hint: query ? { symbol: query } : void 0,
11653
+ context: `${e.name} for "${query}" returned zero results.`,
11654
+ source: "search_zero_hits",
11655
+ subject: `search:${query}`,
11656
+ createdAt: this.now()
11657
+ });
11658
+ }
11659
+ }
11660
+ trackAgentTodos(agents) {
11661
+ const leaderId = this.resolveLeaderAgentId();
11662
+ if (!leaderId) return;
11663
+ const leader = agents.find((a) => a.id === leaderId);
11664
+ if (!leader?.todos) return;
11665
+ for (const todo of leader.todos) {
11666
+ const prev = this.todoSeen.get(todo.id);
11667
+ if (prev !== "in_progress" && todo.status === "in_progress") {
11668
+ const mentions = extractSubjectTokens(todo.content);
11669
+ const first = mentions[0];
11670
+ this.engage({
11671
+ id: randomUUID6(),
11672
+ probe: `Pre-map the files/symbols behind this in-progress todo: "${todo.content.slice(0, 160)}".`,
11673
+ hint: first ? { [first.kind]: first.value } : void 0,
11674
+ context: `Todo "${todo.content.slice(0, 120)}" flipped to in_progress.`,
11675
+ source: "todo_in_progress",
11676
+ subject: `todo:${todo.id}`,
11677
+ createdAt: this.now()
11678
+ });
11679
+ }
11680
+ this.todoSeen.set(todo.id, todo.status);
11681
+ }
11682
+ }
11683
+ trackError(err) {
11684
+ const tokens = extractSubjectTokens(err.message);
11685
+ for (const token of tokens.slice(0, 2)) {
11686
+ this.engage({
11687
+ id: randomUUID6(),
11688
+ probe: `What is ${token.value}, where does it live, and who uses it? The leader hit an error naming it.`,
11689
+ hint: { [token.kind]: token.value },
11690
+ context: `Error: ${err.message.slice(0, 300)}`,
11691
+ source: "error_symbol",
11692
+ subject: `token:${token.value}`,
11693
+ createdAt: this.now()
11694
+ });
11695
+ }
11696
+ }
11697
+ async pollMailbox() {
11698
+ if (!this.cfg.enabled || !this.cfg.signals.mailboxAsk) return;
11699
+ try {
11700
+ const messages = await this.opts.mailbox.query({
11701
+ unreadBy: this.cfg.companionAgentId,
11702
+ limit: 20
11703
+ });
11704
+ const lsid = this.resolveLeaderSessionId();
11705
+ for (const msg of messages) {
11706
+ if (msg.type !== "ask" && msg.type !== "assign") continue;
11707
+ const fromLeader = isMailboxLeader(msg.from) || lsid != null && msg.senderSessionId === lsid;
11708
+ if (!fromLeader) continue;
11709
+ this.engage({
11710
+ id: randomUUID6(),
11711
+ probe: msg.body.trim().slice(0, 2e3) || msg.subject,
11712
+ context: `Direct ask from ${msg.from}: ${msg.subject}`,
11713
+ source: "mailbox_ask",
11714
+ subject: `mail:${msg.id}`,
11715
+ createdAt: this.now()
11716
+ });
11717
+ await this.opts.mailbox.ack({
11718
+ messageId: msg.id,
11719
+ readerId: this.cfg.companionAgentId,
11720
+ read: true,
11721
+ completed: true
11722
+ }).catch(() => {
11723
+ });
11724
+ }
11725
+ } catch {
11726
+ }
11727
+ }
11728
+ // ── engagement ───────────────────────────────────────────────────────────
11729
+ cooldownOk(subject) {
11730
+ const last = this.probedAt.get(subject);
11731
+ return last === void 0 || this.now() - last >= this.cfg.cooldownMs;
11732
+ }
11733
+ now() {
11734
+ return this.opts.now ? this.opts.now() : Date.now();
11735
+ }
11736
+ engage(probe) {
11737
+ if (!this.cfg.enabled) return;
11738
+ if (!this.cooldownOk(probe.subject)) return;
11739
+ this.probedAt.set(probe.subject, this.now());
11740
+ if (this.pending.length >= this.cfg.maxPending) {
11741
+ this.pending.shift();
11742
+ }
11743
+ this.pending.push(probe);
11744
+ void this.drain();
11745
+ }
11746
+ async drain() {
11747
+ if (this.inFlight) return;
11748
+ const probe = this.pending.shift();
11749
+ if (!probe) return;
11750
+ this.inFlight = true;
11751
+ try {
11752
+ await this.opts.onProbe(probe);
11753
+ } catch {
11754
+ } finally {
11755
+ this.inFlight = false;
11756
+ if (this.pending.length > 0) void this.drain();
11757
+ }
11758
+ }
11759
+ };
11760
+
11171
11761
  // src/coordination/dep-watcher.ts
11172
11762
  var DEPENDENCY_FILE_PATTERNS = [
11173
11763
  "package.json",
@@ -11323,7 +11913,7 @@ function attachDepWatcherBridge(opts) {
11323
11913
  }
11324
11914
 
11325
11915
  // src/coordination/director.ts
11326
- import { randomUUID as randomUUID14 } from "node:crypto";
11916
+ import { randomUUID as randomUUID15 } from "node:crypto";
11327
11917
  import * as fsp25 from "node:fs/promises";
11328
11918
 
11329
11919
  // src/core/instruction-template.ts
@@ -12128,7 +12718,7 @@ var FleetContextOverflowError = class extends Error {
12128
12718
  };
12129
12719
 
12130
12720
  // src/coordination/director/director-task-registry.ts
12131
- import { randomUUID as randomUUID6 } from "node:crypto";
12721
+ import { randomUUID as randomUUID7 } from "node:crypto";
12132
12722
  var DirectorTaskRegistry = class _DirectorTaskRegistry {
12133
12723
  constructor(deps) {
12134
12724
  this.deps = deps;
@@ -12163,7 +12753,7 @@ var DirectorTaskRegistry = class _DirectorTaskRegistry {
12163
12753
  return { internal, consumedInBand: waiter !== void 0 || anyConsumed };
12164
12754
  }
12165
12755
  async assign(task) {
12166
- const taskWithId = task.id ? task : { ...task, id: randomUUID6() };
12756
+ const taskWithId = task.id ? task : { ...task, id: randomUUID7() };
12167
12757
  if (this.deps.isWorkComplete()) {
12168
12758
  const stopped = this.makeStoppedResult(
12169
12759
  taskWithId.id,
@@ -12183,7 +12773,7 @@ var DirectorTaskRegistry = class _DirectorTaskRegistry {
12183
12773
  return taskWithId.id;
12184
12774
  }
12185
12775
  async assignInternal(task) {
12186
- const taskWithId = task.id ? task : { ...task, id: randomUUID6() };
12776
+ const taskWithId = task.id ? task : { ...task, id: randomUUID7() };
12187
12777
  this.internalTaskIds.add(taskWithId.id);
12188
12778
  try {
12189
12779
  await this.deps.coordinator.assign(taskWithId);
@@ -12398,7 +12988,7 @@ ${JSON.stringify(result.result, null, 2)}
12398
12988
  };
12399
12989
 
12400
12990
  // src/coordination/director-tools.ts
12401
- import { randomUUID as randomUUID10 } from "node:crypto";
12991
+ import { randomUUID as randomUUID11 } from "node:crypto";
12402
12992
  import {
12403
12993
  completeKanbanDispatch,
12404
12994
  failKanbanDispatch,
@@ -12411,7 +13001,7 @@ import {
12411
13001
  } from "@wrongstack/kanban";
12412
13002
 
12413
13003
  // src/coordination/director-input-helpers.ts
12414
- import { randomUUID as randomUUID7 } from "node:crypto";
13004
+ import { randomUUID as randomUUID8 } from "node:crypto";
12415
13005
  function stringArray2(value) {
12416
13006
  if (!Array.isArray(value)) return void 0;
12417
13007
  const strings = value.filter((v) => typeof v === "string" && v.trim().length > 0);
@@ -12425,7 +13015,7 @@ function normalizeWorktreeOverride(value) {
12425
13015
  function instantiateRosterConfig2(role, base) {
12426
13016
  return {
12427
13017
  ...base,
12428
- id: `${role}-${randomUUID7().slice(0, 8)}`
13018
+ id: `${role}-${randomUUID8().slice(0, 8)}`
12429
13019
  };
12430
13020
  }
12431
13021
 
@@ -12492,7 +13082,7 @@ function buildKanbanFleetTaskPrompt(board, task, lease) {
12492
13082
  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})`);
12493
13083
  const checks = task.successCriteria?.map((check) => `- ${check.description}`).join("\n");
12494
13084
  const metrics = task.goalMetrics?.map(
12495
- (metric) => `- ${metric.name}: ${metric.current ?? "n/a"}${metric.target !== void 0 ? ` / ${metric.target}` : ""}${metric.unit ? ` ${metric.unit}` : ""} [${metric.status}]`
13085
+ (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}]`
12496
13086
  ).join("\n");
12497
13087
  const chain = task.chain ? [
12498
13088
  `chainId: ${task.chain.chainId}`,
@@ -12766,7 +13356,7 @@ function makeLLMClassifier(complete2) {
12766
13356
  }
12767
13357
 
12768
13358
  // src/coordination/director-basic-tools.ts
12769
- import { randomUUID as randomUUID8 } from "node:crypto";
13359
+ import { randomUUID as randomUUID9 } from "node:crypto";
12770
13360
  function makeAssignTool(director) {
12771
13361
  const inputSchema = {
12772
13362
  type: "object",
@@ -12805,7 +13395,7 @@ function makeAssignTool(director) {
12805
13395
  };
12806
13396
  }
12807
13397
  const task = {
12808
- id: randomUUID8(),
13398
+ id: randomUUID9(),
12809
13399
  description: composeBoundedTaskDescription(i.description, boundary.boundary),
12810
13400
  subagentId: i.subagentId,
12811
13401
  maxToolCalls: i.maxToolCalls,
@@ -13225,7 +13815,7 @@ function makeWorkCompleteTool(director) {
13225
13815
  }
13226
13816
 
13227
13817
  // src/coordination/director-quality-gate-tool.ts
13228
- import { randomUUID as randomUUID9 } from "node:crypto";
13818
+ import { randomUUID as randomUUID10 } from "node:crypto";
13229
13819
  function makeQualityGateTool(director, roster) {
13230
13820
  return {
13231
13821
  name: "quality_gate",
@@ -13322,7 +13912,7 @@ function makeQualityGateTool(director, roster) {
13322
13912
  makeQualityGateSubagentConfig("verifier", roster, i.verifierWorktree ?? "auto")
13323
13913
  );
13324
13914
  const taskId = await director.assign({
13325
- id: randomUUID9(),
13915
+ id: randomUUID10(),
13326
13916
  subagentId,
13327
13917
  description: buildVerifierTask(i, {
13328
13918
  attempt,
@@ -13340,7 +13930,7 @@ function makeQualityGateTool(director, roster) {
13340
13930
  makeQualityGateSubagentConfig("reviewer", roster, i.reviewerWorktree ?? "off")
13341
13931
  );
13342
13932
  const taskId = await director.assign({
13343
- id: randomUUID9(),
13933
+ id: randomUUID10(),
13344
13934
  subagentId,
13345
13935
  description: buildReviewerTask(i, {
13346
13936
  attempt,
@@ -13368,7 +13958,7 @@ function makeQualityGateTool(director, roster) {
13368
13958
  };
13369
13959
  }
13370
13960
  const repairTaskId = await director.assign({
13371
- id: randomUUID9(),
13961
+ id: randomUUID10(),
13372
13962
  subagentId: i.repairSubagentId,
13373
13963
  description: buildRepairTask(i, attempts[attempts.length - 1], attempt),
13374
13964
  timeoutMs: i.timeoutMs
@@ -13890,7 +14480,7 @@ function makeKanbanQueueTool(director, roster) {
13890
14480
  try {
13891
14481
  const config = buildKanbanSubagentConfig(claim.task, i, roster, instantiateRosterConfig2);
13892
14482
  subagentId = await director.spawn(config);
13893
- const dispatchTaskId = randomUUID10();
14483
+ const dispatchTaskId = randomUUID11();
13894
14484
  const taskSpec = {
13895
14485
  id: dispatchTaskId,
13896
14486
  subagentId,
@@ -14252,7 +14842,7 @@ import * as fsp24 from "node:fs/promises";
14252
14842
  import * as path32 from "node:path";
14253
14843
 
14254
14844
  // src/storage/session-store.ts
14255
- import { randomUUID as randomUUID12 } from "node:crypto";
14845
+ import { randomUUID as randomUUID13 } from "node:crypto";
14256
14846
  import * as fsp23 from "node:fs/promises";
14257
14847
  import * as path31 from "node:path";
14258
14848
 
@@ -15976,7 +16566,7 @@ var FileSessionWriter = class _FileSessionWriter {
15976
16566
 
15977
16567
  // src/storage/session-checkpoint-cas.ts
15978
16568
  import { spawn as spawn3 } from "node:child_process";
15979
- import { createHash as createHash3, randomUUID as randomUUID11 } from "node:crypto";
16569
+ import { createHash as createHash3, randomUUID as randomUUID12 } from "node:crypto";
15980
16570
  import * as fsp10 from "node:fs/promises";
15981
16571
  import * as path23 from "node:path";
15982
16572
 
@@ -16234,7 +16824,7 @@ var SessionCheckpointCas = class {
16234
16824
  }
16235
16825
  const temp = path23.join(
16236
16826
  path23.dirname(target),
16237
- `.${path23.basename(target)}.${process.pid}.${randomUUID11()}.tmp`
16827
+ `.${path23.basename(target)}.${process.pid}.${randomUUID12()}.tmp`
16238
16828
  );
16239
16829
  let handle;
16240
16830
  try {
@@ -18030,7 +18620,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
18030
18620
  onAppend;
18031
18621
  onAppendBatch;
18032
18622
  catalogClient;
18033
- maintenanceHolderId = randomUUID12();
18623
+ maintenanceHolderId = randomUUID13();
18034
18624
  _loadCache = /* @__PURE__ */ new Map();
18035
18625
  loadCache = new SessionLoadCache(this._loadCache);
18036
18626
  _indexCache = null;
@@ -20237,7 +20827,7 @@ function hashStr(s) {
20237
20827
  }
20238
20828
 
20239
20829
  // src/coordination/multi-agent-coordinator.ts
20240
- import { randomUUID as randomUUID13 } from "node:crypto";
20830
+ import { randomUUID as randomUUID14 } from "node:crypto";
20241
20831
  import { EventEmitter as EventEmitter2 } from "node:events";
20242
20832
 
20243
20833
  // src/coordination/coordinator/error-classifier.ts
@@ -20607,7 +21197,7 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
20607
21197
  return { ...subagent, name: display };
20608
21198
  }
20609
21199
  async spawn(subagent) {
20610
- const id = subagent.id || randomUUID13();
21200
+ const id = subagent.id || randomUUID14();
20611
21201
  const cfg = this.withNickname(subagent, id);
20612
21202
  if (this.subagents.has(id)) {
20613
21203
  throw new Error(`Subagent id "${id}" already exists \u2014 refusing to overwrite`);
@@ -21492,7 +22082,7 @@ var Director = class _Director {
21492
22082
  sessionProvider;
21493
22083
  sessionModel;
21494
22084
  constructor(opts) {
21495
- this.id = opts.config.coordinatorId || randomUUID14();
22085
+ this.id = opts.config.coordinatorId || randomUUID15();
21496
22086
  this.manifestPath = opts.manifestPath;
21497
22087
  this.roster = opts.roster;
21498
22088
  this.directorPreamble = opts.directorPreamble ?? DEFAULT_DIRECTOR_PREAMBLE;
@@ -21775,7 +22365,7 @@ var Director = class _Director {
21775
22365
  );
21776
22366
  }
21777
22367
  const msg = {
21778
- id: randomUUID14(),
22368
+ id: randomUUID15(),
21779
22369
  type: "task",
21780
22370
  from: this.id,
21781
22371
  to: subagentId,
@@ -22029,7 +22619,7 @@ var Director = class _Director {
22029
22619
  };
22030
22620
 
22031
22621
  // src/coordination/fleet-manager.ts
22032
- import { randomUUID as randomUUID15 } from "node:crypto";
22622
+ import { randomUUID as randomUUID16 } from "node:crypto";
22033
22623
  import * as fsp26 from "node:fs/promises";
22034
22624
  import * as path33 from "node:path";
22035
22625
  var FleetManager = class {
@@ -22095,7 +22685,7 @@ var FleetManager = class {
22095
22685
  maxContext;
22096
22686
  constructor(opts = {}) {
22097
22687
  this.manifestPath = opts.manifestPath;
22098
- this.directorRunId = opts.directorRunId ?? randomUUID15();
22688
+ this.directorRunId = opts.directorRunId ?? randomUUID16();
22099
22689
  this.maxSpawns = opts.maxSpawns ?? Number.POSITIVE_INFINITY;
22100
22690
  this.maxSpawnDepth = resolveMaxSpawnDepth(opts.maxSpawnDepth);
22101
22691
  this.spawnDepth = opts.spawnDepth ?? 0;
@@ -23004,235 +23594,6 @@ var MailboxProjectServerConnection = class {
23004
23594
  }
23005
23595
  };
23006
23596
 
23007
- // src/coordination/mailbox-type-properties.ts
23008
- var MAILBOX_TYPE_PROPERTIES = {
23009
- note: {
23010
- category: "informational",
23011
- expectsReply: false,
23012
- requiresAction: false,
23013
- backgroundEligible: false,
23014
- outOfBand: false,
23015
- renderPriority: 20,
23016
- recipientObligation: "Read for context; no reply needed.",
23017
- senderGuidance: "General-purpose FYI. Use when no more specific type applies."
23018
- },
23019
- ask: {
23020
- category: "actionable",
23021
- expectsReply: true,
23022
- requiresAction: true,
23023
- backgroundEligible: true,
23024
- outOfBand: false,
23025
- renderPriority: 10,
23026
- recipientObligation: "Answer as soon as possible \u2014 the sender is waiting.",
23027
- senderGuidance: "Blocking question. Only use when you need an answer to proceed."
23028
- },
23029
- assign: {
23030
- category: "actionable",
23031
- expectsReply: false,
23032
- requiresAction: true,
23033
- backgroundEligible: true,
23034
- outOfBand: false,
23035
- renderPriority: 10,
23036
- recipientObligation: "Accept or decline; act on it when current operation allows.",
23037
- senderGuidance: 'Task delegation. Must be directed to a specific recipient (not "*").'
23038
- },
23039
- steer: {
23040
- category: "actionable",
23041
- expectsReply: false,
23042
- requiresAction: true,
23043
- backgroundEligible: true,
23044
- outOfBand: false,
23045
- renderPriority: 0,
23046
- // Always rendered first
23047
- recipientObligation: "Pause current approach, adjust per instruction, then resume.",
23048
- senderGuidance: "Mid-task direction change. The recipient is already working on something."
23049
- },
23050
- btw: {
23051
- category: "informational",
23052
- expectsReply: false,
23053
- requiresAction: false,
23054
- backgroundEligible: false,
23055
- outOfBand: false,
23056
- renderPriority: 30,
23057
- recipientObligation: "Absorb the information and stay on current task; no reply needed.",
23058
- senderGuidance: "Low-priority aside. Non-urgent info that can wait."
23059
- },
23060
- broadcast: {
23061
- category: "routing",
23062
- expectsReply: false,
23063
- requiresAction: false,
23064
- backgroundEligible: false,
23065
- outOfBand: false,
23066
- renderPriority: 20,
23067
- recipientObligation: 'Read if addressed to you (direct recipient, alias, or "*").',
23068
- senderGuidance: 'Multi-recipient envelope. Auto-selected when to is "*" or "@session".'
23069
- },
23070
- status: {
23071
- category: "informational",
23072
- expectsReply: false,
23073
- requiresAction: false,
23074
- backgroundEligible: false,
23075
- outOfBand: false,
23076
- renderPriority: 40,
23077
- recipientObligation: "Use to avoid redundant work; never act on as a task or question.",
23078
- senderGuidance: "Agent/system status update. Machine-generated, not for human-originated messages."
23079
- },
23080
- result: {
23081
- category: "informational",
23082
- expectsReply: false,
23083
- requiresAction: false,
23084
- backgroundEligible: true,
23085
- outOfBand: false,
23086
- renderPriority: 10,
23087
- recipientObligation: "Factor into next decision; treat as evidence, not a new task.",
23088
- senderGuidance: "Task completion notice. Share the outcome of finished work."
23089
- },
23090
- review: {
23091
- category: "actionable",
23092
- expectsReply: false,
23093
- requiresAction: true,
23094
- backgroundEligible: true,
23095
- outOfBand: false,
23096
- renderPriority: 10,
23097
- recipientObligation: "Inspect when convenient; no immediate reply required.",
23098
- senderGuidance: "Passive review request (code/doc/PR). No reply required."
23099
- },
23100
- control: {
23101
- category: "control_signal",
23102
- expectsReply: false,
23103
- requiresAction: false,
23104
- backgroundEligible: false,
23105
- outOfBand: true,
23106
- renderPriority: 999,
23107
- // Never rendered
23108
- recipientObligation: 'Handled by the agent loop, NOT folded into conversation. "interrupt" causes cooperative halt.',
23109
- senderGuidance: "RESERVED for runtime use. Agents must NOT send control messages."
23110
- }
23111
- };
23112
-
23113
- // src/coordination/mailbox-auth-types.ts
23114
- var MAILBOX_CAPABILITY_IMPLICATIONS = {
23115
- "mail.read.all": ["mail.read.self"],
23116
- "mail.events.all": ["mail.events.self"],
23117
- "mail.send.directive": ["mail.send.actionable", "mail.send.informational"],
23118
- "mail.send.actionable": ["mail.send.informational"],
23119
- // Leaf capabilities imply nothing further.
23120
- "mail.send.informational": [],
23121
- "mail.read.self": [],
23122
- "mail.ack.self": [],
23123
- "mail.events.self": [],
23124
- "mail.presence.register.self": [],
23125
- "mail.presence.heartbeat.self": [],
23126
- "mail.presence.deregister.self": [],
23127
- "mail.presence.read": [],
23128
- "mail.retention.purge": [],
23129
- "mail.retention.clear": [],
23130
- "mail.admin.receipts": []
23131
- };
23132
- function expandMailboxCapabilities(caps) {
23133
- const result = /* @__PURE__ */ new Set();
23134
- const queue = [...caps];
23135
- while (queue.length > 0) {
23136
- const cap = queue.pop();
23137
- if (result.has(cap)) continue;
23138
- result.add(cap);
23139
- const implied = MAILBOX_CAPABILITY_IMPLICATIONS[cap];
23140
- if (implied) queue.push(...implied);
23141
- }
23142
- return result;
23143
- }
23144
- function hasMailboxCapability(actor, cap) {
23145
- if (actor.capabilities.has(cap)) return true;
23146
- const expanded = expandMailboxCapabilities(actor.capabilities);
23147
- return expanded.has(cap);
23148
- }
23149
-
23150
- // src/coordination/mailbox-predicates.ts
23151
- function mailboxIdentityBase(agentId) {
23152
- return agentId.split(/[@#]/, 1)[0].trim().toLowerCase();
23153
- }
23154
- function isMailboxLeader(agentId, role) {
23155
- return mailboxIdentityBase(agentId) === "leader" || role?.trim().toLowerCase() === "leader";
23156
- }
23157
- function isMailboxSenderInFamily(senderId, family) {
23158
- const base = mailboxIdentityBase(senderId);
23159
- const normalizedFamily = family.trim().toLowerCase();
23160
- if (normalizedFamily.length === 0) return false;
23161
- return base === normalizedFamily || base.startsWith(`${normalizedFamily}-`);
23162
- }
23163
- function isMailboxMessageVisibleTo(message, agentId, role) {
23164
- return message.audience !== "leaders" || isMailboxLeader(agentId, role);
23165
- }
23166
- function validateSendType(type, to) {
23167
- if (type === "control") {
23168
- throw new TypeError('Type "control" is reserved for runtime use and cannot be set by agents');
23169
- }
23170
- const isMultiRecipient = to === "*" || to.startsWith("@session:");
23171
- if (type === "assign" && isMultiRecipient) {
23172
- throw new TypeError(
23173
- `Type "assign" requires a specific recipient \u2014 multi-recipient target "${to}" is ambiguous`
23174
- );
23175
- }
23176
- if (type === "steer" && isMultiRecipient) {
23177
- throw new TypeError(
23178
- `Type "steer" requires a specific recipient \u2014 multi-recipient target "${to}" is ambiguous`
23179
- );
23180
- }
23181
- }
23182
- var SESSION_RECIPIENT_PREFIX = "@session:";
23183
- function sessionRecipient(sessionId) {
23184
- const normalizedSessionId = sessionId.trim();
23185
- if (!normalizedSessionId) {
23186
- throw new TypeError('sessionId is required for the "@session" recipient');
23187
- }
23188
- return `${SESSION_RECIPIENT_PREFIX}${normalizedSessionId}`;
23189
- }
23190
- function normalizeRecipient(to, sessionId) {
23191
- const trimmed = to.trim();
23192
- const normalized = trimmed.toLowerCase();
23193
- if (normalized === "all") return "*";
23194
- if (normalized === "@session") return sessionRecipient(sessionId ?? "");
23195
- return trimmed;
23196
- }
23197
- function isActionRequiredForActor(message, projection) {
23198
- if (projection.legacyGlobalCompletion) return false;
23199
- if (message.deletedAt !== void 0) return false;
23200
- if (projection.completedByMe) return false;
23201
- return MAILBOX_TYPE_PROPERTIES[message.type]?.requiresAction === true;
23202
- }
23203
-
23204
- // src/coordination/mailbox-session-sync.ts
23205
- function isAffectedBySessionAffinity(message) {
23206
- return message.sessionAffinity !== void 0;
23207
- }
23208
- async function acceptMailboxMessageForSession(message, currentSessionId, ctx) {
23209
- if (!isAffectedBySessionAffinity(message)) return true;
23210
- const affinity = message.sessionAffinity;
23211
- if (affinity === null || typeof affinity !== "object" || Array.isArray(affinity)) {
23212
- return false;
23213
- }
23214
- if (affinity.sessionId !== void 0 && typeof affinity.sessionId !== "string" || affinity.reportId !== void 0 && typeof affinity.reportId !== "string") {
23215
- return false;
23216
- }
23217
- if (!currentSessionId) {
23218
- return ctx?.allowUnscoped === true;
23219
- }
23220
- if (typeof affinity.sessionId === "string" && affinity.sessionId.length > 0) {
23221
- if (affinity.sessionId !== currentSessionId) return false;
23222
- return true;
23223
- }
23224
- if (affinity.reportId && ctx?.resolveChimeraReportSessionId) {
23225
- try {
23226
- const resolved = await ctx.resolveChimeraReportSessionId(affinity.reportId);
23227
- if (resolved === currentSessionId) return true;
23228
- if (resolved !== void 0) return false;
23229
- } catch {
23230
- }
23231
- }
23232
- if (ctx?.allowUnscoped === true) return true;
23233
- return false;
23234
- }
23235
-
23236
23597
  // src/coordination/mailbox-message-codec.ts
23237
23598
  function resolveSendType(type, to) {
23238
23599
  const normalizedTo = normalizeRecipient(to);
@@ -24129,7 +24490,7 @@ function makeFleetStatusTool(opts = {}) {
24129
24490
  }
24130
24491
 
24131
24492
  // src/coordination/fleet-supervisor.ts
24132
- import { randomUUID as randomUUID16 } from "node:crypto";
24493
+ import { randomUUID as randomUUID17 } from "node:crypto";
24133
24494
  var COLLAB_ID_PREFIXES2 = ["bug-hunter-", "refactor-planner-", "critic-"];
24134
24495
  var DEFAULTS = {
24135
24496
  intervalMs: 2e4,
@@ -24407,7 +24768,7 @@ var FleetSupervisor = class {
24407
24768
  */
24408
24769
  async decide(question, context, options, risk) {
24409
24770
  const request = {
24410
- id: `fleetsup-${randomUUID16()}`,
24771
+ id: `fleetsup-${randomUUID17()}`,
24411
24772
  sessionId: this.opts.sessionId?.(),
24412
24773
  source: "system",
24413
24774
  question,
@@ -28582,7 +28943,7 @@ function createAgentMonitorService(opts) {
28582
28943
  }
28583
28944
 
28584
28945
  // src/coordination/autonomous-brain.ts
28585
- import { randomUUID as randomUUID17 } from "node:crypto";
28946
+ import { randomUUID as randomUUID18 } from "node:crypto";
28586
28947
  var AutonomousBrain = class {
28587
28948
  graph;
28588
28949
  // Fleet bus for emitting decisions — null-safe, no-op if not provided
@@ -28688,7 +29049,7 @@ var AutonomousBrain = class {
28688
29049
  consequence: i === 0 ? `Spawn the most appropriate agent for: ${taskDescription.slice(0, 80)}` : `Spawn an alternative agent for the same task`
28689
29050
  }));
28690
29051
  return this.decideAuto({
28691
- id: randomUUID17(),
29052
+ id: randomUUID18(),
28692
29053
  source,
28693
29054
  decisionType: "spawn",
28694
29055
  question: `Should we spawn a subagent for this task?`,
@@ -28731,7 +29092,7 @@ var AutonomousBrain = class {
28731
29092
  }
28732
29093
  ];
28733
29094
  return this.decideAuto({
28734
- id: randomUUID17(),
29095
+ id: randomUUID18(),
28735
29096
  source,
28736
29097
  decisionType: "approve_change",
28737
29098
  question: `Should we approve the change "${change.title}"?`,
@@ -28790,7 +29151,7 @@ var AutonomousBrain = class {
28790
29151
  consequence: "Break the task into smaller sub-tasks"
28791
29152
  });
28792
29153
  return this.decideAuto({
28793
- id: randomUUID17(),
29154
+ id: randomUUID18(),
28794
29155
  source,
28795
29156
  decisionType: "escalate_task",
28796
29157
  question: `Task failed: ${error.slice(0, 100)}. How should we proceed?`,
@@ -28924,10 +29285,10 @@ ${ctx.error}`);
28924
29285
  };
28925
29286
 
28926
29287
  // src/coordination/autonomous-coordinator.ts
28927
- import { randomUUID as randomUUID20 } from "node:crypto";
29288
+ import { randomUUID as randomUUID21 } from "node:crypto";
28928
29289
 
28929
29290
  // src/coordination/knowledge-graph.ts
28930
- import { randomUUID as randomUUID18 } from "node:crypto";
29291
+ import { randomUUID as randomUUID19 } from "node:crypto";
28931
29292
  import * as fsp28 from "node:fs/promises";
28932
29293
  import * as path41 from "node:path";
28933
29294
  var DEFAULT_MAX_NODES = 2e3;
@@ -28975,7 +29336,7 @@ var KnowledgeGraph = class _KnowledgeGraph {
28975
29336
  * Returns the node with its assigned id.
28976
29337
  */
28977
29338
  async add(node) {
28978
- const full = { id: randomUUID18(), ...node };
29339
+ const full = { id: randomUUID19(), ...node };
28979
29340
  this.nodes.set(full.id, full);
28980
29341
  this._trackSeq(full.id);
28981
29342
  this._addToIndex(full, this._indexKeys(full));
@@ -29104,8 +29465,8 @@ var KnowledgeGraph = class _KnowledgeGraph {
29104
29465
  if (this.subs.size >= MAX_SUBSCRIPTIONS) {
29105
29466
  throw new Error(`Knowledge graph subscription limit reached (${MAX_SUBSCRIPTIONS})`);
29106
29467
  }
29107
- const channel = randomUUID18();
29108
- const sub = { id: randomUUID18(), agentId, filter, channel };
29468
+ const channel = randomUUID19();
29469
+ const sub = { id: randomUUID19(), agentId, filter, channel };
29109
29470
  this.subs.set(channel, sub);
29110
29471
  this.pendingDeliveries.set(channel, []);
29111
29472
  return channel;
@@ -29586,7 +29947,7 @@ var TaskDAG = class {
29586
29947
  };
29587
29948
 
29588
29949
  // src/coordination/task-auctioneer.ts
29589
- import { randomUUID as randomUUID19 } from "node:crypto";
29950
+ import { randomUUID as randomUUID20 } from "node:crypto";
29590
29951
  function isTerminalGoalStatus(status) {
29591
29952
  return status === "done" || status === "failed";
29592
29953
  }
@@ -29709,7 +30070,7 @@ var TaskAuctioneer = class {
29709
30070
  const score = dispatchResult.confidence * (dispatchResult.role === agent.agentRole ? 1.2 : 1);
29710
30071
  if (score < this.minConfidence) return false;
29711
30072
  const bid = {
29712
- id: randomUUID19(),
30073
+ id: randomUUID20(),
29713
30074
  taskId,
29714
30075
  agentId: agent.agentId,
29715
30076
  agentName: agent.agentName,
@@ -30646,7 +31007,7 @@ var AutonomousCoordinator = class _AutonomousCoordinator {
30646
31007
  break;
30647
31008
  }
30648
31009
  const decision = await this.brain.decideAuto({
30649
- id: randomUUID20(),
31010
+ id: randomUUID21(),
30650
31011
  source: "system",
30651
31012
  decisionType: "prioritize_goals",
30652
31013
  question: `What should we work on next? Open goals: ${dispatchable.map((g) => g.title).join(", ")}`,
@@ -31361,7 +31722,13 @@ export {
31361
31722
  DEFAULT_DIRECTOR_PREAMBLE,
31362
31723
  DEFAULT_DISPATCH_ROLE,
31363
31724
  DEFAULT_EAGER_SKILL_LIMIT,
31725
+ DEFAULT_EXPLORE_COMPANION_AGENT_ID,
31726
+ DEFAULT_EXPLORE_EDIT_TOOLS,
31727
+ DEFAULT_EXPLORE_SEARCH_TOOLS,
31728
+ DEFAULT_MAILBOX_POLL_INTERVAL_MS,
31364
31729
  DEFAULT_MAX_FLEET_SPAWNS,
31730
+ DEFAULT_MAX_PENDING_PROBES,
31731
+ DEFAULT_PROBE_COOLDOWN_MS,
31365
31732
  DEFAULT_QUALITY_CHECKS,
31366
31733
  DEFAULT_SUBAGENT_BASELINE,
31367
31734
  DELIVERY_AGENTS,
@@ -31375,6 +31742,7 @@ export {
31375
31742
  Director,
31376
31743
  DirectorAlertLevel,
31377
31744
  EscalationRoutingBrainArbiter,
31745
+ ExploreCompanion,
31378
31746
  FLEET_ROSTER,
31379
31747
  FLEET_ROSTER_BUDGETS,
31380
31748
  FLEET_ROSTER_WITHACP,
@@ -31453,6 +31821,7 @@ export {
31453
31821
  brainDecisionKey,
31454
31822
  buildConsolidationInstruction,
31455
31823
  buildDownAlert,
31824
+ buildProbeTaskText,
31456
31825
  buildProjectContextualizedPrompt,
31457
31826
  buildRecoveryAlert,
31458
31827
  buildSkillDistillInstruction,