@wrongstack/core 0.9.19 → 0.9.20

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-DMVOX0cF.d.ts → agent-bridge-Dti3KXGk.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-C4qt9e5Y.d.ts → agent-subagent-runner-U-rs7kk7.d.ts} +3 -4
  3. package/dist/compactor-D7X96RLZ.d.ts +41 -0
  4. package/dist/{config-CWva0qoL.d.ts → config-CLXMDOSs.d.ts} +1 -1
  5. package/dist/{context-BRNbHmRM.d.ts → context-zkZeILpr.d.ts} +46 -0
  6. package/dist/coordination/index.d.ts +13 -13
  7. package/dist/coordination/index.js +660 -146
  8. package/dist/coordination/index.js.map +1 -1
  9. package/dist/defaults/index.d.ts +20 -20
  10. package/dist/defaults/index.js +918 -350
  11. package/dist/defaults/index.js.map +1 -1
  12. package/dist/{events-CiG9qUM_.d.ts → events-DH-9r-_C.d.ts} +42 -1
  13. package/dist/execution/index.d.ts +41 -30
  14. package/dist/execution/index.js +358 -112
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +6 -6
  17. package/dist/extension/index.js.map +1 -1
  18. package/dist/{index-aizK8olO.d.ts → index-BIHJ4uII.d.ts} +11 -8
  19. package/dist/{index-p95HQ22A.d.ts → index-CFO9QmJo.d.ts} +8 -8
  20. package/dist/index.d.ts +311 -35
  21. package/dist/index.js +1933 -512
  22. package/dist/index.js.map +1 -1
  23. package/dist/infrastructure/index.d.ts +6 -6
  24. package/dist/infrastructure/index.js +36 -0
  25. package/dist/infrastructure/index.js.map +1 -1
  26. package/dist/kernel/index.d.ts +9 -9
  27. package/dist/kernel/index.js.map +1 -1
  28. package/dist/{mcp-servers-BkVEqkRe.d.ts → mcp-servers-DkESgh0G.d.ts} +25 -3
  29. package/dist/models/index.d.ts +2 -2
  30. package/dist/models/index.js +1 -1
  31. package/dist/models/index.js.map +1 -1
  32. package/dist/{multi-agent-3ZnTB1aT.d.ts → multi-agent-DNp6lAzg.d.ts} +35 -23
  33. package/dist/{multi-agent-coordinator-bRaI_aD1.d.ts → multi-agent-coordinator-CAhsegPz.d.ts} +20 -2
  34. package/dist/{null-fleet-bus-DKM3Iy9d.d.ts → null-fleet-bus-Dnl19vmf.d.ts} +411 -110
  35. package/dist/observability/index.d.ts +2 -2
  36. package/dist/{path-resolver-TcJfc29Y.d.ts → path-resolver-CHiBL0DD.d.ts} +2 -2
  37. package/dist/{permission-bPuzAy4x.d.ts → permission-H35s9Evv.d.ts} +1 -1
  38. package/dist/{permission-policy-BUQSutpl.d.ts → permission-policy-CT-nRmTn.d.ts} +2 -2
  39. package/dist/{plan-templates-fkQTyz3U.d.ts → plan-templates-Bs8iRwi6.d.ts} +4 -4
  40. package/dist/{provider-runner-BEpikbbN.d.ts → provider-runner-BZdDrWrS.d.ts} +3 -3
  41. package/dist/{retry-policy-BYkq0ugs.d.ts → retry-policy-J9N_PM40.d.ts} +1 -1
  42. package/dist/sdd/index.d.ts +9 -10
  43. package/dist/sdd/index.js +224 -68
  44. package/dist/sdd/index.js.map +1 -1
  45. package/dist/security/index.d.ts +3 -3
  46. package/dist/{selector-pox8abg0.d.ts → selector-CFTh3Z6p.d.ts} +1 -1
  47. package/dist/{session-reader-CSWcb5Ga.d.ts → session-reader-C7JJlxOw.d.ts} +2 -2
  48. package/dist/skills/index.d.ts +1 -1
  49. package/dist/skills/index.js +1 -1
  50. package/dist/skills/index.js.map +1 -1
  51. package/dist/storage/index.d.ts +390 -6
  52. package/dist/storage/index.js +672 -35
  53. package/dist/storage/index.js.map +1 -1
  54. package/dist/{system-prompt-Bs-Wliab.d.ts → system-prompt-CneIxVip.d.ts} +1 -1
  55. package/dist/{tool-executor-Boo3dekH.d.ts → tool-executor-flTuxsqO.d.ts} +9 -4
  56. package/dist/types/index.d.ts +14 -14
  57. package/dist/types/index.js +60 -0
  58. package/dist/types/index.js.map +1 -1
  59. package/dist/utils/index.d.ts +18 -6
  60. package/dist/utils/index.js +61 -56
  61. package/dist/utils/index.js.map +1 -1
  62. package/package.json +1 -1
  63. package/dist/compactor-DVTKL7XD.d.ts +0 -23
@@ -410,7 +410,11 @@ Working rules:
410
410
  thrashing, terminate it rather than letting cost climb silently.
411
411
  6. Never claim a subagent's work as your own without verifying it. If a
412
412
  result looks wrong, ask_subagent for clarification before passing it
