@wrongstack/core 0.257.2 → 0.260.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/{agent-bridge-BrxWHEOm.d.ts → agent-bridge-BbskZ7HH.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-US741uBH.d.ts → agent-subagent-runner-BNIGZx18.d.ts} +28 -8
  3. package/dist/{brain-TjEEwSpw.d.ts → brain-C2yDd7Lw.d.ts} +58 -1
  4. package/dist/{compactor-C5sT4U7I.d.ts → compactor-t0R_AIt_.d.ts} +1 -1
  5. package/dist/{config-DuAu23zm.d.ts → config-FG6As4H5.d.ts} +1 -1
  6. package/dist/{context-CGdgA0q6.d.ts → context-JFOVvu6z.d.ts} +22 -0
  7. package/dist/coordination/index.d.ts +14 -14
  8. package/dist/coordination/index.js +189 -28
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +25 -25
  11. package/dist/defaults/index.js +881 -83
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/execution/index.d.ts +15 -15
  14. package/dist/execution/index.js +108 -26
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/execution/prompt-enhancer.d.ts +1 -1
  17. package/dist/extension/index.d.ts +6 -6
  18. package/dist/{goal-preamble-CznHTZqP.d.ts → goal-preamble-B1IXJtLX.d.ts} +9 -9
  19. package/dist/{goal-store-CV9Yz2X_.d.ts → goal-store-CPXz6Mml.d.ts} +4 -2
  20. package/dist/{index-CitPrI3a.d.ts → index-BPcg4N3M.d.ts} +5 -5
  21. package/dist/{index-CC0Mcm05.d.ts → index-CebbJB94.d.ts} +8 -8
  22. package/dist/index.d.ts +44 -42
  23. package/dist/index.js +1452 -274
  24. package/dist/index.js.map +1 -1
  25. package/dist/infrastructure/index.d.ts +6 -6
  26. package/dist/kernel/index.d.ts +9 -9
  27. package/dist/kernel/index.js.map +1 -1
  28. package/dist/{llm-selector-CJ4SyAFE.d.ts → llm-selector-DXxI2tlu.d.ts} +2 -2
  29. package/dist/{mcp-servers-D8YnLaEp.d.ts → mcp-servers-OwNHo43-.d.ts} +3 -3
  30. package/dist/models/index.d.ts +5 -5
  31. package/dist/{models-registry-ByZCdFuQ.d.ts → models-registry-Djlmq4uB.d.ts} +1 -1
  32. package/dist/{multi-agent-coordinator-DqTUEAeC.d.ts → multi-agent-coordinator-CEmrSCMJ.d.ts} +1 -1
  33. package/dist/{null-fleet-bus-B5mfTJXT.d.ts → null-fleet-bus-DT92xqgJ.d.ts} +13 -8
  34. package/dist/observability/index.d.ts +2 -2
  35. package/dist/{package-outdated-watcher-BSgR_kK-.d.ts → package-outdated-watcher-C70ag2G9.d.ts} +3 -3
  36. package/dist/{parallel-eternal-engine-C0juOszP.d.ts → parallel-eternal-engine-0SItuq5r.d.ts} +13 -9
  37. package/dist/{path-resolver-CbkT-RMU.d.ts → path-resolver-DKBh6Jlo.d.ts} +3 -3
  38. package/dist/{permission-CwBBpCoF.d.ts → permission-BJ7eO9Vl.d.ts} +1 -1
  39. package/dist/{permission-policy-B8rSu908.d.ts → permission-policy-DEXOfnpm.d.ts} +3 -2
  40. package/dist/{pipeline-JG8XoudC.d.ts → pipeline-zflkI2dp.d.ts} +2 -2
  41. package/dist/{plan-templates-DPiQMkBz.d.ts → plan-templates-BFXyRkEK.d.ts} +32 -11
  42. package/dist/{provider-runner-hM7EXlLI.d.ts → provider-runner-BC-uywtT.d.ts} +3 -3
  43. package/dist/{retry-policy-Tg7LXkoK.d.ts → retry-policy-Cavrzmtk.d.ts} +1 -1
  44. package/dist/sdd/index.d.ts +8 -8
  45. package/dist/sdd/index.js +20 -2
  46. package/dist/sdd/index.js.map +1 -1
  47. package/dist/{secret-vault-gxtFZYBt.d.ts → secret-vault-CDvDYXWX.d.ts} +1 -1
  48. package/dist/security/index.d.ts +4 -4
  49. package/dist/security/index.js +30 -1
  50. package/dist/security/index.js.map +1 -1
  51. package/dist/{selector-DWsqVjGf.d.ts → selector-B7AivHsu.d.ts} +1 -1
  52. package/dist/{session-event-bridge-BAFWdgQ3.d.ts → session-event-bridge-BmIDxdJd.d.ts} +1 -1
  53. package/dist/{session-reader-CqRvaL5v.d.ts → session-reader-DtofsB-2.d.ts} +1 -1
  54. package/dist/storage/index.d.ts +30 -21
  55. package/dist/storage/index.js +1264 -216
  56. package/dist/storage/index.js.map +1 -1
  57. package/dist/types/index.d.ts +19 -19
  58. package/dist/types/index.js +8 -0
  59. package/dist/types/index.js.map +1 -1
  60. package/dist/utils/index.d.ts +2 -2
  61. package/package.json +1 -1
  62. package/skills/output-standards/SKILL.md +14 -9
  63. package/skills/output-standards/SKILL.save.md +3 -2
@@ -451,6 +451,40 @@ var DefaultSessionStore = class _DefaultSessionStore {
451
451
  this.events = opts.events;
452
452
  this.secretScrubber = opts.secretScrubber;
453
453
  }
454
+ // ── Storage event helpers ───────────────────────────────────────────────────
455
+ emitRead(sessionId, filePath, operation, outcome, durationMs, error) {
456
+ this.events?.emit("storage.read", {
457
+ sessionId,
458
+ store: "session",
459
+ filePath,
460
+ operation,
461
+ outcome,
462
+ durationMs,
463
+ ...error !== void 0 ? { error } : {}
464
+ });
465
+ }
466
+ emitWrite(sessionId, filePath, operation, outcome, durationMs, eventCount, error) {
467
+ this.events?.emit("storage.write", {
468
+ sessionId,
469
+ store: "session",
470
+ filePath,
471
+ operation,
472
+ outcome,
473
+ durationMs,
474
+ ...eventCount !== void 0 ? { eventCount } : {},
475
+ ...error !== void 0 ? { error } : {}
476
+ });
477
+ }
478
+ emitError(sessionId, filePath, operation, error, recoverable) {
479
+ this.events?.emit("storage.error", {
480
+ sessionId,
481
+ store: "session",
482
+ filePath,
483
+ operation,
484
+ error,
485
+ recoverable
486
+ });
487
+ }
454
488
  /** Absolute path to the session index file. */