413
- to the user.`;
413
+ to the user.
414
+ 7. Wind down when satisfied. When the results are good enough, call
415
+ work_complete \u2014 no new subagents will spawn and queued tasks complete
416
+ as aborted. Running subagents finish naturally. Call terminate_subagent
417
+ only for ones you need to stop immediately.`;
414
418
  var DEFAULT_SUBAGENT_BASELINE = `You are a subagent operating under a Director. You were spawned to handle
415
419
  a specific slice of a larger plan \u2014 do that slice well and report back.
416
420
 
@@ -555,14 +559,12 @@ var FleetBus = class {
555
559
  };
556
560
  var FleetUsageAggregator = class {
557
561
  constructor(bus, priceLookup, metaLookup) {
558
- this.bus = bus;
559
562
  this.priceLookup = priceLookup;
560
563
  this.metaLookup = metaLookup;
561
564
  bus.filter("provider.response", (e) => this.onProviderResponse(e));
562
565
  bus.filter("tool.executed", (e) => this.onToolExecuted(e));
563
566
  bus.filter("iteration.started", (e) => this.onIterationStarted(e));
564
567
  }
565
- bus;
566
568
  priceLookup;
567
569
  metaLookup;
568
570
  perSubagent = /* @__PURE__ */ new Map();
@@ -704,7 +706,7 @@ var DOMAIN_PREFERENCES = {
704
706
  "e2e": ["hopper", "bell", "marconi", "tesla"],
705
707
  "performance": ["knuth", "gauss", "planck", "feynman"],
706
708
  "chaos": ["tesla", "edison", "curie", "fermi"],
707
- "cost": ["oh", "bell", "marconi", "tesla"],
709
+ "cost": ["ohm", "bell", "marconi", "tesla"],
708
710
  // default fallback
709
711
  "default": ["einstein", "newton", "curie", "tesla", "edison", "turing", "shannon", "hopper", "knuth", "stallman"]
710
712
  };
@@ -714,8 +716,9 @@ function assignNickname(role, used) {
714
716
  ...DOMAIN_PREFERENCES["default"] ?? []
715
717
  ];
716
718
  for (const key of preferences) {
717
- if (!used.has(key)) {
718
- return `${NICKNAME_POOL[key].name} (${formatRole(role)})`;
719
+ const entry = NICKNAME_POOL[key];
720
+ if (entry && !used.has(key)) {
721
+ return `${entry.name} (${formatRole(role)})`;
719
722
  }
720
723
  }
721
724
  for (const entry of ALL_NICKNAMES) {
@@ -879,17 +882,7 @@ var SubagentBudget = class _SubagentBudget {
879
882
  startTime = null;
880
883
  _onThreshold;
881
884
  /**
882
- * Tracks which budget kinds currently have an extension request
883
- * in flight. While a kind is here, further `checkLimit` calls for the
884
- * same kind are no-ops — without this dedup, every `recordIteration`
885
- * after the limit is reached spawns a fresh decision Promise (until
886
- * the first one lands and patches limits), flooding the FleetBus
887
- * with redundant threshold events. Cleared in `negotiateExtension`'s
888
- * `finally`.
889
- */
890
- pendingExtensions = /* @__PURE__ */ new Set();
891
- /**
892
- * Hard cap on how long `negotiateExtension` waits for the coordinator to
885
+ * Hard cap on how long `_negotiateExtension` waits for the coordinator to
893
886
  * respond before defaulting to 'stop'. Without this fallback an absent
894
887
  * or hung listener (Director not built / event filter detached mid-run)
895
888
  * leaves the budget over-limit and never enforces anything.
@@ -951,38 +944,83 @@ var SubagentBudget = class _SubagentBudget {
951
944
  * - `mode === 'auto'` + no listener → throw `BudgetExceededError` (hard stop; no one to ask)
952
945
  * - `mode === 'auto'` + listener → throw `BudgetThresholdSignal` with async decision promise
953
946
  */
954
- checkLimit(kind, used, limit) {
947
+ /**
948
+ * Collects all exceeded budget kinds into a single NOOP-free negotiation.
949
+ * Called by recordIteration / recordToolCall / recordUsage — each may call
950
+ * this for its own kind. The first call starts the negotiation and stores
951
+ * the Promise in _pendingNegotiation. Subsequent calls for DIFFERENT
952
+ * kinds (while a negotiation is in flight) are NOOPs — they don't start
953
+ * new conversations with the coordinator. This prevents an EventBus flood
954
+ * when multiple budget kinds are exceeded simultaneously in one iteration.
955
+ *
956
+ * Returns the kinds that were found to be exceeded (for logging/debugging).
957
+ */
958
+ checkLimits(elapsedMs) {
959
+ const exceeded = [];
960
+ if (this.limits.maxIterations !== void 0 && this.iterations > this.limits.maxIterations) {
961
+ exceeded.push({ kind: "iterations", used: this.iterations, limit: this.limits.maxIterations });
962
+ }
963
+ if (this.limits.maxToolCalls !== void 0 && this.toolCalls > this.limits.maxToolCalls) {
964
+ exceeded.push({ kind: "tool_calls", used: this.toolCalls, limit: this.limits.maxToolCalls });
965
+ }
966
+ const totalTokens = this.tokenInput + this.tokenOutput;
967
+ if (this.limits.maxTokens !== void 0 && totalTokens > this.limits.maxTokens) {
968
+ exceeded.push({ kind: "tokens", used: totalTokens, limit: this.limits.maxTokens });
969
+ }
970
+ if (this.limits.maxCostUsd !== void 0 && this.costUsd > this.limits.maxCostUsd) {
971
+ exceeded.push({ kind: "cost", used: this.costUsd, limit: this.limits.maxCostUsd });
972
+ }
973
+ if (elapsedMs !== void 0 && this.limits.timeoutMs !== void 0 && elapsedMs > this.limits.timeoutMs) {
974
+ exceeded.push({ kind: "timeout", used: elapsedMs, limit: this.limits.timeoutMs });
975
+ }
976
+ if (exceeded.length === 0) return [];
955
977
  if (!this._onThreshold) {
956
- throw new BudgetExceededError(kind, limit, used);
978
+ const first2 = exceeded[0];
979
+ throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
957
980
  }
958
981
  if (this._mode === "sync") {
959
- throw new BudgetExceededError(kind, limit, used);
982
+ const first2 = exceeded[0];
983
+ throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
960
984
  }
961
985
  const bus = this._events;
962
986
  if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
963
- throw new BudgetExceededError(kind, limit, used);
987
+ const first2 = exceeded[0];
988
+ throw new BudgetExceededError(first2.kind, first2.limit, first2.used);
964
989
  }
965
- if (this.pendingExtensions.has(kind)) return;
966
- this.pendingExtensions.add(kind);
967
- const decision = this.negotiateExtension(kind, used, limit);
968
- throw new BudgetThresholdSignal(kind, limit, used, decision);
990
+ for (const entry of exceeded) {
991
+ if (this._pendingNegotiations.has(entry.kind)) continue;
992
+ const decision2 = this._negotiateExtension(entry.kind, exceeded);
993
+ this._pendingNegotiations.set(entry.kind, decision2);
994
+ }
995
+ const first = exceeded[0];
996
+ const decision = this._pendingNegotiations.get(first.kind);
997
+ throw new BudgetThresholdSignal(first.kind, first.limit, first.used, decision);
969
998
  }
999
+ /**
1000
+ * Per-kind in-flight negotiation Promises. Each budget kind can have its
1001
+ * own concurrent negotiation — e.g. iterations and timeout can both
1002
+ * be exceeded simultaneously without blocking each other. The same kind
1003
+ * cannot start two concurrent negotiations (dedup guard).
1004
+ * Cleared in `_negotiateExtension`'s `finally` block.
1005
+ */
1006
+ _pendingNegotiations = /* @__PURE__ */ new Map();
970
1007
  /**
971
1008
  * Drive the threshold handler to a decision. Resolves with `'stop'`
972
1009
  * (signal the runner to abort) or `{ extend: ... }` (limits already
973
- * patched in-place; the runner should not abort). Always releases the
974
- * `pendingExtensions` slot in `finally`.
1010
+ * patched in-place; the runner should not abort). Clears the
1011
+ * per-kind slot in `_pendingNegotiations` in `finally`.
975
1012
  *
976
1013
  * The 'continue' return from a sync handler is treated as
977
1014
  * `{ extend: {} }` — keep going without patching; next overrun fires
978
1015
  * a fresh signal.
979
1016
  */
980
- async negotiateExtension(kind, used, limit) {
1017
+ async _negotiateExtension(kind, exceeded) {
981
1018
  try {
1019
+ const first = exceeded[0];
982
1020
  const result = this._onThreshold({
983
- kind,
984
- used,
985
- limit,
1021
+ kind: first.kind,
1022
+ used: first.used,
1023
+ limit: first.limit,
986
1024
  requestDecision: () => {
987
1025
  const bus = this._events;
988
1026
  if (!bus || !bus.hasListenerFor("budget.threshold_reached")) {
@@ -999,20 +1037,22 @@ var SubagentBudget = class _SubagentBudget {
999
1037
  () => respond("stop"),
1000
1038
  _SubagentBudget.DECISION_TIMEOUT_MS
1001
1039
  );
1002
- bus.emit("budget.threshold_reached", {
1003
- kind,
1004
- used,
1005
- limit,
1006
- timeoutMs: _SubagentBudget.DECISION_TIMEOUT_MS,
1007
- extend: (extra) => {
1008
- clearTimeout(fallback);
1009
- respond({ extend: extra });
1010
- },
1011
- deny: () => {
1012
- clearTimeout(fallback);
1013
- respond("stop");
1014
- }
1015
- });
1040
+ for (const { kind: kind2, used, limit } of exceeded) {
1041
+ bus.emit("budget.threshold_reached", {
1042
+ kind: kind2,
1043
+ used,
1044
+ limit,
1045
+ timeoutMs: _SubagentBudget.DECISION_TIMEOUT_MS,
1046
+ extend: (extra) => {
1047
+ clearTimeout(fallback);
1048
+ respond({ extend: extra });
1049
+ },
1050
+ deny: () => {
1051
+ clearTimeout(fallback);
1052
+ respond("stop");
1053
+ }
1054
+ });
1055
+ }
1016
1056
  });
1017
1057
  }
1018
1058
  });
@@ -1038,47 +1078,39 @@ var SubagentBudget = class _SubagentBudget {
1038
1078
  }
1039
1079
  return decision;
1040
1080
  } finally {
1041
- this.pendingExtensions.delete(kind);
1081
+ this._pendingNegotiations.delete(kind);
1042
1082
  }
1043
1083
  }
1044
1084
  recordIteration() {
1045
1085
  this.iterations++;
1046
- if (this.limits.maxIterations !== void 0 && this.iterations > this.limits.maxIterations) {
1047
- void this.checkLimit("iterations", this.iterations, this.limits.maxIterations);
1048
- }
1086
+ void this.checkLimits();
1049
1087
  }
1050
1088
  recordToolCall() {
1051
1089
  this.toolCalls++;
1052
- if (this.limits.maxToolCalls !== void 0 && this.toolCalls > this.limits.maxToolCalls) {
1053
- void this.checkLimit("tool_calls", this.toolCalls, this.limits.maxToolCalls);
1054
- }
1090
+ void this.checkLimits();
1055
1091
  }
1056
1092
  recordUsage(usage, costUsd = 0) {
1057
1093
  this.tokenInput += usage.input;
1058
1094
  this.tokenOutput += usage.output;
1059
1095
  this.costUsd += costUsd;
1060
- const totalTokens = this.tokenInput + this.tokenOutput;
1061
- if (this.limits.maxTokens !== void 0 && totalTokens > this.limits.maxTokens) {
1062
- void this.checkLimit("tokens", totalTokens, this.limits.maxTokens);
1063
- }
1064
- if (this.limits.maxCostUsd !== void 0 && this.costUsd > this.limits.maxCostUsd) {
1065
- void this.checkLimit("cost", this.costUsd, this.limits.maxCostUsd);
1066
- }
1096
+ void this.checkLimits();
1067
1097
  }
1068
1098
  /**
1069
- * Wall-clock budget check. Unlike other limits, timeout check passes through
1070
- * `checkLimit` and is subject to the same negotiation-mode decision table.
1071
- * In practice, `'sync'` mode (the usual test configuration) means a timeout
1072
- * immediately throws `BudgetExceededError`. In production with a coordinator,
1073
- * a timeout emits `budget.threshold_reached` so the Director can decide whether
1074
- * to extend or abort.
1099
+ * Wall-clock budget check. Unlike other limits, timeout is always a hard stop
1100
+ * wall-clock time cannot be "extended" by the coordinator, so it throws
1101
+ * synchronously rather than entering the negotiation flow.
1102
+ *
1103
+ * Decision table:
1104
+ * - no `onThreshold` handler → throw `BudgetExceededError`
1105
+ * - `mode === 'sync'` → throw `BudgetExceededError`
1106
+ * - `mode === 'auto'` + no listener → throw `BudgetExceededError`
1107
+ * - `mode === 'auto'` + listener → throw `BudgetExceededError` (timeout is not extendable)
1075
1108
  */
1076
1109
  checkTimeout() {
1077
1110
  if (this.startTime === null || this.limits.timeoutMs === void 0) return;
1078
1111
  const elapsed = Date.now() - this.startTime;
1079
- if (elapsed > this.limits.timeoutMs) {
1080
- void this.checkLimit("timeout", elapsed, this.limits.timeoutMs);
1081
- }
1112
+ if (elapsed <= this.limits.timeoutMs) return;
1113
+ void this.checkLimits(elapsed);
1082
1114
  }
1083
1115
  /** Returns true if a timeout has occurred without throwing. Useful for races. */
1084
1116
  isTimedOut() {
@@ -3583,6 +3615,15 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
3583
3615
  runner;
3584
3616
  fleetBus;
3585
3617
  subagents = /* @__PURE__ */ new Map();
3618
+ /**
3619
+ * Base nickname keys already handed out this run (e.g. `einstein`, `tesla`).
3620
+ * Prevents two workers sharing a name. Direct `coordinator.spawn()` callers
3621
+ * (parallel/eternal engine, SDD parallel run) don't go through
3622
+ * `Director.spawn()` where nicknames are normally assigned, so the
3623
+ * coordinator upgrades placeholder names ("Executor", "slot-ab12cd", role
3624
+ * names) to memorable ones here — that's what surfaces in the fleet monitor.
3625
+ */
3626
+ usedNicknames = /* @__PURE__ */ new Set();
3586
3627
  pendingTasks = [];
3587
3628
  completedResults = [];
3588
3629
  totalIterations = 0;
@@ -3631,7 +3672,26 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
3631
3672
  this.config.maxConcurrent = Math.floor(n);
3632
3673
  this.tryDispatchNext();
3633
3674
  }
3675
+ /**
3676
+ * Upgrade a placeholder/role-derived name to a memorable scientist nickname
3677
+ * (e.g. "Einstein (Executor)"). A name is treated as a placeholder when it is
3678
+ * empty, equals the role (case-insensitive), is a generic default
3679
+ * ("subagent"/"adhoc"/"generic"), or is an auto-generated `slot-…` id.
3680
+ * Explicit, human-chosen names — including nicknames already assigned by
3681
+ * `Director.spawn()` — are left untouched, so this never double-assigns.
3682
+ */
3683
+ withNickname(subagent) {
3684
+ const role = subagent.role ?? "subagent";
3685
+ const name = subagent.name?.trim() ?? "";
3686
+ const isPlaceholder = name === "" || name.toLowerCase() === role.toLowerCase() || name === "subagent" || name === "adhoc" || name === "generic" || /^slot-/.test(name);
3687
+ if (!isPlaceholder) return subagent;
3688
+ const nickname = assignNickname(role, this.usedNicknames);
3689
+ const baseKey = nickname.split(" ")[0].toLowerCase().replace(/[^a-z0-9-]/g, "-");
3690
+ this.usedNicknames.add(baseKey);
3691
+ return { ...subagent, name: nickname };
3692
+ }
3634
3693
  async spawn(subagent) {
3694
+ subagent = this.withNickname(subagent);
3635
3695
  const id = subagent.id || randomUUID();
3636
3696
  if (this.subagents.has(id)) {
3637
3697
  throw new Error(`Subagent id "${id}" already exists \u2014 refusing to overwrite`);
@@ -4510,7 +4570,7 @@ function makeRollUpTool(director) {
4510
4570
  function makeTerminateTool(director) {
4511
4571
  return {
4512
4572
  name: "terminate_subagent",
4513
- description: "Forcibly abort a subagent.",
4573
+ description: 'Forcibly abort a subagent. The subagent finishes its current iteration then exits with status "stopped".',
4514
4574
  permission: "auto",
4515
4575
  mutating: true,
4516
4576
  inputSchema: { type: "object", properties: { subagentId: { type: "string", description: "Subagent to abort." } }, required: ["subagentId"] },
@@ -4521,6 +4581,19 @@ function makeTerminateTool(director) {
4521
4581
  }
4522
4582
  };
4523
4583
  }
4584
+ function makeTerminateAllTool(director) {
4585
+ return {
4586
+ name: "terminate_all",
4587
+ description: 'Forcibly stop every subagent in the fleet and drain the pending task queue. In-flight tasks are terminated mid-execution; pending tasks receive "aborted_by_parent" completion immediately. Use this when the fleet is wedged, looping, or you need a clean slate. Compare: work_complete stops spawning but lets running agents finish naturally.',
4588
+ permission: "auto",
4589
+ mutating: true,
4590
+ inputSchema: { type: "object", properties: {}, required: [] },
4591
+ async execute() {
4592
+ await director.terminateAll();
4593
+ return { ok: true, message: `Fleet shutdown complete \u2014 all subagents stopped, pending tasks drained.` };
4594
+ }
4595
+ };
4596
+ }
4524
4597
  function makeFleetStatusTool(director) {
4525
4598
  return {
4526
4599
  name: "fleet_status",
@@ -4663,7 +4736,7 @@ function makeCollabDebugTool(director) {
4663
4736
  function makeFleetEmitTool(director) {
4664
4737
  return {
4665
4738
  name: "fleet_emit",
4666
- description: "Emit a structured event on the FleetBus. Use this when you find a bug (bug.found), complete a refactor plan (refactor.plan), or finish an evaluation (critic.evaluation). Events are routed to other agents in the collab session.",
4739
+ description: "Emit a structured event on the FleetBus. Any subagent can emit any event type; the Director routes it to all listeners. Use it to stream findings, progress updates, or final results to other agents in real time.",
4667
4740
  permission: "auto",
4668
4741
  mutating: false,
4669
4742
  inputSchema: {
@@ -4671,14 +4744,14 @@ function makeFleetEmitTool(director) {
4671
4744
  properties: {
4672
4745
  type: {
4673
4746
  type: "string",
4674
- description: "Event type: bug.found | refactor.plan | critic.evaluation"
4747
+ description: "Event type string (e.g. bug.found, refactor.plan, critic.evaluation, progress, result)."
4675
4748
  },
4676
4749
  payload: {
4677
4750
  type: "object",
4678
- description: "Event payload matching the event type."
4751
+ description: "Event payload. Structure depends on event type. Use null if no payload."
4679
4752
  }
4680
4753
  },
4681
- required: ["type", "payload"]
4754
+ required: ["type"]
4682
4755
  },
4683
4756
  async execute(input) {
4684
4757
  const i = input;
@@ -4686,12 +4759,31 @@ function makeFleetEmitTool(director) {
4686
4759
  subagentId: director.id,
4687
4760
  ts: Date.now(),
4688
4761
  type: i.type,
4689
- payload: i.payload
4762
+ payload: i.payload ?? {}
4690
4763
  });
4691
4764
  return { ok: true, event: i.type };
4692
4765
  }
4693
4766
  };
4694
4767
  }
4768
+ function makeWorkCompleteTool(director) {
4769
+ return {
4770
+ name: "work_complete",
4771
+ description: "Signal that the director is satisfied with the results and the fleet should wind down. After calling this, spawn_subagent will refuse with a budget error and assign_task will instantly complete any queued tasks as aborted. Running subagents finish naturally. Call terminate_subagent separately to stop specific subagents immediately.",
4772
+ permission: "auto",
4773
+ mutating: false,
4774
+ inputSchema: { type: "object", properties: {}, required: [] },
4775
+ async execute() {
4776
+ director.workComplete();
4777
+ return { ok: true, message: "Fleet wind-down signaled. No new spawns or task dispatches." };
4778
+ }
4779
+ };
4780
+ }
4781
+ var DirectorAlertLevel = /* @__PURE__ */ ((DirectorAlertLevel2) => {
4782
+ DirectorAlertLevel2["WARNING"] = "warning";
4783
+ DirectorAlertLevel2["CRITICAL"] = "critical";
4784
+ DirectorAlertLevel2["CANCELLED"] = "cancelled";
4785
+ return DirectorAlertLevel2;
4786
+ })(DirectorAlertLevel || {});
4695
4787
  var CollabSession = class extends EventEmitter {
4696
4788
  sessionId;
4697
4789
  options;
@@ -4706,6 +4798,14 @@ var CollabSession = class extends EventEmitter {
4706
4798
  disposers = new Array();
4707
4799
  settled = false;
4708
4800
  timeoutMs;
4801
+ cancelled = false;
4802
+ alerts = [];
4803
+ /** Tracks tool call counts per subagent for progress-based timeout decisions. */
4804
+ progressBySubagent = /* @__PURE__ */ new Map();
4805
+ /** Last tool call count when a timeout warning was handled. */
4806
+ lastTimeoutProgress = /* @__PURE__ */ new Map();
4807
+ /** Session-level timeout timer handle (cleared on cancel or natural completion). */
4808
+ _timeoutTimer;
4709
4809
  constructor(director, fleetBus, options) {
4710
4810
  super();
4711
4811
  this.sessionId = randomUUID();
@@ -4723,11 +4823,23 @@ var CollabSession = class extends EventEmitter {
4723
4823
  };
4724
4824
  }
4725
4825
  }
4826
+ get id() {
4827
+ return this.sessionId;
4828
+ }
4829
+ getSessionAlerts() {
4830
+ return [...this.alerts];
4831
+ }
4832
+ isCancelled() {
4833
+ return this.cancelled;
4834
+ }
4726
4835
  /**
4727
- * Read the target files from disk and populate the snapshot.
4728
- * Call this after construction if you did not provide a prebuiltSnapshot
4729
- * and want the session to operate on real file contents.
4836
+ * Snapshot of role subagentId map. The Director calls coordinator.stop()
4837
+ * for each agent when cancelling the session, using this map to enumerate
4838
+ * all three collab agents.
4730
4839
  */
4840
+ getSubagentIds() {
4841
+ return new Map(this.subagentIds);
4842
+ }
4731
4843
  async buildSnapshot() {
4732
4844
  if (this.snapshot.files.length > 0) return this.snapshot;
4733
4845
  for (const filePath of this.options.targetPaths) {
@@ -4743,9 +4855,30 @@ var CollabSession = class extends EventEmitter {
4743
4855
  return this.snapshot;
4744
4856
  }
4745
4857
  /**
4746
- * Start the collaborative session: snapshot files, spawn all three agents,
4747
- * wire up event routing, and wait for completion.
4858
+ * Cancel the session. Emits director.cancel_collab on the FleetBus so all
4859
+ * collab agents finish early. The session-level timeout timer is also cleared.
4860
+ * Safe to call multiple times (idempotent after first call).
4748
4861
  */
4862
+ cancel(reason = "Director cancelled collab session") {
4863
+ if (this.settled) return;
4864
+ this.cancelled = true;
4865
+ if (this._timeoutTimer) {
4866
+ clearTimeout(this._timeoutTimer);
4867
+ this._timeoutTimer = void 0;
4868
+ }
4869
+ this.fleetBus.emit({
4870
+ subagentId: this.director.id,
4871
+ ts: Date.now(),
4872
+ type: "director.cancel_collab",
4873
+ payload: { sessionId: this.sessionId, reason, cancelledAt: (/* @__PURE__ */ new Date()).toISOString() }
4874
+ });
4875
+ this.fleetBus.emit({
4876
+ subagentId: this.director.id,
4877
+ ts: Date.now(),
4878
+ type: "collab.cancelled",
4879
+ payload: { sessionId: this.sessionId, reason }
4880
+ });
4881
+ }
4749
4882
  async start() {
4750
4883
  if (this.settled) throw new Error("session already settled");
4751
4884
  this.settled = true;
@@ -4760,10 +4893,10 @@ var CollabSession = class extends EventEmitter {
4760
4893
  this.subagentIds.set("refactor-planner", refactorPlannerId);
4761
4894
  this.subagentIds.set("critic", criticId);
4762
4895
  const timeout = new Promise((_, reject) => {
4763
- setTimeout(
4764
- () => reject(new Error(`CollabSession timed out after ${this.timeoutMs}ms`)),
4765
- this.timeoutMs
4766
- );
4896
+ this._timeoutTimer = setTimeout(() => {
4897
+ this.cancel("Session-level timeout reached");
4898
+ reject(new Error(`CollabSession timed out after ${this.timeoutMs}ms`));
4899
+ }, this.timeoutMs);
4767
4900
  });
4768
4901
  let results;
4769
4902
  try {
@@ -4776,6 +4909,10 @@ var CollabSession = class extends EventEmitter {
4776
4909
  timeout
4777
4910
  ]);
4778
4911
  } catch (err) {
4912
+ if (this._timeoutTimer) {
4913
+ clearTimeout(this._timeoutTimer);
4914
+ this._timeoutTimer = void 0;
4915
+ }
4779
4916
  this.cleanup();
4780
4917
  const error = err instanceof Error ? err : new Error(String(err));
4781
4918
  this.emit("session.error", error);
@@ -4789,17 +4926,6 @@ var CollabSession = class extends EventEmitter {
4789
4926
  this.emit("session.done", report);
4790
4927
  return report;
4791
4928
  }
4792
- /**
4793
- * Parse a completed agent's final text output and route the structured
4794
- * findings onto the FleetBus. Agents are instructed to emit one JSON object
4795
- * per finding / plan / evaluation; we scan the output for balanced JSON
4796
- * objects (tolerating prose, markdown, and ```json fences around them) and
4797
- * dispatch each by its discriminating key. The wired FleetBus listeners then
4798
- * collect them into the bugs / plans / evaluations maps.
4799
- *
4800
- * Failed or empty results are ignored, and a single malformed object never
4801
- * aborts the collation pass — see {@link extractJsonObjects}.
4802
- */
4803
4929
  async parseAndEmit(result) {
4804
4930
  if (result.status !== "success" || result.result == null) return;
4805
4931
  const text = typeof result.result === "string" ? result.result : JSON.stringify(result.result);
@@ -4815,12 +4941,6 @@ var CollabSession = class extends EventEmitter {
4815
4941
  });
4816
4942
  }
4817
4943
  }
4818
- /**
4819
- * Extract every top-level JSON object embedded in free-form agent text.
4820
- * Scans for balanced braces while respecting string literals and escape
4821
- * sequences, so prose, markdown headers, and code fences around the JSON
4822
- * are skipped. Malformed spans are dropped silently rather than thrown.
4823
- */
4824
4944
  extractJsonObjects(text) {
4825
4945
  const objects = [];
4826
4946
  let depth = 0;
@@ -4857,25 +4977,33 @@ var CollabSession = class extends EventEmitter {
4857
4977
  }
4858
4978
  return objects;
4859
4979
  }
4980
+ budgetForRole(role) {
4981
+ if (this.options.budgetOverrides?.[role]) {
4982
+ return this.options.budgetOverrides[role];
4983
+ }
4984
+ const defaults = {
4985
+ "bug-hunter": { maxIterations: 2e3, maxToolCalls: 5e3, timeoutMs: 10 * 60 * 1e3 },
4986
+ "refactor-planner": { maxIterations: 1500, maxToolCalls: 4e3, timeoutMs: 8 * 60 * 1e3 },
4987
+ "critic": { maxIterations: 1e3, maxToolCalls: 3e3, timeoutMs: 6 * 60 * 1e3 }
4988
+ };
4989
+ return defaults[role] ?? { maxIterations: 1500, maxToolCalls: 4e3, timeoutMs: 8 * 60 * 1e3 };
4990
+ }
4860
4991
  async spawnAgent(role, taskBrief) {
4992
+ const budget = this.budgetForRole(role);
4861
4993
  const cfg = {
4862
4994
  id: `${role}-${this.sessionId}`,
4863
4995
  name: role,
4864
- role
4865
- // No fleet_emit tool agents output structured JSON, the Director parses
4866
- // results and emits FleetBus events. This keeps the agent simple and the
4867
- // routing deterministic.
4996
+ role,
4997
+ tools: ["fleet_emit", "fleet_status", "read", "grep", "glob", "bash", "write"],
4998
+ maxIterations: budget.maxIterations,
4999
+ maxToolCalls: budget.maxToolCalls,
5000
+ timeoutMs: budget.timeoutMs
4868
5001
  };
4869
5002
  const subagentId = await this.director.spawn(cfg);
4870
- await this.director.assign({
4871
- id: randomUUID(),
4872
- subagentId,
4873
- description: taskBrief
4874
- });
5003
+ await this.director.assign({ id: randomUUID(), subagentId, description: taskBrief });
4875
5004
  return subagentId;
4876
5005
  }