455
489
  get indexFile() {
456
490
  return path11.join(this.dir, "_index.jsonl");
@@ -474,22 +508,26 @@ var DefaultSessionStore = class _DefaultSessionStore {
474
508
  const id = meta.id && meta.id.length > 0 ? meta.id : generateSessionId(startedAt, meta.model ?? meta.provider);
475
509
  const shardDir = await this.ensureShardDir(id);
476
510
  const file = path11.join(shardDir, `${path11.basename(id)}.jsonl`);
511
+ const t0 = Date.now();
477
512
  let handle;
478
513
  try {
479
514
  handle = await fsp.open(file, "a", 384);
480
515
  } catch (err) {
516
+ this.emitError(id, file, "create", err instanceof Error ? err.message : String(err), false);
481
517
  throw new Error(
482
518
  `Failed to open session file: ${err instanceof Error ? err.message : String(err)}`,
483
519
  { cause: err }
484
520
  );
485
521
  }
486
522
  try {
487
- return new FileSessionWriter(id, handle, startedAt, meta, this.events, {
523
+ const writer = new FileSessionWriter(id, handle, startedAt, meta, this.events, {
488
524
  dir: shardDir,
489
525
  filePath: file,
490
526
  secretScrubber: this.secretScrubber,
491
527
  onClose: (s) => this.appendToIndex(s)
492
528
  });
529
+ this.emitWrite(id, file, "create", "success", Date.now() - t0);
530
+ return writer;
493
531
  } catch (err) {
494
532
  await handle.close().catch((e) => console.warn(JSON.stringify({
495
533
  level: "warn",
@@ -497,16 +535,19 @@ var DefaultSessionStore = class _DefaultSessionStore {
497
535
  message: e instanceof Error ? e.message : String(e),
498
536
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
499
537
  })));
538
+ this.emitError(id, file, "create", err instanceof Error ? err.message : String(err), true);
500
539
  throw err;
501
540
  }
502
541
  }
503
542
  async resume(id) {
504
543
  const file = this.sessionPath(id, ".jsonl");
544
+ const t0 = Date.now();
505
545
  const data = await this.load(id);
506
546
  let handle;
507
547
  try {
508
548
  handle = await fsp.open(file, "a", 384);
509
549
  } catch (err) {
550
+ this.emitError(id, file, "resume", err instanceof Error ? err.message : String(err), false);
510
551
  throw new Error(
511
552
  `Failed to open session "${id}" for append: ${err instanceof Error ? err.message : String(err)}`,
512
553
  { cause: err }
@@ -534,6 +575,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
534
575
  onClose: (s) => this.appendToIndex(s)
535
576
  }
536
577
  );
578
+ this.emitWrite(id, file, "resume", "success", Date.now() - t0);
537
579
  return { writer, data };
538
580
  } catch (err) {
539
581
  await handle.close().catch((e) => console.warn(JSON.stringify({
@@ -542,27 +584,39 @@ var DefaultSessionStore = class _DefaultSessionStore {
542
584
  message: e instanceof Error ? e.message : String(e),
543
585
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
544
586
  })));
587
+ this.emitError(id, file, "resume", err instanceof Error ? err.message : String(err), true);
545
588
  throw err;
546
589
  }
547
590
  }
548
591
  async load(id) {
549
592
  const file = this.sessionPath(id, ".jsonl");
550
- const raw = await fsp.readFile(file, "utf8");
551
- const lines = raw.split("\n").filter((l) => l.trim());
552
- const events = [];
553
- for (const line of lines) {
554
- try {
555
- const parsed = JSON.parse(line);
556
- if (parsed !== null && typeof parsed === "object" && typeof parsed.type === "string" && typeof parsed.ts === "string") {
557
- events.push(parsed);
593
+ const t0 = Date.now();
594
+ let outcome = "success";
595
+ let errorMsg;
596
+ try {
597
+ const raw = await fsp.readFile(file, "utf8");
598
+ const lines = raw.split("\n").filter((l) => l.trim());
599
+ const events = [];
600
+ for (const line of lines) {
601
+ try {
602
+ const parsed = JSON.parse(line);
603
+ if (parsed !== null && typeof parsed === "object" && typeof parsed.type === "string" && typeof parsed.ts === "string") {
604
+ events.push(parsed);
605
+ }
606
+ } catch {
558
607
  }
559
- } catch {
560
608
  }
609
+ const meta = this.metaFromEvents(id, events);
610
+ const { messages, usage } = this.replay(events, id);
611
+ const toolCallEnds = extractToolCallEnds(events);
612
+ return { metadata: meta, events, messages, usage, toolCallEnds };
613
+ } catch (err) {
614
+ outcome = "failure";
615
+ errorMsg = err instanceof Error ? err.message : String(err);
616
+ throw err;
617
+ } finally {
618
+ this.emitRead(id, file, "load", outcome, Date.now() - t0, errorMsg);
561
619
  }
562
- const meta = this.metaFromEvents(id, events);
563
- const { messages, usage } = this.replay(events, id);
564
- const toolCallEnds = extractToolCallEnds(events);
565
- return { metadata: meta, events, messages, usage, toolCallEnds };
566
620
  }
567
621
  async list(limit = 20) {
568
622
  try {
@@ -629,12 +683,22 @@ var DefaultSessionStore = class _DefaultSessionStore {
629
683
  * (keep latest per session), and rewrite. Atomic via temp+rename.
630
684
  */
631
685
  async compactIndex() {
632
- const entries = await this.readIndex();
633
- if (entries.length === 0) return;
634
- const tmp = `${this.indexFile}.compact.tmp`;
635
- const lines = entries.map((s) => JSON.stringify(s)).join("\n") + "\n";
636
- await fsp.writeFile(tmp, lines, "utf8");
637
- await fsp.rename(tmp, this.indexFile);
686
+ const t0 = Date.now();
687
+ let outcome = "success";
688
+ let errorMsg;
689
+ try {
690
+ const entries = await this.readIndex();
691
+ if (entries.length === 0) return;
692
+ const tmp = `${this.indexFile}.compact.tmp`;
693
+ const lines = entries.map((s) => JSON.stringify(s)).join("\n") + "\n";
694
+ await fsp.writeFile(tmp, lines, "utf8");
695
+ await fsp.rename(tmp, this.indexFile);
696
+ } catch (err) {
697
+ outcome = "failure";
698
+ errorMsg = err instanceof Error ? err.message : String(err);
699
+ } finally {
700
+ this.emitWrite("~compact~", this.indexFile, "compact", outcome, Date.now() - t0, void 0, errorMsg);
701
+ }
638
702
  }
639
703
  /**
640
704
  * Read the index file and return deduplicated session summaries.
@@ -710,22 +774,31 @@ var DefaultSessionStore = class _DefaultSessionStore {
710
774
  }
711
775
  async summaryFor(id) {
712
776
  const manifest = this.sessionPath(id, ".summary.json");
777
+ const t0 = Date.now();
778
+ let outcome = "success";
779
+ let errorMsg;
713
780
  try {
714
781
  const raw = await fsp.readFile(manifest, "utf8");
782
+ this.emitRead(id, manifest, "summary", "success", Date.now() - t0);
715
783
  return JSON.parse(raw);
716
784
  } catch {
717
785
  const full = this.sessionPath(id, ".jsonl");
718
786
  const stat6 = await fsp.stat(full);
719
787
  const summary = await this.summarize(id, stat6.mtime.toISOString());
720
788
  await atomicWrite(manifest, JSON.stringify(summary), { mode: 384 }).catch((err) => {
789
+ const msg = err instanceof Error ? err.message : String(err);
790
+ this.emitError(id, manifest, "summary_fallback", msg, true);
721
791
  console.warn(JSON.stringify({
722
792
  level: "warn",
723
793
  event: "session_store.manifest_write_failed",
724
794
  sessionId: id,
725
- message: err instanceof Error ? err.message : String(err),
795
+ message: msg,
726
796
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
727
797
  }));
728
798
  });
799
+ outcome = "failure";
800
+ errorMsg = "summary fallback \u2014 manifest rebuilt";
801
+ this.emitRead(id, manifest, "summary", outcome, Date.now() - t0, errorMsg);
729
802
  return summary;
730
803
  }
731
804
  }
@@ -991,7 +1064,7 @@ function extractToolCallEnds(events) {
991
1064
  return result;
992
1065
  }
993
1066
  var FileSessionWriter = class _FileSessionWriter {
994
- constructor(id, handle, startedAt, meta, events, opts = {}) {
1067
+ constructor(id, handle, startedAt, meta, events, opts = {}, traceId) {
995
1068
  this.id = id;
996
1069
  this.handle = handle;
997
1070
  this.startedAt = startedAt;
@@ -1010,6 +1083,7 @@ var FileSessionWriter = class _FileSessionWriter {
1010
1083
  provider: meta.provider ?? "unknown",
1011
1084
  tokenTotal: 0
1012
1085
  };
1086
+ this.traceId = traceId;
1013
1087
  }
1014
1088
  id;
1015
1089
  handle;
@@ -1042,6 +1116,8 @@ var FileSessionWriter = class _FileSessionWriter {
1042
1116
  lastAppendWarnAt = 0;
1043
1117
  secretScrubber;
1044
1118
  onCloseCb;
1119
+ /** Implements SessionWriter.traceId — propagated from ContextInit.traceId. */
1120
+ traceId;
1045
1121
  // ── Write buffer — batches events to reduce per-event disk I/O ─────────
1046
1122
  //
1047
1123
  // Every append() pushes the scrubbed event into an in-memory buffer instead
@@ -1195,9 +1271,14 @@ var FileSessionWriter = class _FileSessionWriter {
1195
1271
  const eventCount = this.writeBuffer.length;
1196
1272
  const batch = this.writeBuffer.map((e) => JSON.stringify(e)).join("\n") + "\n";
1197
1273
  this.writeBuffer = [];
1274
+ const t0 = Date.now();
1275
+ let outcome = "success";
1276
+ let errorMsg;
1198
1277
  try {
1199
1278
  await this.enqueueWrite(batch);
1200
1279
  } catch (err) {
1280
+ outcome = "failure";
1281
+ errorMsg = err instanceof Error ? err.message : String(err);
1201
1282
  this.appendFailCount += eventCount;
1202
1283
  const now = Date.now();
1203
1284
  if (now - this.lastAppendWarnAt > 5e3) {
@@ -1211,6 +1292,18 @@ var FileSessionWriter = class _FileSessionWriter {
1211
1292
  this.lastAppendWarnAt = now;
1212
1293
  this.appendFailCount = 0;
1213
1294
  }
1295
+ } finally {
1296
+ this.events?.emit("storage.write", {
1297
+ sessionId: this.id,
1298
+ store: "session",
1299
+ filePath: this.filePath,
1300
+ operation: "flush",
1301
+ outcome,
1302
+ durationMs: Date.now() - t0,
1303
+ ...errorMsg !== void 0 ? { error: errorMsg } : {},
1304
+ ...eventCount !== void 0 ? { eventCount } : {},
1305
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
1306
+ });
1214
1307
  }
1215
1308
  }
1216
1309
  observeForSummary(event) {
@@ -1276,14 +1369,46 @@ var FileSessionWriter = class _FileSessionWriter {
1276
1369
  outcome: this.outcome ?? "completed"
1277
1370
  };
1278
1371
  if (this.manifestFile) {
1372
+ const t0 = Date.now();
1373
+ let outcome = "success";
1374
+ let errorMsg;
1279
1375
  try {
1280
1376
  await atomicWrite(this.manifestFile, JSON.stringify(this.summary), { mode: 384 });
1281
- } catch {
1377
+ } catch (err) {
1378
+ outcome = "failure";
1379
+ errorMsg = err instanceof Error ? err.message : String(err);
1380
+ } finally {
1381
+ this.events?.emit("storage.write", {
1382
+ sessionId: this.id,
1383
+ store: "session",
1384
+ filePath: this.manifestFile,
1385
+ operation: "close",
1386
+ outcome,
1387
+ durationMs: Date.now() - t0,
1388
+ ...errorMsg !== void 0 ? { error: errorMsg } : {},
1389
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
1390
+ });
1282
1391
  }
1283
1392
  }
1393
+ const idxT0 = Date.now();
1394
+ let idxOutcome = "success";
1395
+ let idxError;
1284
1396
  try {
1285
1397
  await this.onCloseCb?.(this.summary);
1286
- } catch {
1398
+ } catch (err) {
1399
+ idxOutcome = "failure";
1400
+ idxError = err instanceof Error ? err.message : String(err);
1401
+ } finally {
1402
+ this.events?.emit("storage.write", {
1403
+ sessionId: this.summary.id,
1404
+ store: "session",
1405
+ filePath: this.filePath,
1406
+ operation: "index_append",
1407
+ outcome: idxOutcome,
1408
+ durationMs: Date.now() - idxT0,
1409
+ ...idxError !== void 0 ? { error: idxError } : {},
1410
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
1411
+ });
1287
1412
  }
1288
1413
  try {
1289
1414
  await this.handle.close();
@@ -1445,23 +1570,81 @@ function userInputTitle(content) {
1445
1570
  init_atomic_write();
1446
1571
  var QueueStore = class {
1447
1572
  file;
1573
+ // Use `| undefined` (not `?`) so exactOptionalPropertyTypes doesn't
1574
+ // reject assigning an optional constructor parameter to these fields.
1575
+ events;
1576
+ traceId;
1448
1577
  constructor(opts) {
1449
1578
  this.file = path11.join(opts.dir, "queue.json");
1579
+ this.events = opts.events;
1580
+ this.traceId = opts.traceId;
1450
1581
  }
1451
1582
  async write(items) {
1583
+ const t0 = Date.now();
1452
1584
  if (items.length === 0) {
1453
1585
  await this.clear();
1454
1586
  return;
1455
1587
  }
1456
- await atomicWrite(this.file, JSON.stringify(items), { mode: 384 });
1588
+ try {
1589
+ await atomicWrite(this.file, JSON.stringify(items), { mode: 384 });
1590
+ this.events?.emit("storage.write", {
1591
+ sessionId: this.traceId ?? "~boot~",
1592
+ store: "queue",
1593
+ filePath: this.file,
1594
+ operation: "write",
1595
+ outcome: "success",
1596
+ durationMs: Date.now() - t0,
1597
+ ...this.traceId !== void 0 && { traceId: this.traceId }
1598
+ });
1599
+ } catch (err) {
1600
+ this.events?.emit("storage.error", {
1601
+ sessionId: this.traceId ?? "~boot~",
1602
+ store: "queue",
1603
+ filePath: this.file,
1604
+ operation: "write",
1605
+ outcome: "failure",
1606
+ error: err instanceof Error ? err.message : String(err),
1607
+ recoverable: false,
1608
+ ...this.traceId !== void 0 && { traceId: this.traceId }
1609
+ });
1610
+ console.warn(JSON.stringify({
1611
+ level: "warn",
1612
+ event: "queue_store.write_failed",
1613
+ path: this.file,
1614
+ message: err instanceof Error ? err.message : String(err),
1615
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1616
+ }));
1617
+ }
1457
1618
  }
1458
1619
  async read() {
1620
+ const t0 = Date.now();
1459
1621
  let raw;
1460
1622
  try {
1461
1623
  raw = await fsp.readFile(this.file, "utf8");
1462
1624
  } catch (err) {
1463
1625
  const code = err.code;
1464
- if (code === "ENOENT") return [];
1626
+ if (code === "ENOENT") {
1627
+ this.events?.emit("storage.read", {
1628
+ sessionId: this.traceId ?? "~boot~",
1629
+ store: "queue",
1630
+ filePath: this.file,
1631
+ operation: "read",
1632
+ outcome: "success",
1633
+ durationMs: Date.now() - t0,
1634
+ ...this.traceId !== void 0 && { traceId: this.traceId }
1635
+ });
1636
+ return [];
1637
+ }
1638
+ this.events?.emit("storage.error", {
1639
+ sessionId: this.traceId ?? "~boot~",
1640
+ store: "queue",
1641
+ filePath: this.file,
1642
+ operation: "read",
1643
+ outcome: "failure",
1644
+ error: err instanceof Error ? err.message : String(err),
1645
+ recoverable: true,
1646
+ ...this.traceId !== void 0 && { traceId: this.traceId }
1647
+ });
1465
1648
  console.warn(JSON.stringify({
1466
1649
  level: "warn",
1467
1650
  event: "queue_store.read_failed",
@@ -1475,9 +1658,40 @@ var QueueStore = class {
1475
1658
  try {
1476
1659
  parsed = JSON.parse(raw);
1477
1660
  } catch {
1661
+ this.events?.emit("storage.read", {
1662
+ sessionId: this.traceId ?? "~boot~",
1663
+ store: "queue",
1664
+ filePath: this.file,
1665
+ operation: "read",
1666
+ outcome: "failure",
1667
+ durationMs: Date.now() - t0,
1668
+ error: "parse_failed",
1669
+ ...this.traceId !== void 0 && { traceId: this.traceId }
1670
+ });
1671
+ return [];
1672
+ }
1673
+ if (!Array.isArray(parsed)) {
1674
+ this.events?.emit("storage.read", {
1675
+ sessionId: this.traceId ?? "~boot~",
1676
+ store: "queue",
1677
+ filePath: this.file,
1678
+ operation: "read",
1679
+ outcome: "failure",
1680
+ durationMs: Date.now() - t0,
1681
+ error: "invalid_schema",
1682
+ ...this.traceId !== void 0 && { traceId: this.traceId }
1683
+ });
1478
1684
  return [];
1479
1685
  }
1480
- if (!Array.isArray(parsed)) return [];
1686
+ this.events?.emit("storage.read", {
1687
+ sessionId: this.traceId ?? "~boot~",
1688
+ store: "queue",
1689
+ filePath: this.file,
1690
+ operation: "read",
1691
+ outcome: "success",
1692
+ durationMs: Date.now() - t0,
1693
+ ...this.traceId !== void 0 && { traceId: this.traceId }
1694
+ });
1481
1695
  const out = [];
1482
1696
  for (const v of parsed) {
1483
1697
  if (isPersistedQueueItem(v)) out.push(v);
@@ -1485,11 +1699,31 @@ var QueueStore = class {
1485
1699
  return out;
1486
1700
  }
1487
1701
  async clear() {
1702
+ const t0 = Date.now();
1488
1703
  try {
1489
1704
  await fsp.unlink(this.file);
1705
+ this.events?.emit("storage.write", {
1706
+ sessionId: this.traceId ?? "~boot~",
1707
+ store: "queue",
1708
+ filePath: this.file,
1709
+ operation: "clear",
1710
+ outcome: "success",
1711
+ durationMs: Date.now() - t0,
1712
+ ...this.traceId !== void 0 && { traceId: this.traceId }
1713
+ });
1490
1714
  } catch (err) {
1491
1715
  const code = err.code;
1492
1716
  if (code === "ENOENT") return;
1717
+ this.events?.emit("storage.error", {
1718
+ sessionId: this.traceId ?? "~boot~",
1719
+ store: "queue",
1720
+ filePath: this.file,
1721
+ operation: "clear",
1722
+ outcome: "failure",
1723
+ error: err instanceof Error ? err.message : String(err),
1724
+ recoverable: true,
1725
+ ...this.traceId !== void 0 && { traceId: this.traceId }
1726
+ });
1493
1727
  console.warn(JSON.stringify({
1494
1728
  level: "warn",
1495
1729
  event: "queue_store.clear_failed",
@@ -1876,6 +2110,7 @@ var MAX_BYTES_TOTAL = 32e3;
1876
2110
  var DefaultMemoryStore = class {
1877
2111
  files;
1878
2112
  events;
2113
+ traceId;
1879
2114
  backend;
1880
2115
  /**
1881
2116
  * Per-scope serialization queue. `remember` / `forget` / `consolidate` /
@@ -1941,15 +2176,70 @@ var DefaultMemoryStore = class {
1941
2176
  if (writeErr2) {
1942
2177
  parts.push(`> \u26A0\uFE0F Memory write error (${labelOf(scope)}): ${writeErr2.message}`);
1943
2178
  }
1944
- const body = await this.backend.readAll(scope, this.files[scope]);
1945
- if (body.trim()) parts.push(`## ${labelOf(scope)}
2179
+ const t0 = Date.now();
2180
+ const filePath = this.files[scope];
2181
+ try {
2182
+ const body = await this.backend.readAll(scope, filePath);
2183
+ const dur = Date.now() - t0;
2184
+ this.events?.emit("storage.read", {
2185
+ sessionId: "~memory~",
2186
+ store: "memory",
2187
+ filePath,
2188
+ operation: "readAll",
2189
+ outcome: "success",
2190
+ durationMs: dur,
2191
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2192
+ });
2193
+ if (body.trim()) parts.push(`## ${labelOf(scope)}
1946
2194
 
1947
2195
  ${body.trim()}`);
2196
+ } catch (err) {
2197
+ const dur = Date.now() - t0;
2198
+ this.events?.emit("storage.read", {
2199
+ sessionId: "~memory~",
2200
+ store: "memory",
2201
+ filePath,
2202
+ operation: "readAll",
2203
+ outcome: "failure",
2204
+ durationMs: dur,
2205
+ error: err instanceof Error ? err.message : String(err),
2206
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2207
+ });
2208
+ throw err;
2209
+ }
1948
2210
  }
1949
2211
  return parts.join("\n\n");
1950
2212
  }
1951
2213
  async read(scope) {
1952
- return this.backend.readAll(scope, this.files[scope]);
2214
+ const t0 = Date.now();
2215
+ const filePath = this.files[scope];
2216
+ try {
2217
+ const body = await this.backend.readAll(scope, filePath);
2218
+ const dur = Date.now() - t0;
2219
+ this.events?.emit("storage.read", {
2220
+ sessionId: "~memory~",
2221
+ store: "memory",
2222
+ filePath,
2223
+ operation: "read",
2224
+ outcome: "success",
2225
+ durationMs: dur,
2226
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2227
+ });
2228
+ return body;
2229
+ } catch (err) {
2230
+ const dur = Date.now() - t0;
2231
+ this.events?.emit("storage.read", {
2232
+ sessionId: "~memory~",
2233
+ store: "memory",
2234
+ filePath,
2235
+ operation: "read",
2236
+ outcome: "failure",
2237
+ durationMs: dur,
2238
+ error: err instanceof Error ? err.message : String(err),
2239
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2240
+ });
2241
+ throw err;
2242
+ }
1953
2243
  }
1954
2244
  /**
1955
2245
  * List entries from a scope, newest first. Delegates to the backend
@@ -1975,7 +2265,34 @@ ${body.trim()}`);
1975
2265
  const ts = (/* @__PURE__ */ new Date()).toISOString();
1976
2266
  return this.runSerialized(scope, async () => {
1977
2267
  const entry = { scope, text, ts, ...metadata };
1978
- await this.backend.remember(scope, entry, this.files[scope]);
2268
+ const filePath = this.files[scope];
2269
+ const t0 = Date.now();
2270
+ try {
2271
+ await this.backend.remember(scope, entry, filePath);
2272
+ const dur = Date.now() - t0;
2273
+ this.events?.emit("storage.write", {
2274
+ sessionId: "~memory~",
2275
+ store: "memory",
2276
+ filePath,
2277
+ operation: "remember",
2278
+ outcome: "success",
2279
+ durationMs: dur,
2280
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2281
+ });
2282
+ } catch (err) {
2283
+ const dur = Date.now() - t0;
2284
+ this.events?.emit("storage.write", {
2285
+ sessionId: "~memory~",
2286
+ store: "memory",
2287
+ filePath,
2288
+ operation: "remember",
2289
+ outcome: "failure",
2290
+ durationMs: dur,
2291
+ error: err instanceof Error ? err.message : String(err),
2292
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2293
+ });
2294
+ throw err;
2295
+ }
1979
2296
  const raw = await this.backend.readAll(scope, this.files[scope]);
1980
2297
  if (Buffer.byteLength(raw, "utf8") > MAX_BYTES_TOTAL) {
1981
2298
  const removed = await this.backend.consolidate(scope, this.files[scope]);
@@ -2103,7 +2420,35 @@ ${body.trim()}`);
2103
2420
  }
2104
2421
  async forget(query, scope = "project-memory") {
2105
2422
  return this.runSerialized(scope, async () => {
2106
- const removed = await this.backend.forget(scope, query, this.files[scope]);
2423
+ const filePath = this.files[scope];
2424
+ const t0 = Date.now();
2425
+ let removed = 0;
2426
+ try {
2427
+ removed = await this.backend.forget(scope, query, filePath);
2428
+ const dur = Date.now() - t0;
2429
+ this.events?.emit("storage.write", {
2430
+ sessionId: "~memory~",
2431
+ store: "memory",
2432
+ filePath,
2433
+ operation: "forget",
2434
+ outcome: "success",
2435
+ durationMs: dur,
2436
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2437
+ });
2438
+ } catch (err) {
2439
+ const dur = Date.now() - t0;
2440
+ this.events?.emit("storage.write", {
2441
+ sessionId: "~memory~",
2442
+ store: "memory",
2443
+ filePath,
2444
+ operation: "forget",
2445
+ outcome: "failure",
2446
+ durationMs: dur,
2447
+ error: err instanceof Error ? err.message : String(err),
2448
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2449
+ });
2450
+ throw err;
2451
+ }
2107
2452
  if (removed > 0) {
2108
2453
  this.events?.emit("memory.forgotten", {
2109
2454
  scope,
@@ -2117,7 +2462,35 @@ ${body.trim()}`);
2117
2462
  }
2118
2463
  async consolidate(scope) {
2119
2464
  return this.runSerialized(scope, async () => {
2120
- const removed = await this.backend.consolidate(scope, this.files[scope]);
2465
+ const filePath = this.files[scope];
2466
+ const t0 = Date.now();
2467
+ let removed = 0;
2468
+ try {
2469
+ removed = await this.backend.consolidate(scope, filePath);
2470
+ const dur = Date.now() - t0;
2471
+ this.events?.emit("storage.write", {
2472
+ sessionId: "~memory~",
2473
+ store: "memory",
2474
+ filePath,
2475
+ operation: "consolidate",
2476
+ outcome: "success",
2477
+ durationMs: dur,
2478
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2479
+ });
2480
+ } catch (err) {
2481
+ const dur = Date.now() - t0;
2482
+ this.events?.emit("storage.write", {
2483
+ sessionId: "~memory~",
2484
+ store: "memory",
2485
+ filePath,
2486
+ operation: "consolidate",
2487
+ outcome: "failure",
2488
+ durationMs: dur,
2489
+ error: err instanceof Error ? err.message : String(err),
2490
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2491
+ });
2492
+ throw err;
2493
+ }
2121
2494
  if (removed > 0) {
2122
2495
  this.events?.emit("memory.consolidated", {
2123
2496
  scope,
@@ -2130,7 +2503,34 @@ ${body.trim()}`);
2130
2503
  async clear(scope) {
2131
2504
  if (scope) {
2132
2505
  await this.runSerialized(scope, async () => {
2133
- await this.backend.clear(scope, this.files[scope]);
2506
+ const filePath = this.files[scope];
2507
+ const t0 = Date.now();
2508
+ try {
2509
+ await this.backend.clear(scope, filePath);
2510
+ const dur = Date.now() - t0;
2511
+ this.events?.emit("storage.write", {
2512
+ sessionId: "~memory~",
2513
+ store: "memory",
2514
+ filePath,
2515
+ operation: "clear",
2516
+ outcome: "success",
2517
+ durationMs: dur,
2518
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2519
+ });
2520
+ } catch (err) {
2521
+ const dur = Date.now() - t0;
2522
+ this.events?.emit("storage.write", {
2523
+ sessionId: "~memory~",
2524
+ store: "memory",
2525
+ filePath,
2526
+ operation: "clear",
2527
+ outcome: "failure",
2528
+ durationMs: dur,
2529
+ error: err instanceof Error ? err.message : String(err),
2530
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2531
+ });
2532
+ throw err;
2533
+ }
2134
2534
  this.events?.emit("memory.cleared", { scope });
2135
2535
  await this.mirrorBackup(scope);
2136
2536
  });
@@ -2138,15 +2538,54 @@ ${body.trim()}`);
2138
2538
  }
2139
2539
  await Promise.all(
2140
2540
  ["project-agents", "project-memory", "user-memory"].map(
2141
- (s) => this.runSerialized(s, async () => {
2142
- await this.backend.clear(s, this.files[s]);
2541
+ async (s) => this.runSerialized(s, async () => {
2542
+ const filePath = this.files[s];
2543
+ const t0 = Date.now();
2544
+ try {
2545
+ await this.backend.clear(s, filePath);
2546
+ const dur = Date.now() - t0;
2547
+ this.events?.emit("storage.write", {
2548
+ sessionId: "~memory~",
2549
+ store: "memory",
2550
+ filePath,
2551
+ operation: "clear",
2552
+ outcome: "success",
2553
+ durationMs: dur,
2554
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2555
+ });
2556
+ } catch (err) {
2557
+ const dur = Date.now() - t0;
2558
+ this.events?.emit("storage.write", {
2559
+ sessionId: "~memory~",
2560
+ store: "memory",
2561
+ filePath,
2562
+ operation: "clear",
2563
+ outcome: "failure",
2564
+ durationMs: dur,
2565
+ error: err instanceof Error ? err.message : String(err),
2566
+ ...this.traceId !== void 0 && { traceId: this.traceId }
2567
+ });
2568
+ throw err;
2569
+ }
2143
2570
  this.events?.emit("memory.cleared", { scope: s });
2144
2571
  await this.mirrorBackup(s);
2145
2572
  })
2146
2573
  )
2147
2574
  );
2148
2575
  }
2149
- /** Mirror current memory content to the persistent backup directory. */
2576
+ /**
2577
+ * Return a new MemoryStore proxy that carries `traceId` on every storage
2578
+ * event. The original store is left unchanged — callers that need a
2579
+ * trace-decorated view (e.g. session-run tools) receive the proxy while
2580
+ * the singleton remains trace-free for boot-time use.
2581
+ *
2582
+ * The proxy implements the full `MemoryStore` interface; all other
2583
+ * properties (backend, etc.) are delegated to the original store.
2584
+ */
2585
+ withTraceId(traceId) {
2586
+ this.traceId = traceId;
2587
+ return this;
2588
+ }
2150
2589
  async mirrorBackup(scope) {
2151
2590
  if (!this.persistBackup || scope === "project-agents") return;
2152
2591
  try {
@@ -2796,6 +3235,13 @@ var DEFAULT_SESSION_LOGGING_CONFIG = Object.freeze({
2796
3235
  });
2797
3236
 
2798
3237
  // src/storage/config-loader.ts
3238
+ function storageErrorString(err) {
3239
+ if (err instanceof Error) {
3240
+ const code = err.code;
3241
+ return code ? `${code}: ${err.message}` : err.message;
3242
+ }
3243
+ return String(err);
3244
+ }
2799
3245
  var BEHAVIOR_DEFAULTS = {
2800
3246
  version: 1,
2801
3247
  context: {
@@ -2898,11 +3344,15 @@ var DefaultConfigLoader = class {
2898
3344
  strict;
2899
3345
  vault;
2900
3346
  extraSources;
3347
+ events;
3348
+ traceId;
2901
3349
  constructor(opts) {
2902
3350
  this.paths = opts.paths;
2903
3351
  this.strict = opts.strict ?? false;
2904
3352
  this.vault = opts.vault;
2905
3353
  this.extraSources = opts.sources ?? [];
3354
+ this.events = opts.events;
3355
+ this.traceId = opts.traceId;
2906
3356
  }
2907
3357
  async load(opts = {}) {
2908
3358
  let cfg = { ...BEHAVIOR_DEFAULTS };
@@ -2979,7 +3429,33 @@ var DefaultConfigLoader = class {
2979
3429
  if (this.vault && toWrite.githubToken && !toWrite.githubToken.startsWith("enc:")) {
2980
3430
  toWrite = { ...toWrite, githubToken: this.vault.encrypt(toWrite.githubToken) };
2981
3431
  }
2982
- await atomicWrite(this.paths.syncConfig, JSON.stringify(toWrite, null, 2), { mode: 384 });
3432
+ const fp = this.paths.syncConfig;
3433
+ const t0 = Date.now();
3434
+ try {
3435
+ await atomicWrite(fp, JSON.stringify(toWrite, null, 2), { mode: 384 });
3436
+ this.events?.emit("storage.write", {
3437
+ sessionId: "~config~",
3438
+ store: "config",
3439
+ filePath: fp,
3440
+ operation: "persist_sync",
3441
+ outcome: "success",
3442
+ durationMs: Date.now() - t0,
3443
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
3444
+ });
3445
+ } catch (err) {
3446
+ this.events?.emit("storage.error", {
3447
+ sessionId: "~config~",
3448
+ store: "config",
3449
+ filePath: fp,
3450
+ operation: "persist_sync",
3451
+ outcome: "failure",
3452
+ error: storageErrorString(err),
3453
+ recoverable: false,
3454
+ durationMs: Date.now() - t0,
3455
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
3456
+ });
3457
+ throw err;
3458
+ }
2983
3459
  }
2984
3460
  /**
2985
3461
  * Read ~/.wrongstack/sync.json (encrypted GitHub token storage) and decrypt
@@ -2988,17 +3464,60 @@ var DefaultConfigLoader = class {
2988
3464
  * isolated — it should never be part of project-local or env-driven config.
2989
3465
  */
2990
3466
  async loadSyncConfig() {
3467
+ const fp = this.paths.syncConfig;
3468
+ const t0 = Date.now();
2991
3469
  try {
2992
- const raw = await fsp.readFile(this.paths.syncConfig, "utf8");
3470
+ const raw = await fsp.readFile(fp, "utf8");
2993
3471
  const parsed = safeParse(raw);
2994
- if (!parsed.ok || !parsed.value) return null;
3472
+ if (!parsed.ok || !parsed.value) {
3473
+ this.events?.emit("storage.read", {
3474
+ sessionId: "~config~",
3475
+ store: "config",
3476
+ filePath: fp,
3477
+ operation: "load_sync",
3478
+ outcome: "failure",
3479
+ durationMs: Date.now() - t0,
3480
+ error: "parse error or empty file",
3481
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
3482
+ });
3483
+ return null;
3484
+ }
2995
3485
  if (this.vault) {
2996
3486
  const decrypted = decryptConfigSecrets({ sync: parsed.value }, this.vault);
2997
- return decrypted.sync ?? null;
3487
+ const result = decrypted.sync ?? null;
3488
+ this.events?.emit("storage.read", {
3489
+ sessionId: "~config~",
3490
+ store: "config",
3491
+ filePath: fp,
3492
+ operation: "load_sync",
3493
+ outcome: "success",
3494
+ durationMs: Date.now() - t0,
3495
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
3496
+ });
3497
+ return result;
2998
3498
  }
3499
+ this.events?.emit("storage.read", {
3500
+ sessionId: "~config~",
3501
+ store: "config",
3502
+ filePath: fp,
3503
+ operation: "load_sync",
3504
+ outcome: "success",
3505
+ durationMs: Date.now() - t0,
3506
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
3507
+ });
2999
3508
  return parsed.value;
3000
3509
  } catch (err) {
3001
3510
  if (err.code === "ENOENT") return null;
3511
+ this.events?.emit("storage.read", {
3512
+ sessionId: "~config~",
3513
+ store: "config",
3514
+ filePath: fp,
3515
+ operation: "load_sync",
3516
+ outcome: "failure",
3517
+ durationMs: Date.now() - t0,
3518
+ error: storageErrorString(err),
3519
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
3520
+ });
3002
3521
  console.warn(JSON.stringify({
3003
3522
  level: "warn",
3004
3523
  event: "config.sync_load_failed",
@@ -3010,10 +3529,21 @@ var DefaultConfigLoader = class {
3010
3529
  }
3011
3530
  async readJson(file) {
3012
3531
  let raw;
3532
+ const t0 = Date.now();
3013
3533
  try {
3014
3534
  raw = await fsp.readFile(file, "utf8");
3015
3535
  } catch (err) {
3016
3536
  if (err.code !== "ENOENT") {
3537
+ this.events?.emit("storage.read", {
3538
+ sessionId: "~config~",
3539
+ store: "config",
3540
+ filePath: file,
3541
+ operation: "read_json",
3542
+ outcome: "failure",
3543
+ durationMs: Date.now() - t0,
3544
+ error: storageErrorString(err),
3545
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
3546
+ });
3017
3547
  console.warn(JSON.stringify({
3018
3548
  level: "warn",
3019
3549
  event: "config.read_failed",
@@ -3026,6 +3556,16 @@ var DefaultConfigLoader = class {
3026
3556
  }
3027
3557
  const parsed = safeParse(raw);
3028
3558
  if (!parsed.ok || !parsed.value) {
3559
+ this.events?.emit("storage.read", {
3560
+ sessionId: "~config~",
3561
+ store: "config",
3562
+ filePath: file,
3563
+ operation: "read_json",
3564
+ outcome: "failure",
3565
+ durationMs: Date.now() - t0,
3566
+ error: "parse error or empty file",
3567
+ ...this.traceId !== void 0 ? { traceId: this.traceId } : {}
3568
+ });
3029
3569
  console.warn(JSON.stringify({
3030
3570
  level: "warn",
3031
3571
  event: "config.parse_failed",
@@ -3813,24 +4353,66 @@ function resolveSessionLoggingConfig(cfg) {
3813
4353
 
3814
4354
  // src/storage/todos-checkpoint.ts
3815
4355
  init_atomic_write();
3816
- async function loadTodosCheckpoint(filePath) {
4356
+ async function loadTodosCheckpoint(filePath, events, traceId) {
4357
+ const t0 = Date.now();
3817
4358
  let raw;
3818
4359
  try {
3819
4360
  raw = await fsp.readFile(filePath, "utf8");
3820
- } catch {
4361
+ } catch (err) {
4362
+ events?.emit("storage.error", {
4363
+ sessionId: traceId ?? "~boot~",
4364
+ store: "todos",
4365
+ filePath,
4366
+ operation: "load",
4367
+ outcome: "failure",
4368
+ error: err instanceof Error ? err.message : String(err),
4369
+ recoverable: true
4370
+ });
3821
4371
  return null;
3822
4372
  }
3823
4373
  try {
3824
4374
  const parsed = JSON.parse(raw);
3825
- if (parsed?.version !== 1 || !Array.isArray(parsed.todos)) return null;
4375
+ if (parsed?.version !== 1 || !Array.isArray(parsed.todos)) {
4376
+ events?.emit("storage.read", {
4377
+ sessionId: traceId ?? "~boot~",
4378
+ store: "todos",
4379
+ filePath,
4380
+ operation: "load",
4381
+ outcome: "failure",
4382
+ durationMs: Date.now() - t0,
4383
+ error: "invalid_schema",
4384
+ ...traceId !== void 0 && { traceId }
4385
+ });
4386
+ return null;
4387
+ }
4388
+ events?.emit("storage.read", {
4389
+ sessionId: traceId ?? "~boot~",
4390
+ store: "todos",
4391
+ filePath,
4392
+ operation: "load",
4393
+ outcome: "success",
4394
+ durationMs: Date.now() - t0,
4395
+ ...traceId !== void 0 && { traceId }
4396
+ });
3826
4397
  return parsed.todos.filter(
3827
4398
  (t) => !!t && typeof t.id === "string" && typeof t.content === "string" && typeof t.status === "string" && (t.activeForm === void 0 || typeof t.activeForm === "string")
3828
4399
  );
3829
4400
  } catch {
4401
+ events?.emit("storage.read", {
4402
+ sessionId: traceId ?? "~boot~",
4403
+ store: "todos",
4404
+ filePath,
4405
+ operation: "load",
4406
+ outcome: "failure",
4407
+ durationMs: Date.now() - t0,
4408
+ error: "parse_failed",
4409
+ ...traceId !== void 0 && { traceId }
4410
+ });
3830
4411
  return null;
3831
4412
  }
3832
4413
  }
3833
- async function saveTodosCheckpoint(filePath, sessionId, todos) {
4414
+ async function saveTodosCheckpoint(filePath, sessionId, todos, events, traceId) {
4415
+ const t0 = Date.now();
3834
4416
  const payload = {
3835
4417
  version: 1,
3836
4418
  sessionId,
@@ -3839,7 +4421,25 @@ async function saveTodosCheckpoint(filePath, sessionId, todos) {
3839
4421
  };
3840
4422
  try {
3841
4423
  await atomicWrite(filePath, JSON.stringify(payload, null, 2), { mode: 384 });
4424
+ events?.emit("storage.write", {
4425
+ sessionId: traceId ?? sessionId,
4426
+ store: "todos",
4427
+ filePath,
4428
+ operation: "save",
4429
+ outcome: "success",
4430
+ durationMs: Date.now() - t0,
4431
+ ...traceId !== void 0 && { traceId }
4432
+ });
3842
4433
  } catch (err) {
4434
+ events?.emit("storage.error", {
4435
+ sessionId: traceId ?? sessionId,
4436
+ store: "todos",
4437
+ filePath,
4438
+ operation: "save",
4439
+ outcome: "failure",
4440
+ error: err instanceof Error ? err.message : String(err),
4441
+ recoverable: false
4442
+ });
3843
4443
  console.warn(JSON.stringify({
3844
4444
  level: "warn",
3845
4445
  event: "todos_checkpoint.save_failed",
@@ -3848,12 +4448,12 @@ async function saveTodosCheckpoint(filePath, sessionId, todos) {
3848
4448
  }));
3849
4449
  }
3850
4450
  }
3851
- function attachTodosCheckpoint(state, filePath, sessionId) {
4451
+ function attachTodosCheckpoint(state, filePath, sessionId, events, traceId) {
3852
4452
  let timer = null;
3853
4453
  let pending = null;
3854
4454
  let writeChain = Promise.resolve();
3855
4455
  const enqueueWrite = (todos) => {
3856
- writeChain = writeChain.then(() => saveTodosCheckpoint(filePath, sessionId, todos)).catch((err) => {
4456
+ writeChain = writeChain.then(() => saveTodosCheckpoint(filePath, sessionId, todos, events, traceId)).catch((err) => {
3857
4457
  const msg = err instanceof Error ? err.message : String(err);
3858
4458
  console.error(JSON.stringify({
3859
4459
  level: "error",
@@ -3895,25 +4495,79 @@ function attachTodosCheckpoint(state, filePath, sessionId) {
3895
4495
 
3896
4496
  // src/storage/plan-store.ts
3897
4497
  init_atomic_write();
3898
- async function loadPlan(filePath) {
4498
+ async function loadPlan(filePath, events) {
4499
+ const t0 = Date.now();
3899
4500
  let raw;
3900
4501
  try {
3901
4502
  raw = await fsp.readFile(filePath, "utf8");
3902
- } catch {
4503
+ } catch (err) {
4504
+ events?.emit("storage.error", {
4505
+ sessionId: "~boot~",
4506
+ store: "plan",
4507
+ filePath,
4508
+ operation: "load",
4509
+ error: err instanceof Error ? err.message : String(err),
4510
+ recoverable: true
4511
+ });
3903
4512
  return null;
3904
4513
  }
3905
4514
  try {
3906
4515
  const parsed = JSON.parse(raw);
3907
- if (parsed?.version !== 1 || !Array.isArray(parsed.items)) return null;
4516
+ if (parsed?.version !== 1 || !Array.isArray(parsed.items)) {
4517
+ events?.emit("storage.read", {
4518
+ sessionId: "~boot~",
4519
+ store: "plan",
4520
+ filePath,
4521
+ operation: "load",
4522
+ outcome: "failure",
4523
+ durationMs: Date.now() - t0,
4524
+ error: "invalid_schema"
4525
+ });
4526
+ return null;
4527
+ }
4528
+ events?.emit("storage.read", {
4529
+ sessionId: "~boot~",
4530
+ store: "plan",
4531
+ filePath,
4532
+ operation: "load",
4533
+ outcome: "success",
4534
+ durationMs: Date.now() - t0
4535
+ });
3908
4536
  return parsed;
3909
4537
  } catch {
4538
+ events?.emit("storage.read", {
4539
+ sessionId: "~boot~",
4540
+ store: "plan",
4541
+ filePath,
4542
+ operation: "load",
4543
+ outcome: "failure",
4544
+ durationMs: Date.now() - t0,
4545
+ error: "parse_failed"
4546
+ });
3910
4547
  return null;
3911
4548
  }
3912
4549
  }
3913
- async function savePlan(filePath, plan) {
4550
+ async function savePlan(filePath, plan, events) {
4551
+ const t0 = Date.now();
3914
4552
  try {
3915
4553
  await atomicWrite(filePath, JSON.stringify(plan, null, 2), { mode: 384 });
4554
+ events?.emit("storage.write", {
4555
+ sessionId: "~boot~",
4556
+ store: "plan",
4557
+ filePath,
4558
+ operation: "save",
4559
+ outcome: "success",
4560
+ durationMs: Date.now() - t0
4561
+ });
3916
4562
  } catch (err) {
4563
+ events?.emit("storage.error", {
4564
+ sessionId: "~boot~",
4565
+ store: "plan",
4566
+ filePath,
4567
+ operation: "save",
4568
+ error: err instanceof Error ? err.message : String(err),
4569
+ recoverable: false
4570
+ });
3917
4571
  console.warn(
3918
4572
  "[plan-store] save failed:",
3919
4573
  err instanceof Error ? err.message : String(err)
@@ -4493,6 +5147,13 @@ function hasDangerousCapabilityForSubagents(toolOrCaps) {
4493
5147
  const caps = Array.isArray(toolOrCaps) ? toolOrCaps : input.capabilities ?? [];
4494
5148
  return caps.some((c) => DANGEROUS_FOR_SUBAGENTS.includes(c));
4495
5149
  }
5150
+ function hasCapability(toolOrCaps, capability) {
5151
+ if (!toolOrCaps) return false;
5152
+ const input = toolOrCaps;
5153
+ const caps = Array.isArray(toolOrCaps) ? toolOrCaps : input.capabilities ?? [];
5154
+ const toCheck = Array.isArray(capability) ? capability : [capability];
5155
+ return toCheck.some((c) => caps.includes(c));
5156
+ }
4496
5157
  function getDangerousCapabilities(toolOrCaps) {
4497
5158
  if (!toolOrCaps) return [];
4498
5159
  const input = toolOrCaps;
@@ -4856,7 +5517,16 @@ var DefaultPermissionPolicy = class {
4856
5517
  };
4857
5518
  }
4858
5519
  }
4859
- if (tool.permission === "auto" && !tool.mutating) {
5520
+ const hasWriteCap = hasCapability(tool, ToolCapabilities.FS_WRITE);
5521
+ const hasShellCap = hasCapability(tool, [
5522
+ ToolCapabilities.SHELL_ARBITRARY,
5523
+ ToolCapabilities.SHELL_RESTRICTED
5524
+ ]);
5525
+ const hasInstallCap = hasCapability(tool, ToolCapabilities.PACKAGE_INSTALL);
5526
+ const hasConfigCap = hasCapability(tool, ToolCapabilities.CONFIG_MUTATE);
5527
+ const hasSubagentCap = hasCapability(tool, ToolCapabilities.SUBAGENT_SPAWN);
5528
+ const isMutating = tool.mutating || hasWriteCap || hasShellCap || hasInstallCap || hasConfigCap || hasSubagentCap;
5529
+ if (tool.permission === "auto" && !isMutating) {
4860
5530
  const decision = { permission: "auto", source: "default" };
4861
5531
  this._evalCache.set(cacheKey, decision);
4862
5532
  return decision;
@@ -4875,7 +5545,27 @@ var DefaultPermissionPolicy = class {
4875
5545
  }
4876
5546
  return { permission: "confirm", source: "default" };
4877
5547
  }
5548
+ // Capability-based destructive check (preferred over name-based)
5549
+ isDestructiveByCapability(tool) {
5550
+ const caps = tool.capabilities ?? [];
5551
+ if (caps.includes("shell.arbitrary")) return true;
5552
+ if (caps.includes("fs.write")) return true;
5553
+ if (caps.includes("fs.write.outside-project")) return true;
5554
+ return false;
5555
+ }
4878
5556
  isDestructiveYoloCall(tool, input, ctx) {
5557
+ if (this.isDestructiveByCapability(tool)) {
5558
+ if (tool.name === "bash") {
5559
+ const command = getInputString(input, "command");
5560
+ return command ? isClearlyDestructiveBashCommand(command, ctx.projectRoot) : true;
5561
+ }
5562
+ if (tool.name === "write" || tool.name === "edit" || tool.name === "replace" || tool.name === "patch") {
5563
+ const targetPath = getInputString(input, "path") ?? getInputString(input, "file");
5564
+ if (!targetPath || !ctx.projectRoot) return false;
5565
+ return !pathLooksInsideProject(targetPath, ctx.projectRoot);
5566
+ }
5567
+ return true;
5568
+ }
4879
5569
  if (tool.name === "bash") {
4880
5570
  const command = getInputString(input, "command");
4881
5571
  return command ? isClearlyDestructiveBashCommand(command, ctx.projectRoot) : true;
@@ -8086,13 +8776,32 @@ var MAX_JOURNAL_ENTRIES = 500;
8086
8776
  function goalFilePath(projectRoot) {
8087
8777
  return resolveWstackPaths({ projectRoot }).projectGoal;
8088
8778
  }
8089
- async function loadGoal(filePath) {
8779
+ async function loadGoal(filePath, events) {
8780
+ const t0 = Date.now();
8090
8781
  let raw;
8091
8782
  try {
8092
8783
  raw = await fsp.readFile(filePath, "utf8");
8093
8784
  } catch (err) {
8094
8785
  const code = err.code;
8095
- if (code === "ENOENT") return null;
8786
+ if (code === "ENOENT") {
8787
+ events?.emit("storage.read", {
8788
+ sessionId: "~boot~",
8789
+ store: "goal",
8790
+ filePath,
8791
+ operation: "load",
8792
+ outcome: "success",
8793
+ durationMs: Date.now() - t0
8794
+ });
8795
+ return null;
8796
+ }
8797
+ events?.emit("storage.error", {
8798
+ sessionId: "~boot~",
8799
+ store: "goal",
8800
+ filePath,
8801
+ operation: "load",
8802
+ error: err instanceof Error ? err.message : String(err),
8803
+ recoverable: false
8804
+ });
8096
8805
  throw err;
8097
8806
  }
8098
8807
  try {
@@ -8105,8 +8814,25 @@ async function loadGoal(filePath) {
8105
8814
  message: "invalid schema \u2014 consider deleting and re-creating",
8106
8815
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
8107
8816
  }));
8817
+ events?.emit("storage.read", {
8818
+ sessionId: "~boot~",
8819
+ store: "goal",
8820
+ filePath,
8821
+ operation: "load",
8822
+ outcome: "failure",
8823
+ durationMs: Date.now() - t0,
8824
+ error: "invalid_schema"
8825
+ });
8108
8826
  return null;
8109
8827
  }
8828
+ events?.emit("storage.read", {
8829
+ sessionId: "~boot~",
8830
+ store: "goal",
8831
+ filePath,
8832
+ operation: "load",
8833
+ outcome: "success",
8834
+ durationMs: Date.now() - t0
8835
+ });
8110
8836
  return parsed;
8111
8837
  } catch {
8112
8838
  console.warn(JSON.stringify({
@@ -8116,13 +8842,39 @@ async function loadGoal(filePath) {
8116
8842
  message: "JSON parse failed \u2014 consider deleting and re-creating",
8117
8843
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
8118
8844
  }));
8845
+ events?.emit("storage.read", {
8846
+ sessionId: "~boot~",
8847
+ store: "goal",
8848
+ filePath,
8849
+ operation: "load",
8850
+ outcome: "failure",
8851
+ durationMs: Date.now() - t0,
8852
+ error: "parse_failed"
8853
+ });
8119
8854
  return null;
8120
8855
  }
8121
8856
  }
8122
- async function saveGoal(filePath, goal) {
8857
+ async function saveGoal(filePath, goal, events) {
8858
+ const t0 = Date.now();
8123
8859
  try {
8124
8860
  await atomicWrite(filePath, JSON.stringify(goal, null, 2), { mode: 384 });
8861
+ events?.emit("storage.write", {
8862
+ sessionId: "~boot~",
8863
+ store: "goal",
8864
+ filePath,
8865
+ operation: "save",
8866
+ outcome: "success",
8867
+ durationMs: Date.now() - t0
8868
+ });
8125
8869
  } catch (err) {
8870
+ events?.emit("storage.error", {
8871
+ sessionId: "~boot~",
8872
+ store: "goal",
8873
+ filePath,
8874
+ operation: "save",
8875
+ error: err instanceof Error ? err.message : String(err),
8876
+ recoverable: false
8877
+ });
8126
8878
  throw new FsError({
8127
8879
  message: err instanceof Error ? err.message : String(err),
8128
8880
  code: ERROR_CODES.FS_ATOMIC_WRITE_FAILED,
@@ -8292,7 +9044,7 @@ var EternalAutonomyEngine = class {
8292
9044
  const emit = (stage) => {
8293
9045
  this.opts.onStage?.(stage);
8294
9046
  };
8295
- const goal = await loadGoal(this.goalPath);
9047
+ const goal = await loadGoal(this.goalPath, this.opts.events);
8296
9048
  if (!goal) {
8297
9049
  emit({ phase: "stopped" });
8298
9050
  this.stopRequested = true;
@@ -8396,7 +9148,7 @@ var EternalAutonomyEngine = class {
8396
9148
  emit({ phase: "reflect", status, note });
8397
9149
  let iterationIndex = 0;
8398
9150
  try {
8399
- const reloaded = await loadGoal(this.goalPath);
9151
+ const reloaded = await loadGoal(this.goalPath, this.opts.events);
8400
9152
  iterationIndex = reloaded?.iterations ?? 0;
8401
9153
  } catch {
8402
9154
  }
@@ -8716,12 +9468,12 @@ ${recentJournal}` : "No prior iterations.",
8716
9468
  }
8717
9469
  }
8718
9470
  async appendIterationEntry(entry) {
8719
- const current = await loadGoal(this.goalPath);
9471
+ const current = await loadGoal(this.goalPath, this.opts.events);
8720
9472
  if (!current) {
8721
9473
  return;
8722
9474
  }
8723
9475
  const updated = appendJournal(current, entry);
8724
- await saveGoal(this.goalPath, updated);
9476
+ await saveGoal(this.goalPath, updated, this.opts.events);
8725
9477
  }
8726
9478
  /**
8727
9479
  * Persistent per-todo failure counter. Skipped silently when the goal
@@ -8730,11 +9482,11 @@ ${recentJournal}` : "No prior iterations.",
8730
9482
  * the counter to rotate past stuck todos once they cross `todoMaxAttempts`.
8731
9483
  */
8732
9484
  async bumpTodoAttempt(todoId) {
8733
- const current = await loadGoal(this.goalPath);
9485
+ const current = await loadGoal(this.goalPath, this.opts.events);
8734
9486
  if (!current) return;
8735
9487
  const attempts = { ...current.todoAttempts ?? {} };
8736
9488
  attempts[todoId] = (attempts[todoId] ?? 0) + 1;
8737
- await saveGoal(this.goalPath, { ...current, todoAttempts: attempts });
9489
+ await saveGoal(this.goalPath, { ...current, todoAttempts: attempts }, this.opts.events);
8738
9490
  }
8739
9491
  /**
8740
9492
  * Flip the mission to `completed` and journal it. Called from two
@@ -8744,7 +9496,7 @@ ${recentJournal}` : "No prior iterations.",
8744
9496
  * goal is already `completed`.
8745
9497
  */
8746
9498
  async markGoalCompleted(action, note) {
8747
- const current = await loadGoal(this.goalPath);
9499
+ const current = await loadGoal(this.goalPath, this.opts.events);
8748
9500
  if (!current) return;
8749
9501
  if (current.goalState === "completed") return;
8750
9502
  const withFlag = { ...current, goalState: "completed" };
@@ -8754,7 +9506,7 @@ ${recentJournal}` : "No prior iterations.",
8754
9506
  status: "success",
8755
9507
  note: note.slice(0, 240)
8756
9508
  });
8757
- await saveGoal(this.goalPath, withEntry);
9509
+ await saveGoal(this.goalPath, withEntry, this.opts.events);
8758
9510
  this.opts.onEternalStop?.();
8759
9511
  }
8760
9512
  /**
@@ -8763,10 +9515,10 @@ ${recentJournal}` : "No prior iterations.",
8763
9515
  * `onEternalStop` so the REPL returns to normal mode.
8764
9516
  */
8765
9517
  async clearGoalManually(note) {
8766
- const current = await loadGoal(this.goalPath);
9518
+ const current = await loadGoal(this.goalPath, this.opts.events);
8767
9519
  if (current) {
8768
9520
  const abandoned = { ...current, goalState: "abandoned" };
8769
- await saveGoal(this.goalPath, abandoned);
9521
+ await saveGoal(this.goalPath, abandoned, this.opts.events);
8770
9522
  }
8771
9523
  try {
8772
9524
  const { unlink: unlink10 } = await import('fs/promises');
@@ -8842,16 +9594,16 @@ ${recentJournal}` : ""
8842
9594
  * Persist a progress update from the agent's [PROGRESS: N%] output.
8843
9595
  */
8844
9596
  async updateProgress(progress, note) {
8845
- const current = await loadGoal(this.goalPath);
9597
+ const current = await loadGoal(this.goalPath, this.opts.events);
8846
9598
  if (!current) return;
8847
9599
  const updated = recordProgress(current, progress, note);
8848
- await saveGoal(this.goalPath, updated);
9600
+ await saveGoal(this.goalPath, updated, this.opts.events);
8849
9601
  }
8850
9602
  async persistEngineState(state) {
8851
- const current = await loadGoal(this.goalPath);
9603
+ const current = await loadGoal(this.goalPath, this.opts.events);
8852
9604
  if (!current) return;
8853
9605
  if (current.engineState === state) return;
8854
- await saveGoal(this.goalPath, { ...current, engineState: state });
9606
+ await saveGoal(this.goalPath, { ...current, engineState: state }, this.opts.events);
8855
9607
  }
8856
9608
  };
8857
9609
 
@@ -9200,6 +9952,20 @@ var SubagentBudget = class _SubagentBudget {
9200
9952
  };
9201
9953
 
9202
9954
  // src/coordination/agent-subagent-runner.ts
9955
+ function withDisabledToolFiltering(factory) {
9956
+ return async (config) => {
9957
+ const result = await factory(config);
9958
+ const disabled = config.disabledTools ?? [];
9959
+ if (disabled.length === 0) return result;
9960
+ const registry = result.agent.tools;
9961
+ if (registry && typeof registry.unregister === "function") {
9962
+ for (const toolName of disabled) {
9963
+ registry.unregister(toolName);
9964
+ }
9965
+ }
9966
+ return result;
9967
+ };
9968
+ }
9203
9969
  function makeAgentSubagentRunner(opts) {
9204
9970
  const format = opts.formatTaskInput ?? defaultFormatTaskInput;
9205
9971
  return async (task, ctx) => {
@@ -13366,7 +14132,8 @@ var ParallelEternalEngine = class {
13366
14132
  doneCondition: { type: "all_tasks_done" }
13367
14133
  };
13368
14134
  this.coordinator = new DefaultMultiAgentCoordinator(config);
13369
- const runner = makeAgentSubagentRunner({ factory: this.agentFactory });
14135
+ const filteredFactory = withDisabledToolFiltering(this.agentFactory);
14136
+ const runner = makeAgentSubagentRunner({ factory: filteredFactory });
13370
14137
  this.coordinator.setRunner?.(runner);
13371
14138
  try {
13372
14139
  while (!this.stopRequested) {
@@ -13401,7 +14168,7 @@ var ParallelEternalEngine = class {
13401
14168
  this.opts.onStage?.(stage);
13402
14169
  };
13403
14170
  this.iterations++;
13404
- const goal = await loadGoal(this.goalPath);
14171
+ const goal = await loadGoal(this.goalPath, this.opts.events);
13405
14172
  if (!goal) {
13406
14173
  this.stopRequested = true;
13407
14174
  emit({ phase: "stopped" });
@@ -13419,7 +14186,8 @@ var ParallelEternalEngine = class {
13419
14186
  doneCondition: { type: "all_tasks_done" }
13420
14187
  };
13421
14188
  this.coordinator = new DefaultMultiAgentCoordinator(config);
13422
- const runner = makeAgentSubagentRunner({ factory: this.agentFactory });
14189
+ const filteredFactory = withDisabledToolFiltering(this.agentFactory);
14190
+ const runner = makeAgentSubagentRunner({ factory: filteredFactory });
13423
14191
  this.coordinator.setRunner?.(runner);
13424
14192
  }
13425
14193
  emit({ phase: "decompose" });
@@ -13528,13 +14296,17 @@ ${personaLine}Task: ${task}
13528
14296
  role: route.role,
13529
14297
  tools: route.definition.config.tools,
13530
14298
  systemPromptOverride: route.definition.config.prompt,
13531
- timeoutMs: this.timeoutMs
14299
+ timeoutMs: this.timeoutMs,
14300
+ // Disable delegation — subagents are leaf workers, not orchestrators
14301
+ disabledTools: ["delegate"]
13532
14302
  } : {
13533
14303
  id: subagentId,
13534
14304
  name: `slot-${subagentId.slice(-6)}`,
13535
14305
  // Let the coordinator apply its default budget (roster or generic).
13536
14306
  // Hardcoding low limits here defeats the x10 budget improvement.
13537
- timeoutMs: this.timeoutMs
14307
+ timeoutMs: this.timeoutMs,
14308
+ // Disable delegation — subagents are leaf workers, not orchestrators
14309
+ disabledTools: ["delegate"]
13538
14310
  }
13539
14311
  );
13540
14312
  subagentIds.push(subagentId);
@@ -13680,10 +14452,10 @@ ${lastFew}` : "No prior iterations.",
13680
14452
  // Helpers
13681
14453
  // -------------------------------------------------------------------------
13682
14454
  async appendIterationEntry(entry) {
13683
- const current = await loadGoal(this.goalPath);
14455
+ const current = await loadGoal(this.goalPath, this.opts.events);
13684
14456
  if (!current) return;
13685
14457
  const updated = appendJournal(current, entry);
13686
- await saveGoal(this.goalPath, updated);
14458
+ await saveGoal(this.goalPath, updated, this.opts.events);
13687
14459
  const entryWithMeta = {
13688
14460
  at: (this.opts.now?.() ?? /* @__PURE__ */ new Date()).toISOString(),
13689
14461
  iteration: updated.iterations,
@@ -13695,10 +14467,10 @@ ${lastFew}` : "No prior iterations.",
13695
14467
  await this.appendIterationEntry({ source: "manual", task, status: "failure", note });
13696
14468
  }
13697
14469
  async persistState(state) {
13698
- const current = await loadGoal(this.goalPath);
14470
+ const current = await loadGoal(this.goalPath, this.opts.events);
13699
14471
  if (!current) return;
13700
14472
  if (current.engineState === state) return;
13701
- await saveGoal(this.goalPath, { ...current, engineState: state });
14473
+ await saveGoal(this.goalPath, { ...current, engineState: state }, this.opts.events);
13702
14474
  }
13703
14475
  };
13704
14476
 
@@ -14758,7 +15530,12 @@ Working rules:
14758
15530
  6. Never claim a subagent's work as your own without verifying it. If a
14759
15531
  result looks wrong, ask_subagent for clarification before passing it
14760
15532
  to the user.
14761
- 7. Wind down when satisfied. When the results are good enough, call
15533
+ 7. **Act on subagent mail immediately**. Subagent messages (result, ask,
15534
+ assign, note) are injected inline before every step \u2014 even mid-task.
15535
+ When you see one, address it before continuing: reply to asks, factor
15536
+ in results, act on assignments. Use \`mailbox action=ack\` to mark
15537
+ completed messages.
15538
+ 8. Wind down when satisfied. When the results are good enough, call
14762
15539
  work_complete \u2014 no new subagents will spawn and queued tasks complete
14763
15540
  as aborted. Running subagents finish naturally. Call terminate_subagent
14764
15541
  only for ones you need to stop immediately.`;
@@ -14775,6 +15552,13 @@ Bridge contract:
14775
15552
  structured, and self-contained \u2014 assume the Director will paste your
14776
15553
  output into its own context.
14777
15554
 
15555
+ CRITICAL CONSTRAINT \u2014 NO FURTHER DELEGATION:
15556
+ - You MUST NOT call the \`delegate\` tool or attempt to spawn subagents.
15557
+ - You MUST NOT use \`spawn_subagent\`, \`assign_task\`, or any equivalent.
15558
+ - Your role is to execute the assigned task yourself, not to orchestrate.
15559
+ - If a subtask is too complex, report back to the Director with what you
15560
+ found and let the Director decide how to decompose.
15561
+
14778
15562
  Inter-agent mailbox (if you have the \`mail_send\`/\`mail_inbox\`/\`mailbox\` tools):
14779
15563
  - You are part of a project-wide fleet that may span other terminals and
14780
15564
  WebUIs. Your mailbox identity is \`<your-name>@<session-tag>\` (unique
@@ -14789,7 +15573,12 @@ Inter-agent mailbox (if you have the \`mail_send\`/\`mail_inbox\`/\`mailbox\` to
14789
15573
  their exact id instead of doing everything yourself. Discover ids with
14790
15574
  \`mailbox action=online\`.
14791
15575
  - Answer your mail: reply to the sender's exact \`from\` id. When done with
14792
- an assigned task, post a \`result\` back to whoever assigned it.`;
15576
+ an assigned task, post a \`result\` back to whoever assigned it.
15577
+ - **Mail to the leader is always seen**: when you send \`ask\`, \`result\`,
15578
+ or \`assign\` to the director/leader, the message is injected inline into
15579
+ the leader's conversation before their next step \u2014 even if the leader is
15580
+ mid-task. Use \`mail_send\` to reliably reach the leader instead of
15581
+ waiting for them to check in.`;
14793
15582
  function composeDirectorPrompt(parts = {}) {
14794
15583
  const sections = [];
14795
15584
  const preamble = parts.directorPreamble ?? DEFAULT_DIRECTOR_PREAMBLE;
@@ -17186,6 +17975,7 @@ async function readSubagentPartial(opts, subagentId) {
17186
17975
  }
17187
17976
  function makeDirectorSessionFactory(opts) {
17188
17977
  const runId = opts.directorRunId ?? `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-director`;
17978
+ const { traceId } = opts;
17189
17979
  let store;
17190
17980
  let dir;
17191
17981
  if (opts.store) {
@@ -17201,12 +17991,16 @@ function makeDirectorSessionFactory(opts) {
17201
17991
  dir,
17202
17992
  directorRunId: runId,
17203
17993
  async createSubagentSession({ subagentId, provider, model, title }) {
17204
- return store.create({
17994
+ const writer = await store.create({
17205
17995
  id: subagentId,
17206
17996
  title: title ?? subagentId,
17207
17997
  provider: provider ?? "unknown",
17208
17998
  model: model ?? "unknown"
17209
17999
  });
18000
+ if (traceId !== void 0) {
18001
+ writer.traceId = traceId;
18002
+ }
18003
+ return writer;
17210
18004
  }
17211
18005
  };
17212
18006
  }
@@ -20650,7 +21444,9 @@ var SddParallelRun = class {
20650
21444
  doneCondition: { type: "all_tasks_done" }
20651
21445
  };
20652
21446
  this.coordinator = new DefaultMultiAgentCoordinator(config);
20653
- const runner = makeAgentSubagentRunner({ factory: this.opts.subagentFactory ?? this.defaultFactory() });
21447
+ const baseFactory = this.opts.subagentFactory ?? this.defaultFactory();
21448
+ const filteredFactory = withDisabledToolFiltering(baseFactory);
21449
+ const runner = makeAgentSubagentRunner({ factory: filteredFactory });
20654
21450
  this.coordinator.setRunner?.(runner);
20655
21451
  }
20656
21452
  defaultFactory() {
@@ -20692,7 +21488,9 @@ var SddParallelRun = class {
20692
21488
  id: subagentId,
20693
21489
  name: subagentId,
20694
21490
  role: "executor",
20695
- timeoutMs: this.timeoutMs
21491
+ timeoutMs: this.timeoutMs,
21492
+ // Disable delegation — subagents are leaf workers, not orchestrators
21493
+ disabledTools: ["delegate"]
20696
21494
  })
20697
21495
  );
20698
21496
  const spawnResults = await Promise.all(spawns);