4877
5006
  buildBugHunterTask() {
4878
- this.options.targetPaths.join(", ");
4879
5007
  const scratchpad = this.director.sharedScratchpadPath ?? "/tmp";
4880
5008
  const fileContents = this.snapshot.files.map((f) => `=== ${f.path} ===
4881
5009
  ${f.content}`).join("\n\n");
@@ -4884,13 +5012,17 @@ ${f.content}`).join("\n\n");
4884
5012
  Target files:
4885
5013
  ${fileContents}
4886
5014
 
4887
- For each bug found, write ONE valid JSON line to the scratchpad with this exact structure:
4888
- { "finding": { "id": "<uuid>", "type": "<pattern>", "severity": "<critical|high|medium|low>", "location": { "file": "<path>", "line": <n> }, "description": "<explain>", "suggestedFix": "<optional>" } }.
4889
- After scanning all files, write your full markdown bug report to the shared scratchpad at:
4890
- ${scratchpad}/bug-hunter-report-${this.sessionId}.md`;
5015
+ For each bug found, emit it using the fleet_emit tool immediately:
5016
+ { "type": "bug.found", "payload": { "finding": { "id": "<uuid>", "type": "<pattern>", "severity": "<critical|high|medium|low>", "location": { "file": "<path>", "line": <n> }, "description": "<explain>", "suggestedFix": "<optional>" } } }
5017
+
5018
+ After scanning all files, write your full markdown bug report to:
5019
+ ${scratchpad}/bug-hunter-report-${this.sessionId}.md
5020
+
5021
+ Important: emit each finding as soon as you find it. Do not batch or wait until the end.`;
4891
5022
  }
4892
5023
  buildRefactorPlannerTask() {
4893
5024
  const scratchpad = this.director.sharedScratchpadPath ?? "/tmp";
5025
+ const bugHunterReportPath = `${scratchpad}/bug-hunter-report-${this.sessionId}.md`;
4894
5026
  const fileContents = this.snapshot.files.map((f) => `=== ${f.path} ===
4895
5027
  ${f.content}`).join("\n\n");
4896
5028
  return `You are RefactorPlanner. Plan refactorings for the following files.
@@ -4898,26 +5030,146 @@ ${f.content}`).join("\n\n");
4898
5030
  Target files:
4899
5031
  ${fileContents}
4900
5032
 
4901
- Listen for bug.found events from BugHunter on the fleet bus. For each bug, create a refactor plan and write one JSON line per plan:
4902
- { "plan": { "id": "<uuid>", "basedOnBugIds": ["<bug-id>"], "phases": [...], "riskScore": "<low|medium|high>", "estimatedChangeCount": <n>, "rollbackStrategy": "<text>" } }.
4903
- After planning, write your full markdown plan to:
4904
- ${scratchpad}/refactor-plan-${this.sessionId}.md`;
5033
+ Read the BugHunter report at: ${bugHunterReportPath}
5034
+
5035
+ For each bug you can address, emit a refactor plan using fleet_emit:
5036
+ { "type": "refactor.plan", "payload": { "plan": { "id": "<uuid>", "basedOnBugIds": ["<bug-id>"], "phases": [{ "number": 1, "title": "<phase>", "tasks": ["<task>"], "risk": "<low|medium|high>" }], "riskScore": "<low|medium|high>", "estimatedChangeCount": <n>, "rollbackStrategy": "<text>" } } }
5037
+
5038
+ Also write your full markdown plan to:
5039
+ ${scratchpad}/refactor-plan-${this.sessionId}.md
5040
+
5041
+ Emit each plan immediately. Do not wait until planning is complete.`;
4905
5042
  }
4906
5043
  buildCriticTask() {
4907
5044
  const scratchpad = this.director.sharedScratchpadPath ?? "/tmp";
5045
+ const bugHunterReportPath = `${scratchpad}/bug-hunter-report-${this.sessionId}.md`;
5046
+ const refactorPlanPath = `${scratchpad}/refactor-plan-${this.sessionId}.md`;
4908
5047
  const fileContents = this.snapshot.files.map((f) => `=== ${f.path} ===
4909
5048
  ${f.content}`).join("\n\n");
4910
- return `You are Critic. Evaluate bug findings and refactor plans as they arrive via fleet bus events.
5049
+ return `You are Critic. Evaluate bug findings and refactor plans.
4911
5050
 
4912
5051
  Target files:
4913
5052
  ${fileContents}
4914
5053
 
4915
- Subscribe to bug.found events (from BugHunter) and refactor.plan events (from RefactorPlanner). For each subject, write one JSON line per evaluation:
4916
- { "evaluation": { "id": "<uuid>", "subjectType": "<bug_finding|refactor_plan>", "subjectId": "<id>", "score": <0-10>, "verdict": "<approve|needs_revision|reject>", "strengths": [...], "weaknesses": [...], "concerns": [...] } }.
4917
- After all evaluations, write your markdown critic report to:
4918
- ${scratchpad}/critic-report-${this.sessionId}.md`;
5054
+ Read the BugHunter report at: ${bugHunterReportPath}
5055
+ Read the RefactorPlanner report at: ${refactorPlanPath}
5056
+
5057
+ For each bug and refactor plan, emit your evaluation using fleet_emit:
5058
+ { "type": "critic.evaluation", "payload": { "evaluation": { "id": "<uuid>", "subjectType": "<bug_finding|refactor_plan>", "subjectId": "<id>", "score": <0-10>, "verdict": "<approve|needs_revision|reject>", "strengths": ["<strength>"], "weaknesses": ["<weakness>"], "concerns": [{ "description": "<concern>", "severity": "<blocking|advisory>" }] } } }
5059
+
5060
+ After all evaluations, write your markdown report to:
5061
+ ${scratchpad}/critic-report-${this.sessionId}.md
5062
+
5063
+ Emit each evaluation immediately. Do not wait until you have read all reports.`;
4919
5064
  }
4920
5065
  wireFleetBus() {
5066
+ const dTool = this.fleetBus.filter("tool.executed", (e) => {
5067
+ this.progressBySubagent.set(e.subagentId, (this.progressBySubagent.get(e.subagentId) ?? 0) + 1);
5068
+ });
5069
+ this.disposers.push(dTool);
5070
+ const dBudget = this.fleetBus.filter("budget.threshold_reached", (e) => {
5071
+ const payload = e.payload;
5072
+ const role = this.roleFromSubagentId(e.subagentId);
5073
+ if (!role) return;
5074
+ const btwNotes = this.director.getLeaderBtwNotes();
5075
+ const alert = {
5076
+ sessionId: this.sessionId,
5077
+ subagentId: e.subagentId,
5078
+ role,
5079
+ level: "warning" /* WARNING */,
5080
+ message: `${role} hit ${payload.kind} soft limit (${payload.used}/${payload.limit})`,
5081
+ budgetKind: payload.kind,
5082
+ elapsedMs: payload.timeoutMs,
5083
+ limit: payload.limit,
5084
+ btwNotes
5085
+ };
5086
+ this.alerts.push(alert);
5087
+ this.fleetBus.emit({
5088
+ subagentId: e.subagentId,
5089
+ ts: Date.now(),
5090
+ type: "collab.warning",
5091
+ payload: alert
5092
+ });
5093
+ const decision = this.options.onBudgetWarning?.(alert) ?? "ignore";
5094
+ if (decision === "cancel") {
5095
+ this.cancel(`Director cancelled: ${role} ${payload.kind} threshold`);
5096
+ return;
5097
+ }
5098
+ if (payload.kind === "timeout") {
5099
+ const progress = this.progressBySubagent.get(e.subagentId) ?? 0;
5100
+ const lastProgress = this.lastTimeoutProgress.get(e.subagentId) ?? -1;
5101
+ if (progress <= lastProgress) {
5102
+ payload.deny();
5103
+ return;
5104
+ }
5105
+ this.lastTimeoutProgress.set(e.subagentId, progress);
5106
+ const newLimit = Math.min(Math.ceil((payload.timeoutMs ?? payload.limit) * 2), 24 * 60 * 6e4);
5107
+ setImmediate(() => {
5108
+ payload.extend({ timeoutMs: newLimit });
5109
+ });
5110
+ return;
5111
+ }
5112
+ if (decision === "extend") {
5113
+ setImmediate(() => {
5114
+ const base = Math.max(payload.limit, payload.used);
5115
+ const extra = {};
5116
+ switch (payload.kind) {
5117
+ case "iterations":
5118
+ extra.maxIterations = Math.min(Math.ceil(base * 1.5), 5e4);
5119
+ break;
5120
+ case "tool_calls":
5121
+ extra.maxToolCalls = Math.min(Math.ceil(base * 1.5), 1e5);
5122
+ break;
5123
+ case "tokens":
5124
+ extra.maxTokens = Math.min(Math.ceil(base * 1.5), 5e6);
5125
+ break;
5126
+ case "cost":
5127
+ extra.maxCostUsd = Math.min(base * 1.5, 100);
5128
+ break;
5129
+ }
5130
+ payload.extend(extra);
5131
+ });
5132
+ return;
5133
+ }
5134
+ if (payload.kind !== "timeout") {
5135
+ setImmediate(() => {
5136
+ const base = Math.max(payload.limit, payload.used);
5137
+ const extra = {};
5138
+ switch (payload.kind) {
5139
+ case "iterations":
5140
+ extra.maxIterations = Math.min(Math.ceil(base * 1.25), 5e4);
5141
+ break;
5142
+ case "tool_calls":
5143
+ extra.maxToolCalls = Math.min(Math.ceil(base * 1.25), 1e5);
5144
+ break;
5145
+ case "tokens":
5146
+ extra.maxTokens = Math.min(Math.ceil(base * 1.25), 5e6);
5147
+ break;
5148
+ case "cost":
5149
+ extra.maxCostUsd = Math.min(base * 1.25, 100);
5150
+ break;
5151
+ }
5152
+ payload.extend(extra);
5153
+ });
5154
+ }
5155
+ });
5156
+ this.disposers.push(dBudget);
5157
+ const dCancel = this.fleetBus.filter("director.cancel_collab", (e) => {
5158
+ const payload = e.payload;
5159
+ if (payload.sessionId !== this.sessionId) return;
5160
+ this.cancelled = true;
5161
+ if (this._timeoutTimer) {
5162
+ clearTimeout(this._timeoutTimer);
5163
+ this._timeoutTimer = void 0;
5164
+ }
5165
+ this.fleetBus.emit({
5166
+ subagentId: this.director.id,
5167
+ ts: Date.now(),
5168
+ type: "collab.cancelled",
5169
+ payload: { sessionId: this.sessionId, reason: payload.reason }
5170
+ });
5171
+ });
5172
+ this.disposers.push(dCancel);
4921
5173
  const d1 = this.fleetBus.filter("bug.found", (e) => {
4922
5174
  const payload = e.payload;
4923
5175
  if (payload?.finding) {
@@ -4943,10 +5195,19 @@ ${scratchpad}/critic-report-${this.sessionId}.md`;
4943
5195
  });
4944
5196
  this.disposers.push(d3);
4945
5197
  }
5198
+ roleFromSubagentId(subagentId) {
5199
+ for (const [role, id] of this.subagentIds) {
5200
+ if (id === subagentId) return role;
5201
+ }
5202
+ const match = subagentId.match(/^(bug-hunter|refactor-planner|critic)/);
5203
+ return match?.[1] ?? null;
5204
+ }
4946
5205
  assembleReport() {
4947
5206
  const bugList = Array.from(this.bugs.values());
4948
5207
  const planList = Array.from(this.plans.values());
4949
5208
  const evalList = Array.from(this.evaluations.values());
5209
+ let disposition = "completed";
5210
+ if (this.cancelled) disposition = "cancelled";
4950
5211
  const verdictOrder = {
4951
5212
  approve: 0,
4952
5213
  needs_revision: 1,
@@ -4960,33 +5221,41 @@ ${scratchpad}/critic-report-${this.sessionId}.md`;
4960
5221
  },
4961
5222
  "approve"
4962
5223
  );
4963
- const summary = this.buildMarkdownSummary(bugList, planList, evalList, overallVerdict);
5224
+ const summary = this.buildMarkdownSummary(bugList, planList, evalList, overallVerdict, disposition);
4964
5225
  return {
4965
5226
  sessionId: this.sessionId,
4966
5227
  startedAt: this.snapshot.createdAt,
4967
5228
  completedAt: (/* @__PURE__ */ new Date()).toISOString(),
4968
5229
  targetPaths: this.options.targetPaths,
5230
+ disposition,
4969
5231
  bugs: bugList,
4970
5232
  refactorPlans: planList,
4971
5233
  evaluations: evalList,
5234
+ alerts: [...this.alerts],
4972
5235
  overallVerdict,
4973
5236
  summary
4974
5237
  };
4975
5238
  }
4976
- buildMarkdownSummary(bugs, plans, evals, overallVerdict) {
5239
+ buildMarkdownSummary(bugs, plans, evals, overallVerdict, disposition) {
4977
5240
  const lines = [
4978
5241
  `## Collaborative Debugging Report \u2014 ${this.sessionId}`,
4979
5242
  "",
4980
5243
  `**Target:** ${this.options.targetPaths.join(", ")}`,
5244
+ `**Disposition:** ${disposition.toUpperCase()}`,
4981
5245
  `**Overall Verdict:** **${overallVerdict.toUpperCase()}**`,
4982
5246
  ""
4983
5247
  ];
5248
+ if (this.alerts.length > 0) {
5249
+ lines.push("### Alerts", "");
5250
+ for (const alert of this.alerts) {
5251
+ lines.push(`- **[${alert.level.toUpperCase()}]** ${alert.role}: ${alert.message}`);
5252
+ }
5253
+ lines.push("");
5254
+ }
4984
5255
  if (bugs.length > 0) {
4985
5256
  lines.push("### Bugs Found", "");
4986
5257
  for (const b of bugs) {
4987
- lines.push(
4988
- `- **[${b.severity.toUpperCase()}]** \`${b.location.file}:${b.location.line}\` \u2014 ${b.description}`
4989
- );
5258
+ lines.push(`- **[${b.severity.toUpperCase()}]** \`${b.location.file}:${b.location.line}\` \u2014 ${b.description}`);
4990
5259
  }
4991
5260
  lines.push("");
4992
5261
  }
@@ -5005,9 +5274,7 @@ ${scratchpad}/critic-report-${this.sessionId}.md`;
5005
5274
  for (const e of evals) {
5006
5275
  lines.push(`- [${e.subjectType}] score=${e.score}/10 \u2014 **${e.verdict.toUpperCase()}**`);
5007
5276
  for (const c of e.concerns) {
5008
- if (c.severity === "blocking") {
5009
- lines.push(` - ${c.description}`);
5010
- }
5277
+ if (c.severity === "blocking") lines.push(` - ${c.description}`);
5011
5278
  }
5012
5279
  }
5013
5280
  lines.push("");
@@ -5025,10 +5292,9 @@ var FleetSpawnBudgetError = class extends Error {
5025
5292
  kind;
5026
5293
  limit;
5027
5294
  observed;
5028
- constructor(kind, limit, observed) {
5029
- super(
5030
- kind === "max_spawns" ? `Director spawn budget exceeded: tried to spawn #${observed} but maxSpawns is ${limit}` : `Director spawn depth budget exceeded: this director is at depth ${observed} and maxSpawnDepth is ${limit}`
5031
- );
5295
+ constructor(kind, limit, observed, message) {
5296
+ const defaultMsg = kind === "max_spawns" ? `Director spawn budget exceeded: tried to spawn #${observed} but maxSpawns is ${limit}` : `Director spawn depth budget exceeded: this director is at depth ${observed} and maxSpawnDepth is ${limit}`;
5297
+ super(message ?? defaultMsg);
5032
5298
  this.name = "FleetSpawnBudgetError";
5033
5299
  this.kind = kind;
5034
5300
  this.limit = limit;
@@ -5049,6 +5315,20 @@ var FleetCostCapError = class extends Error {
5049
5315
  this.observed = observed;
5050
5316
  }
5051
5317
  };
5318
+ var FleetContextOverflowError = class extends Error {
5319
+ kind;
5320
+ limit;
5321
+ observed;
5322
+ constructor(limit, observed) {
5323
+ super(
5324
+ `Leader context overflow: leader has ${observed} tokens in flight (limit: ${limit}). Compact the leader context before spawning more subagents.`
5325
+ );
5326
+ this.name = "FleetContextOverflowError";
5327
+ this.kind = "max_context_load";
5328
+ this.limit = limit;
5329
+ this.observed = observed;
5330
+ }
5331
+ };
5052
5332
  var Director = class {
5053
5333
  /** Alias for the ICoordinator contract. `id` is retained for backward compatibility. */
5054
5334
  get coordinatorId() {
@@ -5065,6 +5345,25 @@ var Director = class {
5065
5345
  * injected; otherwise own FleetUsageAggregator.
5066
5346
  */
5067
5347
  usage;
5348
+ /**
5349
+ * Update the leader agent's current context pressure (full request tokens:
5350
+ * messages + systemPrompt + toolDefs). The director checks this before every
5351
+ * spawn — if the pressure exceeds `maxLeaderContextLoad * maxContext`,
5352
+ * spawning is refused with a `FleetContextOverflowError`.
5353
+ *
5354
+ * Call this after each leader agent iteration to keep the pressure current.
5355
+ * The compactor's `CompactReport.fullRequestTokensAfter` is a natural source.
5356
+ */
5357
+ setLeaderContextPressure(tokens) {
5358
+ this.leaderContextPressure = tokens;
5359
+ this.fleetManager?.setLeaderContextPressure(tokens);
5360
+ }
5361
+ /**
5362
+ * Read the leader agent's current context pressure.
5363
+ */
5364
+ getLeaderContextPressure() {
5365
+ return this.leaderContextPressure;
5366
+ }
5068
5367
  /**
5069
5368
  * Optional fleet-level policy container. When provided the Director
5070
5369
  * delegates spawn budgeting, manifest entries, and checkpointing to it
@@ -5150,6 +5449,23 @@ var Director = class {
5150
5449
  taskCompletedListener = null;
5151
5450
  /** Optional LLM classifier for smart dispatch. Passed from options. */
5152
5451
  dispatchClassifier;
5452
+ /** Leader agent's current context pressure (full request tokens). */
5453
+ leaderContextPressure = 0;
5454
+ /** Maximum context load fraction before spawn is refused. */
5455
+ maxLeaderContextLoad;
5456
+ /** Provider's max context window in tokens. */
5457
+ maxContext;
5458
+ /**
5459
+ * When set by `workComplete()`, the director stops dispatching new tasks
5460
+ * and terminates all running subagents. Used when the director's LLM decides
5461
+ * the goal is satisfied and no further spawns are needed — prevents the
5462
+ * coordinator from keeping workers alive for tasks that will never arrive.
5463
+ */
5464
+ workCompleteFlag = false;
5465
+ /** Pending /btw notes stashed by the leader agent (see setLeaderBtwNote). */
5466
+ _leaderBtwNotes = [];
5467
+ /** Active collab sessions tracked by sessionId (see spawnCollab). */
5468
+ _activeCollabSessions = /* @__PURE__ */ new Map();
5153
5469
  constructor(opts) {
5154
5470
  this.id = opts.config.coordinatorId || randomUUID();
5155
5471
  this.manifestPath = opts.manifestPath;
@@ -5165,6 +5481,8 @@ var Director = class {
5165
5481
  this.dispatchClassifier = opts.dispatchClassifier;
5166
5482
  this.maxFleetCostUsd = opts.directorBudget?.maxCostUsd ?? Number.POSITIVE_INFINITY;
5167
5483
  this.maxBudgetExtensions = opts.maxBudgetExtensions ?? 5;
5484
+ this.maxLeaderContextLoad = opts.maxLeaderContextLoad ?? 0.85;
5485
+ this.maxContext = opts.maxContext ?? 128e3;
5168
5486
  this.sessionsRoot = opts.sessionsRoot;
5169
5487
  this.directorRunId = opts.directorRunId ?? this.id;
5170
5488
  this.stateCheckpoint = opts.stateCheckpointPath ? new DirectorStateCheckpoint(opts.stateCheckpointPath, {
@@ -5192,7 +5510,7 @@ var Director = class {
5192
5510
  this.fleet = new FleetBus();
5193
5511
  this.usage = new FleetUsageAggregator(
5194
5512
  this.fleet,
5195
- (id, provider, model) => {
5513
+ (_id, provider, model) => {
5196
5514
  if (provider && model) return this.priceLookups.get(`${provider}/${model}`);
5197
5515
  return void 0;
5198
5516
  },
@@ -5254,6 +5572,9 @@ var Director = class {
5254
5572
  });
5255
5573
  this.fleet.filter("budget.threshold_reached", (e) => {
5256
5574
  const payload = e.payload;
5575
+ if (e.subagentId.startsWith("bug-hunter-") || e.subagentId.startsWith("refactor-planner-") || e.subagentId.startsWith("critic-")) {
5576
+ return;
5577
+ }
5257
5578
  if (payload.kind === "timeout") {
5258
5579
  const progress = progressBySubagent.get(e.subagentId) ?? 0;
5259
5580
  const lastProgress = lastTimeoutProgress.get(e.subagentId) ?? -1;
@@ -5332,6 +5653,107 @@ var Director = class {
5332
5653
  extensionsFor(subagentId) {
5333
5654
  return this.extendTotals.get(subagentId) ?? 0;
5334
5655
  }
5656
+ /**
5657
+ * Signal that the director's work is done. Once called:
5658
+ * - `spawn()` throws `FleetSpawnBudgetError('max_spawns', …)` — no new
5659
+ * subagents can be created
5660
+ * - Running subagents are NOT forcibly stopped — they finish naturally,
5661
+ * but no new tasks are dispatched to them
5662
+ *
5663
+ * This lets the director LLM say "I'm satisfied with the results, stop
5664
+ * spawning and wind down" — without killing in-flight work mid-execution.
5665
+ * Call `terminateAll()` separately if you need immediate teardown.
5666
+ *
5667
+ * Idempotent — calling twice is a no-op.
5668
+ */
5669
+ workComplete() {
5670
+ this.workCompleteFlag = true;
5671
+ this.fleet.emit({ subagentId: this.id, ts: Date.now(), type: "director.work_complete", payload: {} });
5672
+ }
5673
+ /** Returns true if `workComplete()` has been called on this director. */
5674
+ isWorkComplete() {
5675
+ return this.workCompleteFlag;
5676
+ }
5677
+ /**
5678
+ * Stashes a /btw note on the leader agent's context. The leader's agent loop
5679
+ * calls `consumeBtwNotes()` at each iteration boundary and folds pending notes
5680
+ * into the conversation as a visible block — no abort, no restart, just a
5681
+ * "by the way" nudge the model picks up on its next turn.
5682
+ *
5683
+ * This is the entry point for the host (CLI, TUI) to inject /btw notes
5684
+ * programmatically without going through the slash-command path.
5685
+ */
5686
+ setLeaderBtwNote(note) {
5687
+ const trimmed = note.trim();
5688
+ if (!trimmed) return this._leaderBtwNotes.length;
5689
+ this._leaderBtwNotes = [...this._leaderBtwNotes, trimmed].slice(-20);
5690
+ return this._leaderBtwNotes.length;
5691
+ }
5692
+ /**
5693
+ * Read and clear all pending /btw notes the leader has stashed.
5694
+ * Returns them in FIFO order (empty array when none).
5695
+ *
5696
+ * Called by CollabSession when a budget threshold event fires so the
5697
+ * Director can inspect accumulated /btw notes before deciding whether
5698
+ * to cancel the collab session or let it continue.
5699
+ */
5700
+ getLeaderBtwNotes() {
5701
+ const notes = this._leaderBtwNotes;
5702
+ this._leaderBtwNotes = [];
5703
+ return notes;
5704
+ }
5705
+ /**
5706
+ * Peek at pending /btw notes without consuming them.
5707
+ * Useful for UI to show "N pending notes" without clearing them.
5708
+ */
5709
+ peekLeaderBtwNotes() {
5710
+ return [...this._leaderBtwNotes];
5711
+ }
5712
+ /**
5713
+ * Drain (read + clear) all /btw notes in one call.
5714
+ * Alias for getLeaderBtwNotes() — kept for symmetry with consumeBtwNotes()
5715
+ * in the agent's btw.ts. The Director calls this at the point where it
5716
+ * makes a cancellation decision, not on every budget event.
5717
+ */
5718
+ drainLeaderBtwNotes() {
5719
+ return this.getLeaderBtwNotes();
5720
+ }
5721
+ /**
5722
+ * Cancel an active collab session by its id.
5723
+ * Emits `director.cancel_collab` on the FleetBus so the session's agents
5724
+ * finish early with a 'cancelled' disposition.
5725
+ *
5726
+ * Returns silently if the session id is not tracked or already settled.
5727
+ * The CollabDebugReport will reflect 'cancelled' disposition when awaited.
5728
+ */
5729
+ cancelCollabSession(sessionId, reason = "Director cancelled") {
5730
+ const session = this._activeCollabSessions.get(sessionId);
5731
+ if (!session || session.isCancelled()) return;
5732
+ session.cancel(reason);
5733
+ for (const [_role, subagentId] of session.getSubagentIds()) {
5734
+ this.coordinator.stop(subagentId).catch(() => {
5735
+ });
5736
+ }
5737
+ }
5738
+ /**
5739
+ * Subscribe a callback to be notified whenever a collab session raises
5740
+ * an alert (warning level). The callback receives the full DirectorAlert
5741
+ * payload so the host (CLI, TUI) can display it to the user.
5742
+ * Returns an unsubscribe function.
5743
+ */
5744
+ onCollabAlert(handler) {
5745
+ return this.fleet.filter("collab.warning", (e) => {
5746
+ handler(e.payload);
5747
+ });
5748
+ }
5749
+ /**
5750
+ * Returns all active (not yet settled) collab session ids.
5751
+ * Useful for the TUI to render a "N active sessions" badge and for
5752
+ * the host to know what can be cancelled.
5753
+ */
5754
+ activeCollabSessions() {
5755
+ return Array.from(this._activeCollabSessions.keys());
5756
+ }
5335
5757
  /** Best-effort session-writer append. Swallows failures — the director
5336
5758
  * must not break a fleet run because the session JSONL handle closed. */
5337
5759
  async appendSessionEvent(event) {
@@ -5370,12 +5792,21 @@ var Director = class {
5370
5792
  * it the `cost` column in `usage.snapshot()` stays at 0.
5371
5793
  */
5372
5794
  async spawn(config, priceLookup) {
5795
+ if (this.workCompleteFlag) {
5796
+ throw new FleetSpawnBudgetError(
5797
+ "max_spawns",
5798
+ this.maxSpawns,
5799
+ this.spawnCount + 1,
5800
+ "workComplete() has been called \u2014 director closed further spawning"
5801
+ );
5802
+ }
5373
5803
  if (this.fleetManager) {
5374
5804
  const rejection = this.fleetManager.canSpawn(config);
5375
5805
  if (rejection) {
5376
5806
  if (rejection.kind === "max_spawn_depth") throw new FleetSpawnBudgetError("max_spawn_depth", rejection.limit, rejection.observed);
5377
5807
  if (rejection.kind === "max_spawns") throw new FleetSpawnBudgetError("max_spawns", rejection.limit, rejection.observed);
5378
5808
  if (rejection.kind === "max_cost_usd") throw new FleetCostCapError(rejection.limit, rejection.observed);
5809
+ if (rejection.kind === "max_context_load") throw new FleetContextOverflowError(rejection.limit, rejection.observed);
5379
5810
  }
5380
5811
  } else {
5381
5812
  if (this.spawnDepth >= this.maxSpawnDepth) {
@@ -5390,9 +5821,15 @@ var Director = class {
5390
5821
  throw new FleetCostCapError(this.maxFleetCostUsd, totalCost);
5391
5822
  }
5392
5823
  }
5824
+ if (this.maxLeaderContextLoad < 1) {
5825
+ const threshold = this.maxContext * this.maxLeaderContextLoad;
5826
+ if (this.leaderContextPressure >= threshold) {
5827
+ throw new FleetContextOverflowError(threshold, this.leaderContextPressure);
5828
+ }
5829
+ }
5393
5830
  }
5394
5831
  let result;
5395
- const needsNickname = config.name === config.role || !config.name || config.name === "subagent";
5832
+ const needsNickname = config.name === config.role || !config.name || config.name === "subagent" || config.name === "adhoc";
5396
5833
  if (needsNickname) {
5397
5834
  const role = config.role ?? "subagent";
5398
5835
  if (this.fleetManager) {
@@ -5617,6 +6054,24 @@ var Director = class {
5617
6054
  */
5618
6055
  async assign(task) {
5619
6056
  const taskWithId = task.id ? task : { ...task, id: randomUUID() };
6057
+ if (this.workCompleteFlag) {
6058
+ const synthetic = {
6059
+ subagentId: taskWithId.subagentId ?? "unassigned",
6060
+ taskId: taskWithId.id,
6061
+ status: "stopped",
6062
+ error: { kind: "aborted_by_parent", message: "Director called workComplete() \u2014 no further tasks will run", retryable: false },
6063
+ iterations: 0,
6064
+ toolCalls: 0,
6065
+ durationMs: 0
6066
+ };
6067
+ this.completed.set(taskWithId.id, synthetic);
6068
+ const waiter = this.taskWaiters.get(taskWithId.id);
6069
+ if (waiter) {
6070
+ waiter.resolve(synthetic);
6071
+ this.taskWaiters.delete(taskWithId.id);
6072
+ }
6073
+ return taskWithId.id;
6074
+ }
5620
6075
  if (task.subagentId) {
5621
6076
  if (this.fleetManager) {
5622
6077
  this.fleetManager.addTaskToSubagent(task.subagentId, taskWithId.id);
@@ -5839,12 +6294,14 @@ var Director = class {
5839
6294
  makeAskTool(this),
5840
6295
  makeRollUpTool(this),
5841
6296
  makeTerminateTool(this),
6297
+ makeTerminateAllTool(this),
5842
6298
  makeFleetStatusTool(this),
5843
6299
  makeFleetUsageTool(this),
5844
6300
  makeFleetSessionTool(this),
5845
6301
  makeFleetHealthTool(this),
5846
6302
  makeCollabDebugTool(this),
5847
- makeFleetEmitTool(this)
6303
+ makeFleetEmitTool(this),
6304
+ makeWorkCompleteTool(this)
5848
6305
  ];
5849
6306
  return t;
5850
6307
  }
@@ -5864,7 +6321,15 @@ var Director = class {
5864
6321
  * three agents complete or the session times out.
5865
6322
  */
5866
6323
  async spawnCollab(options) {
5867
- const session = new CollabSession(this, this.fleet, options);
6324
+ const session = new CollabSession(this, this.fleet, {
6325
+ ...options,
6326
+ onBudgetWarning: (alert) => {
6327
+ return options.onBudgetWarning?.(alert) ?? "ignore";
6328
+ }
6329
+ });
6330
+ this._activeCollabSessions.set(session.sessionId, session);
6331
+ session.on("session.done", () => this._activeCollabSessions.delete(session.sessionId));
6332
+ session.on("session.error", () => this._activeCollabSessions.delete(session.sessionId));
5868
6333
  return session.start();
5869
6334
  }
5870
6335
  /**
@@ -6777,7 +7242,6 @@ var FileSessionWriter = class {
6777
7242
  }
6778
7243
  return event;
6779
7244
  }
6780
- promptIndex = 0;
6781
7245
  pendingFileSnapshots = [];
6782
7246
  /** Tracks open tool_use IDs during the current run to serialize on close for resume. */
6783
7247
  openToolUses = /* @__PURE__ */ new Set();
@@ -6868,7 +7332,6 @@ var FileSessionWriter = class {
6868
7332
  await this.writeFileSnapshot(promptIndex, [...this.pendingFileSnapshots]);
6869
7333
  this.pendingFileSnapshots = [];
6870
7334
  }
6871
- this.promptIndex = promptIndex + 1;
6872
7335
  await this.append({
6873
7336
  type: "checkpoint",
6874
7337
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -6964,6 +7427,38 @@ var FileSessionWriter = class {
6964
7427
  `;
6965
7428
  await fsp5.writeFile(this.filePath, record, "utf8");
6966
7429
  }
7430
+ /**
7431
+ * Idea #1 — write an in-flight marker. The agent loop should call
7432
+ * this at the start of each long-running operation; a matching
7433
+ * `clearInFlightMarker` follows on clean exit. A stale marker
7434
+ * (no end) is what `SessionRecovery.detectStale` looks for.
7435
+ */
7436
+ async writeInFlightMarker(context) {
7437
+ if (!context || context.length > 500) {
7438
+ throw new Error("In-flight context must be 1..500 chars");
7439
+ }
7440
+ await this.append({
7441
+ type: "in_flight_start",
7442
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
7443
+ context
7444
+ });
7445
+ this.events?.emit("in_flight.started", { context, ts: (/* @__PURE__ */ new Date()).toISOString() });
7446
+ }
7447
+ /**
7448
+ * Idea #1 — close the in-flight marker. Idempotent in spirit
7449
+ * (you can call it after a successful iteration even if you
7450
+ * didn't open one this round) — but the session log records
7451
+ * every call so postmortem tooling can see "the agent finished
7452
+ * cleanly X times, then died without finishing Y".
7453
+ */
7454
+ async clearInFlightMarker(reason) {
7455
+ await this.append({
7456
+ type: "in_flight_end",
7457
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
7458
+ reason
7459
+ });
7460
+ this.events?.emit("in_flight.ended", { reason, ts: (/* @__PURE__ */ new Date()).toISOString() });
7461
+ }
6967
7462
  };
6968
7463
  function userInputTitle(content) {
6969
7464
  const text = typeof content === "string" ? content : content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
@@ -7064,7 +7559,6 @@ var FleetManager = class {
7064
7559
  /** Usage rollup across all subagents. */
7065
7560
  usage;
7066
7561
  manifestPath;
7067
- sessionsRoot;
7068
7562
  directorRunId;
7069
7563
  /** Spawn cap (lifetime total). Infinity means unlimited. */
7070
7564
  maxSpawns;
@@ -7092,9 +7586,14 @@ var FleetManager = class {
7092
7586
  _usedNicknames = /* @__PURE__ */ new Set();
7093
7587
  /** The coordinator (wired via setCoordinator by Director after construction). */
7094
7588
  coordinator = null;
7589
+ /** Leader agent's current context pressure (full request tokens). */
7590
+ leaderContextPressure = 0;
7591
+ /** Maximum context load fraction before spawn is refused. */
7592
+ maxLeaderContextLoad;
7593
+ /** Provider's max context window in tokens. */
7594
+ maxContext;
7095
7595
  constructor(opts = {}) {
7096
7596
  this.manifestPath = opts.manifestPath;
7097
- this.sessionsRoot = opts.sessionsRoot;
7098
7597
  this.directorRunId = opts.directorRunId ?? randomUUID();
7099
7598
  this.maxSpawns = opts.maxSpawns ?? Number.POSITIVE_INFINITY;
7100
7599
  this.maxSpawnDepth = opts.maxSpawnDepth ?? 2;
@@ -7102,6 +7601,8 @@ var FleetManager = class {
7102
7601
  this.sessionWriter = opts.sessionWriter ?? null;
7103
7602
  this.manifestDebounceMs = opts.manifestDebounceMs ?? 2e3;
7104
7603
  this.maxFleetCostUsd = opts.directorBudget?.maxCostUsd ?? Number.POSITIVE_INFINITY;
7604
+ this.maxLeaderContextLoad = opts.maxLeaderContextLoad ?? 0.85;
7605
+ this.maxContext = opts.maxContext ?? 128e3;
7105
7606
  this.stateCheckpoint = opts.stateCheckpointPath ? new DirectorStateCheckpoint(
7106
7607
  opts.stateCheckpointPath,
7107
7608
  {
@@ -7116,7 +7617,7 @@ var FleetManager = class {
7116
7617
  this.fleet = new FleetBus();
7117
7618
  this.usage = new FleetUsageAggregator(
7118
7619
  this.fleet,
7119
- (id, provider, model) => {
7620
+ (_id, provider, model) => {
7120
7621
  if (provider && model) return this.priceLookups.get(`${provider}/${model}`);
7121
7622
  return void 0;
7122
7623
  },
@@ -7155,7 +7656,7 @@ var FleetManager = class {
7155
7656
  * which cap was exceeded. Does NOT throw — the caller decides
7156
7657
  * how to surface the rejection.
7157
7658
  */
7158
- canSpawn(config) {
7659
+ canSpawn(_config) {
7159
7660
  if (this.spawnDepth >= this.maxSpawnDepth) {
7160
7661
  return { kind: "max_spawn_depth", limit: this.maxSpawnDepth, observed: this.spawnDepth };
7161
7662
  }
@@ -7168,8 +7669,21 @@ var FleetManager = class {
7168
7669
  return { kind: "max_cost_usd", limit: this.maxFleetCostUsd, observed: totalCost };
7169
7670
  }
7170
7671
  }
7672
+ if (this.maxLeaderContextLoad < 1) {
7673
+ const threshold = this.maxContext * this.maxLeaderContextLoad;
7674
+ if (this.leaderContextPressure >= threshold) {
7675
+ return {
7676
+ kind: "max_context_load",
7677
+ limit: threshold,
7678
+ observed: this.leaderContextPressure
7679
+ };
7680
+ }
7681
+ }
7171
7682
  return null;
7172
7683
  }
7684
+ setLeaderContextPressure(tokens) {
7685
+ this.leaderContextPressure = tokens;
7686
+ }
7173
7687
  /**
7174
7688
  * Assign a memorable nickname (e.g. "Einstein (Bug Hunter)") to the config,
7175
7689
  * record it so the same name is never reused, then record the spawn.
@@ -7364,6 +7878,6 @@ var FleetManager = class {
7364
7878
  }
7365
7879
  };
7366
7880
 
7367
- export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, BUG_HUNTER_AGENT, BUILD_AGENTS, BudgetExceededError, BudgetThresholdSignal, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultMultiAgentCoordinator, Director, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, HEAVY_BUDGET, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, LIGHT_BUDGET, MEDIUM_BUDGET, META_AGENTS, NULL_FLEET_BUS, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, VERIFY_AGENTS, applyRosterBudget, attachAutoExtend, composeDirectorPrompt, composeSubagentPrompt, createDelegateTool, createMessage, dispatchAgent, getAgentDefinition, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, rosterSummaryFromConfigs, scoreAgents };
7881
+ export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, TOOLS as AGENT_TOOL_PRESETS, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, BUG_HUNTER_AGENT, BUILD_AGENTS, BudgetExceededError, BudgetThresholdSignal, CollabSession, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_SUBAGENT_BASELINE, DELIVERY_AGENTS, DISCOVERY_AGENTS, DOMAIN_AGENTS, DefaultMultiAgentCoordinator, Director, DirectorAlertLevel, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, HEAVY_BUDGET, InMemoryAgentBridge, InMemoryBridgeTransport, KNOWLEDGE_AGENTS, LIGHT_BUDGET, MEDIUM_BUDGET, META_AGENTS, NULL_FLEET_BUS, PLANNING_AGENTS, REFACTOR_PLANNER_AGENT, REVIEW_AGENTS, SECURITY_SCANNER_AGENT, SubagentBudget, VERIFY_AGENTS, applyRosterBudget, attachAutoExtend, composeDirectorPrompt, composeSubagentPrompt, createDelegateTool, createMessage, dispatchAgent, getAgentDefinition, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAwaitTasksTool, makeCollabDebugTool, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeRollUpTool, makeSpawnTool, makeTerminateTool, makeWorkCompleteTool, rosterSummaryFromConfigs, scoreAgents };
7368
7882
  //# sourceMappingURL=index.js.map
7369
7883
  //# sourceMappingURL=index.js.map