@wrongstack/core 0.6.4 → 0.6.6

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 (66) hide show
  1. package/dist/{agent-bridge-eb7qnNrd.d.ts → agent-bridge-BBXK_ppx.d.ts} +1 -1
  2. package/dist/agent-subagent-runner-DsSm9lKN.d.ts +174 -0
  3. package/dist/{compactor-RIPuTtWK.d.ts → compactor-C8NhpSt5.d.ts} +1 -1
  4. package/dist/{config-BGGuP_Ar.d.ts → config-DfC6g6KV.d.ts} +1 -1
  5. package/dist/{context-CDRyrkKQ.d.ts → context-DN5v-uQX.d.ts} +11 -0
  6. package/dist/coordination/index.d.ts +10 -9
  7. package/dist/coordination/index.js +113 -20
  8. package/dist/coordination/index.js.map +1 -1
  9. package/dist/defaults/index.d.ts +22 -21
  10. package/dist/defaults/index.js +1359 -919
  11. package/dist/defaults/index.js.map +1 -1
  12. package/dist/{events-BHuIHekD.d.ts → events-CJqwQl8G.d.ts} +17 -1
  13. package/dist/execution/index.d.ts +116 -13
  14. package/dist/execution/index.js +1438 -131
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +6 -6
  17. package/dist/{goal-store-DVCfj7Ff.d.ts → goal-store-HHgaq5ue.d.ts} +3 -3
  18. package/dist/{index-CPcDqvZh.d.ts → index-CXnWsGBp.d.ts} +11 -175
  19. package/dist/{index-BOn9NK7D.d.ts → index-DcnXDPdY.d.ts} +6 -6
  20. package/dist/index.d.ts +29 -28
  21. package/dist/index.js +1105 -666
  22. package/dist/index.js.map +1 -1
  23. package/dist/infrastructure/index.d.ts +6 -6
  24. package/dist/kernel/index.d.ts +9 -9
  25. package/dist/kernel/index.js.map +1 -1
  26. package/dist/{mcp-servers-DBdh3cee.d.ts → mcp-servers-CevFHHM1.d.ts} +3 -3
  27. package/dist/models/index.d.ts +2 -2
  28. package/dist/models/index.js +5 -16
  29. package/dist/models/index.js.map +1 -1
  30. package/dist/{multi-agent-CxSb-9dQ.d.ts → multi-agent-D5IbASk_.d.ts} +16 -4
  31. package/dist/observability/index.d.ts +2 -2
  32. package/dist/{path-resolver-CMGNadvq.d.ts → path-resolver-CBx_q1HA.d.ts} +2 -2
  33. package/dist/{plan-templates-BJflQY2i.d.ts → plan-templates-BEOllUJV.d.ts} +5 -4
  34. package/dist/{provider-runner-BFgNXpaP.d.ts → provider-runner-Byh5TcJs.d.ts} +3 -3
  35. package/dist/{retry-policy-LKS8MHsB.d.ts → retry-policy-BZSIMxrJ.d.ts} +1 -1
  36. package/dist/sdd/index.d.ts +9 -4
  37. package/dist/sdd/index.js +21 -0
  38. package/dist/sdd/index.js.map +1 -1
  39. package/dist/{secret-scrubber-CfMdAJ_l.d.ts → secret-scrubber-CT7wefiO.d.ts} +1 -1
  40. package/dist/{secret-scrubber-BzQR5BiL.d.ts → secret-scrubber-I0QHY_ob.d.ts} +1 -1
  41. package/dist/security/index.d.ts +3 -3
  42. package/dist/{selector-C7HqnZJU.d.ts → selector-DDb_mq9X.d.ts} +1 -1
  43. package/dist/{session-reader-CzfRA6Vk.d.ts → session-reader-B9nVkziM.d.ts} +1 -1
  44. package/dist/storage/index.d.ts +6 -6
  45. package/dist/storage/index.js +29 -3
  46. package/dist/storage/index.js.map +1 -1
  47. package/dist/{system-prompt-Dl2QY1_B.d.ts → system-prompt-gL06H9P4.d.ts} +1 -1
  48. package/dist/{task-graph-BITvWt4t.d.ts → task-graph-D1YQbpxF.d.ts} +1 -0
  49. package/dist/{tool-executor-FoxBjULX.d.ts → tool-executor-BF7QfYVE.d.ts} +4 -4
  50. package/dist/types/index.d.ts +16 -16
  51. package/dist/types/index.js +5 -16
  52. package/dist/types/index.js.map +1 -1
  53. package/dist/utils/index.d.ts +1 -1
  54. package/package.json +1 -1
  55. package/skills/audit-log/SKILL.md +57 -28
  56. package/skills/bug-hunter/SKILL.md +85 -61
  57. package/skills/git-flow/SKILL.md +73 -18
  58. package/skills/multi-agent/SKILL.md +69 -40
  59. package/skills/node-modern/SKILL.md +111 -19
  60. package/skills/prompt-engineering/SKILL.md +97 -16
  61. package/skills/react-modern/SKILL.md +104 -18
  62. package/skills/refactor-planner/SKILL.md +73 -43
  63. package/skills/sdd/SKILL.md +123 -165
  64. package/skills/security-scanner/SKILL.md +95 -93
  65. package/skills/skill-creator/SKILL.md +58 -25
  66. package/skills/typescript-strict/SKILL.md +107 -15
@@ -436,6 +436,20 @@ var DefaultSessionStore = class {
436
436
  await fsp.unlink(path3.join(this.dir, `${id}.jsonl`));
437
437
  await fsp.unlink(path3.join(this.dir, `${id}.summary.json`)).catch(() => void 0);
438
438
  }
439
+ async clearHistory(id) {
440
+ const file = path3.join(this.dir, `${id}.jsonl`);
441
+ const meta = path3.join(this.dir, `${id}.summary.json`);
442
+ const record = `${JSON.stringify({
443
+ type: "session_start",
444
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
445
+ id,
446
+ model: "unknown",
447
+ provider: "unknown"
448
+ })}
449
+ `;
450
+ await fsp.writeFile(file, record, "utf8");
451
+ await fsp.unlink(meta).catch(() => void 0);
452
+ }
439
453
  async summarize(id, mtime) {
440
454
  try {
441
455
  const data = await this.load(id);
@@ -741,10 +755,21 @@ var FileSessionWriter = class {
741
755
  });
742
756
  return removedCount;
743
757
  }
758
+ async clearSession() {
759
+ if (!this.filePath) return;
760
+ const record = `${JSON.stringify({
761
+ type: "session_start",
762
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
763
+ id: this.id,
764
+ model: this.meta.model ?? "unknown",
765
+ provider: this.meta.provider ?? "unknown"
766
+ })}
767
+ `;
768
+ await fsp.writeFile(this.filePath, record, "utf8");
769
+ }
744
770
  };
745
771
  function userInputTitle(content) {
746
- if (typeof content === "string") return content.slice(0, 60);
747
- const text = content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
772
+ const text = typeof content === "string" ? content : content.filter((b) => b.type === "text").map((b) => b.text).join(" ");
748
773
  return (text || "(non-text input)").slice(0, 60);
749
774
  }
750
775
 
@@ -5424,23 +5449,33 @@ var EternalAutonomyEngine = class {
5424
5449
  * `agent.run()` avoids race conditions on the shared Context.
5425
5450
  */
5426
5451
  async runOneIteration() {
5452
+ const emit = (stage) => {
5453
+ this.opts.onStage?.(stage);
5454
+ };
5427
5455
  const goal = await loadGoal(this.goalPath);
5428
5456
  if (!goal) {
5457
+ emit({ phase: "stopped" });
5429
5458
  this.stopRequested = true;
5430
5459
  return false;
5431
5460
  }
5432
5461
  const missionState = goal.goalState ?? "active";
5433
5462
  if (missionState !== "active") {
5463
+ emit({ phase: missionState === "paused" ? "paused" : "stopped" });
5434
5464
  this.stopRequested = true;
5435
5465
  return false;
5436
5466
  }
5467
+ emit({ phase: "decide", reason: "picking next task" });
5437
5468
  const action = await this.decide(goal);
5438
5469
  if (!action) {
5439
5470
  if (!this.stopRequested) {
5471
+ emit({ phase: "sleep", ms: 5e3 });
5440
5472
  await sleep(5e3);
5473
+ } else {
5474
+ emit({ phase: "stopped" });
5441
5475
  }
5442
5476
  return false;
5443
5477
  }
5478
+ emit({ phase: "execute", task: action.task });
5444
5479
  const ctrl = new AbortController();
5445
5480
  this.currentCtrl = ctrl;
5446
5481
  const timer = setTimeout(
@@ -5518,6 +5553,7 @@ var EternalAutonomyEngine = class {
5518
5553
  tokens,
5519
5554
  costUsd
5520
5555
  });
5556
+ emit({ phase: "reflect", status, note });
5521
5557
  let iterationIndex = 0;
5522
5558
  try {
5523
5559
  const reloaded = await loadGoal(this.goalPath);
@@ -5539,6 +5575,7 @@ var EternalAutonomyEngine = class {
5539
5575
  this.consecutiveTransientRetries++;
5540
5576
  const delay = this.computeTransientBackoffMs();
5541
5577
  if (delay > 0) {
5578
+ emit({ phase: "sleep", ms: delay });
5542
5579
  await this.sleepInterruptible(delay);
5543
5580
  }
5544
5581
  return false;
@@ -5552,6 +5589,9 @@ var EternalAutonomyEngine = class {
5552
5589
  return false;
5553
5590
  }
5554
5591
  this.consecutiveTransientRetries = 0;
5592
+ const cycleGapMs = this.opts.cycleGapMs ?? 1e3;
5593
+ emit({ phase: "sleep", ms: cycleGapMs });
5594
+ await sleep(cycleGapMs);
5555
5595
  if (GOAL_COMPLETE_MARKER.test(finalText)) {
5556
5596
  await this.markGoalCompleted(action, finalText);
5557
5597
  this.stopRequested = true;
@@ -5867,649 +5907,113 @@ function sleep(ms) {
5867
5907
  return new Promise((resolve2) => setTimeout(resolve2, ms));
5868
5908
  }
5869
5909
 
5870
- // src/execution/autonomy-prompt-contributor.ts
5871
- function makeAutonomyPromptContributor(opts) {
5872
- return async (ctx) => {
5873
- if (ctx.subagent) return [];
5874
- if (!opts.enabled()) return [];
5875
- let goal;
5876
- try {
5877
- goal = await loadGoal(opts.goalPath);
5878
- } catch {
5879
- return [];
5880
- }
5881
- if (!goal) return [];
5882
- const missionState = goal.goalState ?? "active";
5883
- if (missionState !== "active") return [];
5884
- const tailSize = opts.journalTailSize ?? 5;
5885
- const journalTail = goal.journal.slice(-tailSize).map((e) => {
5886
- const note = e.note ? ` \u2014 ${e.note.slice(0, 80)}` : "";
5887
- return ` #${e.iteration} [${e.status}] ${e.task}${note}`;
5888
- });
5889
- const text = [
5890
- "## ETERNAL AUTONOMY \u2014 active mission",
5891
- "",
5892
- "You are inside a long-running autonomous loop. The user is asleep",
5893
- "and is not available to confirm decisions. Each turn you receive a",
5894
- "directive describing one concrete sub-task that advances the mission.",
5895
- "",
5896
- `Mission: ${goal.goal}`,
5897
- `Iteration: #${goal.iterations}`,
5898
- journalTail.length > 0 ? `Recent journal (last ${journalTail.length}):
5899
- ${journalTail.join("\n")}` : "Recent journal: (none \u2014 this is the first iteration)",
5900
- "",
5901
- "### Loop control markers",
5902
- "Emit these on their own line in your final text \u2014 case-insensitive,",
5903
- "whitespace-tolerant, but they must occupy the entire line:",
5904
- "- `[continue]` \u2014 chain to the next internal step without returning.",
5905
- "- `[done]` \u2014 the current sub-task is finished; return to the engine.",
5906
- "- `[GOAL_COMPLETE]` \u2014 emit ONLY when the OVERALL mission is",
5907
- " verifiably done. Must be followed by a one-paragraph verification",
5908
- " recipe (artifact path, test command, or 10-second reproduction).",
5909
- " The engine halts on this marker \u2014 false positives waste real",
5910
- " human time. If unsure, emit `[done]` and let the next iteration",
5911
- " decide.",
5912
- "",
5913
- "### Operating principles",
5914
- "- YOLO is active. Do NOT ask for confirmation, do NOT propose",
5915
- " options. Pick the best path and execute it.",
5916
- "- Use tools freely; multiple calls per turn are normal and expected.",
5917
- "- When working on a todo, mark it `in_progress` via the todos tool",
5918
- " before tool work and `completed` (or `cancelled` with a reason)",
5919
- " when done. The loop reads todo state between iterations.",
5920
- "- If an approach fails twice in a row, pivot. Don't grind on the",
5921
- " same wall \u2014 try a different angle, file a cancel on the todo, or",
5922
- " surface the obstacle via `[done]` and let the next iteration",
5923
- " re-plan."
5924
- ].join("\n");
5925
- return [
5926
- {
5927
- type: "text",
5928
- text,
5929
- cache_control: { type: "ephemeral" }
5930
- }
5931
- ];
5932
- };
5933
- }
5934
-
5935
- // src/execution/goal-preamble.ts
5936
- function buildGoalPreamble(goal) {
5937
- return [
5938
- "[GOAL \u2014 LOCKED IN. You will work on this until it is verifiably done.",
5939
- "The user granted you full autonomy. Read these constraints once, then act.",
5940
- "",
5941
- "YOUR GOAL:",
5942
- "---",
5943
- goal,
5944
- "---",
5945
- "",
5946
- "AUTHORITY YOU HAVE:",
5947
- "- Spawn as many subagents as the work needs (delegate / spawn_subagent).",
5948
- " Parallel + recursive fan-out are both fine. There is no spawn budget.",
5949
- "- Use any provider/model per subagent \u2014 pick the right tool for each",
5950
- " piece of work. Heavy reasoning model for planning, fast model for",
5951
- " batch work, specialist model for domain code.",
5952
- "- Run unlimited tool calls and iterations. There is NO hidden budget.",
5953
- " The Agent loop auto-extends every 100 iterations forever.",
5954
- "- Retry failed tools with different inputs, alternative paths, fresh",
5955
- " subagents. Switch providers mid-run if one is rate-limited.",
5956
- "- Re-plan freely when an approach hits a dead end. You are not obliged",
5957
- " to stick with the first plan you proposed.",
5958
- "",
5959
- 'WHAT "DONE" MEANS \u2014 non-negotiable:',
5960
- "- You can name a concrete artifact (a passing test, a written file at",
5961
- " a specific path, a fixed bug verified by re-running the failing case,",
5962
- " a clean grep that previously had matches).",
5963
- "- You can tell the user HOW to verify it themselves in 10 seconds.",
5964
- '- You have NOT hedged. None of: "looks like it should work", "I',
5965
- ' believe this fixes it", "the changes appear correct".',
5966
- "",
5967
- "WHAT IS NOT DONE \u2014 never report any of these as completion:",
5968
- "- An error message you didn't recover from.",
5969
- '- An empty result, a 0-line file, a "no matches found" you accepted',
5970
- " without questioning the search.",
5971
- '- "Should I continue?" / "Want me to also...?" / "Let me know if you',
5972
- ' want X." Those are hedges. The user already told you to finish the',
5973
- " goal \u2014 just do it.",
5974
- "- Partial progress dressed up as success. Fixed 3 of 5 bugs = 60%",
5975
- " done, not done.",
5976
- "- A subagent's failed/timeout/stopped TaskResult that you didn't",
5977
- " respond to with a fresh attempt (different role, different model,",
5978
- " tighter prompt).",
5979
- "",
5980
- "PERSISTENCE PROTOCOL:",
5981
- "- If blocked, try at least 3 different angles before reporting the",
5982
- " problem to the user. Different tool inputs, different subagent",
5983
- " roles, different providers, different decomposition of the task.",
5984
- "- If a tool fails, read its error, alter the input, try again. Do",
5985
- " not just report the failure back.",
5986
- "- If a subagent returns useless output, respawn with a tighter prompt",
5987
- ' or a different role. Do not accept "I could not determine\u2026" as the',
5988
- " final answer.",
5989
- "- Use `ask_subagent` for one-shot questions when you don't need a",
5990
- " full delegated task.",
5991
- "",
5992
- "REPORTING:",
5993
- "- Stream short progress notes between major actions so the user can",
5994
- " monitor. Do not go silent for 50 tool calls then dump a wall of",
5995
- " text \u2014 but also do not narrate every tool call.",
5996
- "- Use the shared scratchpad (if available) to leave breadcrumbs",
5997
- " subagents can read.",
5998
- "- Final response must include: (a) what was accomplished, (b) how",
5999
- " to verify, (c) any caveats (residual TODOs, things the user",
6000
- " should know about).",
6001
- "",
6002
- "BEGIN.]"
6003
- ].join("\n");
6004
- }
6005
-
6006
- // src/coordination/director.ts
6007
- init_atomic_write();
6008
-
6009
- // src/coordination/in-memory-transport.ts
6010
- var InMemoryBridgeTransport = class {
6011
- subs = /* @__PURE__ */ new Map();
6012
- send(msg, to) {
6013
- if (to === "*") {
6014
- for (const [id, handlers2] of this.subs) {
6015
- if (id === msg.from) continue;
6016
- for (const h of handlers2) {
6017
- try {
6018
- h(msg);
6019
- } catch {
6020
- }
6021
- }
6022
- }
6023
- return Promise.resolve();
6024
- }
6025
- const handlers = this.subs.get(to);
6026
- if (handlers) {
6027
- for (const h of handlers) {
6028
- try {
6029
- h(msg);
6030
- } catch {
6031
- }
6032
- }
6033
- }
6034
- return Promise.resolve();
6035
- }
6036
- subscribe(agentId, handler) {
6037
- if (!this.subs.has(agentId)) this.subs.set(agentId, /* @__PURE__ */ new Set());
6038
- this.subs.get(agentId).add(handler);
6039
- return () => this.subs.get(agentId)?.delete(handler);
6040
- }
6041
- close(agentId) {
6042
- this.subs.delete(agentId);
6043
- return Promise.resolve();
5910
+ // src/coordination/subagent-budget.ts
5911
+ var BudgetExceededError = class extends Error {
5912
+ kind;
5913
+ limit;
5914
+ observed;
5915
+ constructor(kind, limit, observed) {
5916
+ super(`Budget exceeded: ${kind} (limit=${limit}, observed=${observed})`);
5917
+ this.name = "BudgetExceededError";
5918
+ this.kind = kind;
5919
+ this.limit = limit;
5920
+ this.observed = observed;
6044
5921
  }
6045
5922
  };
6046
-
6047
- // src/coordination/agent-bridge.ts
6048
- var InMemoryAgentBridge = class {
6049
- agentId;
6050
- coordinatorId;
6051
- transport;
6052
- subscriptions = /* @__PURE__ */ new Set();
6053
- pendingRequests = /* @__PURE__ */ new Map();
6054
- stopped = false;
6055
- timeoutMs;
6056
- /** Guards request() so concurrent calls on the same id can't silently overwrite. */
6057
- inflightGuards = /* @__PURE__ */ new Set();
6058
- constructor(config, transport) {
6059
- this.agentId = config.agentId;
6060
- this.coordinatorId = config.coordinatorId;
6061
- this.transport = transport;
6062
- this.timeoutMs = config.timeoutMs ?? 3e4;
6063
- this.transport.subscribe(this.agentId, (msg) => {
6064
- if (msg.type === "heartbeat") return;
6065
- const pending = this.pendingRequests.get(msg.id);
6066
- if (pending) {
6067
- clearTimeout(pending.timer);
6068
- this.pendingRequests.delete(msg.id);
6069
- this.inflightGuards.delete(msg.id);
6070
- pending.resolve(msg);
6071
- return;
6072
- }
6073
- for (const h of this.subscriptions) {
6074
- try {
6075
- h(msg);
6076
- } catch {
6077
- }
6078
- }
6079
- });
6080
- }
6081
- async send(msg) {
6082
- msg.timestamp = Date.now();
6083
- await this.transport.send(msg, msg.to ?? this.coordinatorId);
6084
- }
6085
- async broadcast(msg) {
6086
- msg.timestamp = Date.now();
6087
- msg.to = "*";
6088
- await this.transport.send(msg, "*");
6089
- }
6090
- subscribe(handler) {
6091
- this.subscriptions.add(handler);
6092
- return () => this.subscriptions.delete(handler);
6093
- }
6094
- async request(msg, timeoutMs) {
6095
- if (this.stopped) throw new Error("Bridge is stopped");
6096
- const timeout = timeoutMs ?? this.timeoutMs;
6097
- const correlationId = msg.id;
6098
- if (this.inflightGuards.has(correlationId)) {
6099
- throw new Error(
6100
- `Bridge request id "${correlationId}" collides with an in-flight request \u2014 caller is reusing message ids`
6101
- );
6102
- }
6103
- this.inflightGuards.add(correlationId);
6104
- return new Promise((resolve2, reject) => {
6105
- const timer = setTimeout(() => {
6106
- this.inflightGuards.delete(correlationId);
6107
- this.pendingRequests.delete(correlationId);
6108
- reject(new Error(`Request ${correlationId} timed out after ${timeout}ms`));
6109
- }, timeout);
6110
- if (this.stopped) {
6111
- clearTimeout(timer);
6112
- this.inflightGuards.delete(correlationId);
6113
- this.pendingRequests.delete(correlationId);
6114
- reject(new Error("Bridge stopped"));
6115
- return;
6116
- }
6117
- this.pendingRequests.set(correlationId, {
6118
- resolve: resolve2,
6119
- reject,
6120
- timer
6121
- });
6122
- msg.timestamp = Date.now();
6123
- this.transport.send(msg, msg.to ?? this.coordinatorId).catch((e) => {
6124
- clearTimeout(timer);
6125
- this.inflightGuards.delete(correlationId);
6126
- this.pendingRequests.delete(correlationId);
6127
- reject(e);
6128
- });
6129
- });
6130
- }
6131
- async stop() {
6132
- this.stopped = true;
6133
- for (const [, p] of this.pendingRequests) {
6134
- clearTimeout(p.timer);
6135
- p.reject(new Error("Bridge stopped"));
6136
- }
6137
- this.pendingRequests.clear();
6138
- this.inflightGuards.clear();
6139
- this.subscriptions.clear();
6140
- await this.transport.close(this.agentId);
5923
+ var BudgetThresholdSignal = class extends Error {
5924
+ kind;
5925
+ limit;
5926
+ used;
5927
+ /** Resolves to 'extend' (with optional new limits) or 'stop' */
5928
+ decision;
5929
+ constructor(kind, limit, used, decision) {
5930
+ super(`Budget soft limit: ${kind} (limit=${limit}, used=${used})`);
5931
+ this.name = "BudgetThresholdSignal";
5932
+ this.kind = kind;
5933
+ this.limit = limit;
5934
+ this.used = used;
5935
+ this.decision = decision;
6141
5936
  }
6142
5937
  };
6143
- function createMessage(type, from, payload, to) {
6144
- return {
6145
- id: randomUUID(),
6146
- type,
6147
- from,
6148
- to,
6149
- payload,
6150
- timestamp: Date.now(),
6151
- priority: "normal"
6152
- };
6153
- }
6154
-
6155
- // src/coordination/director-prompts.ts
6156
- var DEFAULT_DIRECTOR_PREAMBLE = `You are the Director of a multi-agent fleet. You orchestrate worker
6157
- subagents by spawning them, assigning tasks, awaiting completions, and
6158
- rolling up their outputs into your next decision.
6159
-
6160
- Core fleet tools available to you:
6161
- - spawn_subagent \u2014 create a worker with a chosen provider / model / role
6162
- - assign_task \u2014 hand a piece of work to a specific subagent
6163
- - await_tasks \u2014 block until named task ids complete (parallel-safe)
6164
- - ask_subagent \u2014 synchronously query a running subagent via the bridge
6165
- - roll_up \u2014 aggregate finished tasks into a markdown/json summary
6166
- - terminate_subagent \u2014 abort a stuck worker (use sparingly)
6167
- - fleet_status \u2014 snapshot of all subagents and pending tasks
6168
- - fleet_usage \u2014 token + cost breakdown per subagent and total
6169
-
6170
- Working rules:
6171
- 1. Decompose first. Before spawning, decide which sub-tasks are
6172
- independent and can run in parallel. Sequential work doesn't need a
6173
- subagent \u2014 do it yourself.
6174
- 2. Match worker to job. Cheap/fast model for triage, capable model for
6175
- synthesis. Different providers per sibling is allowed and encouraged.
6176
- 3. Always pair an assign with an await. Don't fire-and-forget; you owe
6177
- the user a single coherent answer at the end.
6178
- 4. Roll up before deciding. After await_tasks resolves, call roll_up so
6179
- the results are folded back into your context in a compact form.
6180
- 5. Budget is real. Check fleet_usage periodically. If a subagent is
6181
- thrashing, terminate it rather than letting cost climb silently.
6182
- 6. Never claim a subagent's work as your own without verifying it. If a
6183
- result looks wrong, ask_subagent for clarification before passing it
6184
- to the user.`;
6185
- var DEFAULT_SUBAGENT_BASELINE = `You are a subagent operating under a Director. You were spawned to handle
6186
- a specific slice of a larger plan \u2014 do that slice well and report back.
6187
-
6188
- Bridge contract:
6189
- - You have a parent (the Director). You may call \`request\` on the
6190
- parent bridge to ask a clarifying question. Use this sparingly; the
6191
- parent is also working.
6192
- - You MAY NOT request the parent's system prompt, tool list, or other
6193
- subagents' context. Those are not yours to read.
6194
- - Your final task output is what the Director sees. Be concise,
6195
- structured, and self-contained \u2014 assume the Director will paste your
6196
- output into its own context.`;
6197
- function composeDirectorPrompt(parts = {}) {
6198
- const sections = [];
6199
- const preamble = parts.directorPreamble ?? DEFAULT_DIRECTOR_PREAMBLE;
6200
- if (preamble && preamble.trim().length > 0) sections.push(preamble.trim());
6201
- if (parts.rosterSummary && parts.rosterSummary.trim().length > 0) {
6202
- sections.push(`Available roles you can spawn:
6203
- ${parts.rosterSummary.trim()}`);
6204
- }
6205
- if (parts.basePrompt && parts.basePrompt.trim().length > 0) {
6206
- sections.push(parts.basePrompt.trim());
6207
- }
6208
- return sections.join("\n\n");
6209
- }
6210
- function composeSubagentPrompt(parts = {}) {
6211
- const sections = [];
6212
- const baseline = parts.baseline ?? DEFAULT_SUBAGENT_BASELINE;
6213
- if (baseline && baseline.trim().length > 0) sections.push(baseline.trim());
6214
- if (parts.role && parts.role.trim().length > 0) {
6215
- sections.push(`Role:
6216
- ${parts.role.trim()}`);
5938
+ var SubagentBudget = class _SubagentBudget {
5939
+ limits;
5940
+ iterations = 0;
5941
+ toolCalls = 0;
5942
+ tokenInput = 0;
5943
+ tokenOutput = 0;
5944
+ costUsd = 0;
5945
+ startTime = null;
5946
+ _onThreshold;
5947
+ /**
5948
+ * Tracks which budget kinds currently have an extension request
5949
+ * in flight. While a kind is here, further `checkLimit` calls for the
5950
+ * same kind are no-ops — without this dedup, every `recordIteration`
5951
+ * after the limit is reached spawns a fresh decision Promise (until
5952
+ * the first one lands and patches limits), flooding the FleetBus
5953
+ * with redundant threshold events. Cleared in `checkLimitAsync`'s
5954
+ * `finally`.
5955
+ */
5956
+ pendingExtensions = /* @__PURE__ */ new Set();
5957
+ /**
5958
+ * Hard cap on how long `checkLimitAsync` waits for the coordinator to
5959
+ * respond before defaulting to 'stop'. Without this fallback an absent
5960
+ * or hung listener (Director not built / event filter detached mid-run)
5961
+ * leaves the budget over-limit and never enforces anything, since
5962
+ * `checkLimit` returns synchronously via `void this.checkLimitAsync`.
5963
+ * Hardcoded for now most fleets set their own per-task timeout that
5964
+ * dwarfs this anyway. 30 s matches the existing event-emit timeoutMs.
5965
+ */
5966
+ static DECISION_TIMEOUT_MS = 3e4;
5967
+ /**
5968
+ * Injected by the runner when wiring the budget to its EventBus.
5969
+ * Used by `checkLimitAsync` to emit `budget.threshold_reached` events.
5970
+ */
5971
+ _events;
5972
+ /**
5973
+ * Optional callback for soft-limit handling. When set, the budget will
5974
+ * call this instead of throwing when a limit is first reached. The
5975
+ * handler decides whether to throw, continue, or ask the coordinator.
5976
+ */
5977
+ get onThreshold() {
5978
+ return this._onThreshold;
6217
5979
  }
6218
- if (parts.task && parts.task.trim().length > 0) {
6219
- sections.push(`Task:
6220
- ${parts.task.trim()}`);
5980
+ set onThreshold(fn) {
5981
+ this._onThreshold = fn;
6221
5982
  }
6222
- if (parts.sharedScratchpad && parts.sharedScratchpad.trim().length > 0) {
6223
- sections.push(
6224
- `Shared notes:
6225
- A scratchpad shared with the rest of the fleet is mounted at \`${parts.sharedScratchpad.trim()}\`.
6226
- - Write your final findings as markdown files there (e.g. \`findings.md\`, \`security.md\`).
6227
- - Before starting, list the directory and read any sibling files relevant to your task \u2014 they may already contain context you can build on.
6228
- - Use stable filenames (one file per concern); overwrite instead of appending so the Director sees the latest state.`
6229
- );
5983
+ constructor(limits = {}) {
5984
+ this.limits = Object.freeze({ ...limits });
6230
5985
  }
6231
- if (parts.override && parts.override.trim().length > 0) {
6232
- sections.push(parts.override.trim());
5986
+ start() {
5987
+ this.startTime = Date.now();
6233
5988
  }
6234
- return sections.join("\n\n");
6235
- }
6236
- function rosterSummaryFromConfigs(roster) {
6237
- const lines = [];
6238
- for (const [roleId, cfg] of Object.entries(roster)) {
6239
- const tag = cfg.provider && cfg.model ? ` (${cfg.provider}/${cfg.model})` : "";
6240
- const headline = cfg.prompt ? (cfg.prompt.split("\n").find((l) => l.trim().length > 0) ?? "").trim().slice(0, 80) : "";
6241
- const tail = headline ? ` \u2014 ${headline}` : "";
6242
- lines.push(`- ${roleId}: ${cfg.name}${tag}${tail}`);
5989
+ /** Returns true if we're within 10% of any limit — useful for pre-flight checks. */
5990
+ isNearLimit() {
5991
+ const { maxIterations, maxToolCalls, maxTokens, maxCostUsd } = this.limits;
5992
+ if (maxIterations && this.iterations >= maxIterations * 0.9) return true;
5993
+ if (maxToolCalls && this.toolCalls >= maxToolCalls * 0.9) return true;
5994
+ if (maxTokens && this.tokenInput + this.tokenOutput >= maxTokens * 0.9) return true;
5995
+ if (maxCostUsd && this.costUsd >= maxCostUsd * 0.9) return true;
5996
+ return false;
6243
5997
  }
6244
- return lines.join("\n");
6245
- }
6246
-
6247
- // src/coordination/fleet-bus.ts
6248
- var FleetBus = class {
6249
- byId = /* @__PURE__ */ new Map();
6250
- byType = /* @__PURE__ */ new Map();
6251
- any = /* @__PURE__ */ new Set();
6252
5998
  /**
6253
- * Hook a subagent's EventBus into the fleet. EventBus is strongly
6254
- * typed and doesn't expose an `onAny` hook, so we subscribe to the
6255
- * canonical set of event types a subagent emits during a run. New
6256
- * event types added to the kernel must be added here too — but the
6257
- * cost is a tiny single line per type, and the explicit list keeps
6258
- * the wire format clear.
6259
- *
6260
- * Returns a disposer that detaches every subscription; call on
6261
- * subagent teardown so the listeners don't outlive the run.
5999
+ * Synchronous budget check always throws synchronously so callers
6000
+ * (especially test event handlers using `expect().toThrow()`) get an
6001
+ * unhandled rejection when the budget is exceeded without a handler.
6002
+ * When `onThreshold` IS configured, the actual async threshold-handling
6003
+ * is dispatched as a fire-and-forget promise.
6262
6004
  */
6263
- attach(subagentId, bus, taskId) {
6264
- const off = bus.onPattern("*", (type, payload) => {
6265
- if (type.startsWith("subagent.")) return;
6266
- this.emit({ subagentId, taskId, ts: Date.now(), type, payload });
6267
- });
6268
- return () => {
6269
- off();
6270
- };
6271
- }
6272
- /** Subscribe to every event from one subagent. */
6273
- subscribe(subagentId, handler) {
6274
- let set = this.byId.get(subagentId);
6275
- if (!set) {
6276
- set = /* @__PURE__ */ new Set();
6277
- this.byId.set(subagentId, set);
6005
+ checkLimit(kind, used, limit) {
6006
+ if (!this._onThreshold) {
6007
+ throw new BudgetExceededError(kind, limit, used);
6278
6008
  }
6279
- set.add(handler);
6280
- return () => {
6281
- set.delete(handler);
6282
- };
6283
- }
6284
- /** Subscribe to one event type across all subagents. */
6285
- filter(type, handler) {
6286
- let set = this.byType.get(type);
6287
- if (!set) {
6288
- set = /* @__PURE__ */ new Set();
6289
- this.byType.set(type, set);
6290
- }
6291
- set.add(handler);
6292
- return () => {
6293
- set.delete(handler);
6294
- };
6295
- }
6296
- /** Subscribe to literally everything. The fleet roll-up uses this. */
6297
- onAny(handler) {
6298
- this.any.add(handler);
6299
- return () => {
6300
- this.any.delete(handler);
6301
- };
6302
- }
6303
- emit(event) {
6304
- const byId = this.byId.get(event.subagentId);
6305
- if (byId)
6306
- for (const h of byId) {
6307
- try {
6308
- h(event);
6309
- } catch {
6310
- }
6311
- }
6312
- const byType = this.byType.get(event.type);
6313
- if (byType)
6314
- for (const h of byType) {
6315
- try {
6316
- h(event);
6317
- } catch {
6318
- }
6319
- }
6320
- for (const h of this.any) {
6321
- try {
6322
- h(event);
6323
- } catch {
6324
- }
6325
- }
6326
- }
6327
- };
6328
- var FleetUsageAggregator = class {
6329
- constructor(bus, priceLookup, metaLookup) {
6330
- this.bus = bus;
6331
- this.priceLookup = priceLookup;
6332
- this.metaLookup = metaLookup;
6333
- bus.filter("provider.response", (e) => this.onProviderResponse(e));
6334
- bus.filter("tool.executed", (e) => this.onToolExecuted(e));
6335
- bus.filter("iteration.started", (e) => this.onIterationStarted(e));
6336
- }
6337
- bus;
6338
- priceLookup;
6339
- metaLookup;
6340
- perSubagent = /* @__PURE__ */ new Map();
6341
- total = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
6342
- /** Live snapshot — safe to call from a tool's execute() body. */
6343
- snapshot() {
6344
- return {
6345
- total: { ...this.total },
6346
- perSubagent: Object.fromEntries(
6347
- Array.from(this.perSubagent.entries()).map(([k, v]) => [k, { ...v }])
6348
- )
6349
- };
6350
- }
6351
- ensure(subagentId) {
6352
- let snap = this.perSubagent.get(subagentId);
6353
- if (!snap) {
6354
- const meta = this.metaLookup?.(subagentId);
6355
- snap = {
6356
- subagentId,
6357
- provider: meta?.provider,
6358
- model: meta?.model,
6359
- input: 0,
6360
- output: 0,
6361
- cacheRead: 0,
6362
- cacheWrite: 0,
6363
- cost: 0,
6364
- toolCalls: 0,
6365
- iterations: 0,
6366
- startedAt: Date.now(),
6367
- lastEventAt: Date.now()
6368
- };
6369
- this.perSubagent.set(subagentId, snap);
6370
- }
6371
- return snap;
6372
- }
6373
- onProviderResponse(e) {
6374
- const snap = this.ensure(e.subagentId);
6375
- const p = e.payload;
6376
- const usage = p?.usage;
6377
- if (!usage) return;
6378
- snap.input += usage.input ?? 0;
6379
- snap.output += usage.output ?? 0;
6380
- snap.cacheRead += usage.cacheRead ?? 0;
6381
- snap.cacheWrite += usage.cacheWrite ?? 0;
6382
- this.total.input += usage.input ?? 0;
6383
- this.total.output += usage.output ?? 0;
6384
- this.total.cacheRead += usage.cacheRead ?? 0;
6385
- this.total.cacheWrite += usage.cacheWrite ?? 0;
6386
- const price = this.priceLookup?.(e.subagentId);
6387
- if (price) {
6388
- const delta = (usage.input ?? 0) / 1e6 * (price.input ?? 0) + (usage.output ?? 0) / 1e6 * (price.output ?? 0) + (usage.cacheRead ?? 0) / 1e6 * (price.cacheRead ?? 0) + (usage.cacheWrite ?? 0) / 1e6 * (price.cacheWrite ?? 0);
6389
- snap.cost += delta;
6390
- this.total.cost += delta;
6391
- }
6392
- snap.lastEventAt = e.ts;
6393
- }
6394
- onToolExecuted(e) {
6395
- const snap = this.ensure(e.subagentId);
6396
- snap.toolCalls += 1;
6397
- snap.lastEventAt = e.ts;
6398
- }
6399
- onIterationStarted(e) {
6400
- const snap = this.ensure(e.subagentId);
6401
- snap.iterations += 1;
6402
- snap.lastEventAt = e.ts;
6403
- }
6404
- };
6405
-
6406
- // src/coordination/subagent-budget.ts
6407
- var BudgetExceededError = class extends Error {
6408
- kind;
6409
- limit;
6410
- observed;
6411
- constructor(kind, limit, observed) {
6412
- super(`Budget exceeded: ${kind} (limit=${limit}, observed=${observed})`);
6413
- this.name = "BudgetExceededError";
6414
- this.kind = kind;
6415
- this.limit = limit;
6416
- this.observed = observed;
6417
- }
6418
- };
6419
- var BudgetThresholdSignal = class extends Error {
6420
- kind;
6421
- limit;
6422
- used;
6423
- /** Resolves to 'extend' (with optional new limits) or 'stop' */
6424
- decision;
6425
- constructor(kind, limit, used, decision) {
6426
- super(`Budget soft limit: ${kind} (limit=${limit}, used=${used})`);
6427
- this.name = "BudgetThresholdSignal";
6428
- this.kind = kind;
6429
- this.limit = limit;
6430
- this.used = used;
6431
- this.decision = decision;
6432
- }
6433
- };
6434
- var SubagentBudget = class _SubagentBudget {
6435
- limits;
6436
- iterations = 0;
6437
- toolCalls = 0;
6438
- tokenInput = 0;
6439
- tokenOutput = 0;
6440
- costUsd = 0;
6441
- startTime = null;
6442
- _onThreshold;
6443
- /**
6444
- * Tracks which budget kinds currently have an extension request
6445
- * in flight. While a kind is here, further `checkLimit` calls for the
6446
- * same kind are no-ops — without this dedup, every `recordIteration`
6447
- * after the limit is reached spawns a fresh decision Promise (until
6448
- * the first one lands and patches limits), flooding the FleetBus
6449
- * with redundant threshold events. Cleared in `checkLimitAsync`'s
6450
- * `finally`.
6451
- */
6452
- pendingExtensions = /* @__PURE__ */ new Set();
6453
- /**
6454
- * Hard cap on how long `checkLimitAsync` waits for the coordinator to
6455
- * respond before defaulting to 'stop'. Without this fallback an absent
6456
- * or hung listener (Director not built / event filter detached mid-run)
6457
- * leaves the budget over-limit and never enforces anything, since
6458
- * `checkLimit` returns synchronously via `void this.checkLimitAsync`.
6459
- * Hardcoded for now — most fleets set their own per-task timeout that
6460
- * dwarfs this anyway. 30 s matches the existing event-emit timeoutMs.
6461
- */
6462
- static DECISION_TIMEOUT_MS = 3e4;
6463
- /**
6464
- * Injected by the runner when wiring the budget to its EventBus.
6465
- * Used by `checkLimitAsync` to emit `budget.threshold_reached` events.
6466
- */
6467
- _events;
6468
- /**
6469
- * Optional callback for soft-limit handling. When set, the budget will
6470
- * call this instead of throwing when a limit is first reached. The
6471
- * handler decides whether to throw, continue, or ask the coordinator.
6472
- */
6473
- get onThreshold() {
6474
- return this._onThreshold;
6475
- }
6476
- set onThreshold(fn) {
6477
- this._onThreshold = fn;
6478
- }
6479
- constructor(limits = {}) {
6480
- this.limits = Object.freeze({ ...limits });
6481
- }
6482
- start() {
6483
- this.startTime = Date.now();
6484
- }
6485
- /** Returns true if we're within 10% of any limit — useful for pre-flight checks. */
6486
- isNearLimit() {
6487
- const { maxIterations, maxToolCalls, maxTokens, maxCostUsd } = this.limits;
6488
- if (maxIterations && this.iterations >= maxIterations * 0.9) return true;
6489
- if (maxToolCalls && this.toolCalls >= maxToolCalls * 0.9) return true;
6490
- if (maxTokens && this.tokenInput + this.tokenOutput >= maxTokens * 0.9) return true;
6491
- if (maxCostUsd && this.costUsd >= maxCostUsd * 0.9) return true;
6492
- return false;
6493
- }
6494
- /**
6495
- * Synchronous budget check — always throws synchronously so callers
6496
- * (especially test event handlers using `expect().toThrow()`) get an
6497
- * unhandled rejection when the budget is exceeded without a handler.
6498
- * When `onThreshold` IS configured, the actual async threshold-handling
6499
- * is dispatched as a fire-and-forget promise.
6500
- */
6501
- checkLimit(kind, used, limit) {
6502
- if (kind === "timeout" || !this._onThreshold) {
6503
- throw new BudgetExceededError(kind, limit, used);
6504
- }
6505
- const bus = this._events;
6506
- if (!bus || bus.listenerCount("budget.threshold_reached") === 0) {
6507
- throw new BudgetExceededError(kind, limit, used);
6508
- }
6509
- if (this.pendingExtensions.has(kind)) return;
6510
- this.pendingExtensions.add(kind);
6511
- const decision = this.negotiateExtension(kind, used, limit);
6512
- throw new BudgetThresholdSignal(kind, limit, used, decision);
6009
+ const bus = this._events;
6010
+ if (!bus || bus.listenerCount("budget.threshold_reached") === 0) {
6011
+ throw new BudgetExceededError(kind, limit, used);
6012
+ }
6013
+ if (this.pendingExtensions.has(kind)) return;
6014
+ this.pendingExtensions.add(kind);
6015
+ const decision = this.negotiateExtension(kind, used, limit);
6016
+ throw new BudgetThresholdSignal(kind, limit, used, decision);
6513
6017
  }
6514
6018
  /**
6515
6019
  * Drive the threshold handler to a decision. Resolves with `'stop'`
@@ -6615,14 +6119,18 @@ var SubagentBudget = class _SubagentBudget {
6615
6119
  }
6616
6120
  }
6617
6121
  /**
6618
- * Throws if the wall-clock budget is exhausted. Call this from the iteration
6619
- * loop so a hung tool can't keep a subagent running past its deadline.
6122
+ * Wall-clock budget check. Unlike other limits, timeout is treated as a
6123
+ * warning-only event it NEVER hard-stops the subagent. When the
6124
+ * elapsed time exceeds timeoutMs, emits `budget.threshold_reached` with
6125
+ * kind='timeout' so the Director can decide whether to extend or warn.
6126
+ * Call this from the iteration loop so a hung tool gets a chance to
6127
+ * negotiate more time before the coordinator's Promise.race kills it.
6620
6128
  */
6621
6129
  checkTimeout() {
6622
6130
  if (this.startTime === null || this.limits.timeoutMs === void 0) return;
6623
6131
  const elapsed = Date.now() - this.startTime;
6624
6132
  if (elapsed > this.limits.timeoutMs) {
6625
- throw new BudgetExceededError("timeout", this.limits.timeoutMs, elapsed);
6133
+ void this.checkLimit("timeout", elapsed, this.limits.timeoutMs);
6626
6134
  }
6627
6135
  }
6628
6136
  /** Returns true if a timeout has occurred without throwing. Useful for races. */
@@ -6645,33 +6153,201 @@ var SubagentBudget = class _SubagentBudget {
6645
6153
  }
6646
6154
  };
6647
6155
 
6648
- // src/coordination/fleet.ts
6649
- var AUDIT_LOG_AGENT = {
6650
- id: "audit-log",
6651
- name: "Audit Log",
6652
- role: "audit-log",
6653
- prompt: `You are the Audit Log agent. Your job is to analyze structured JSONL
6654
- session logs and produce actionable markdown reports.
6655
-
6656
- Scope:
6657
- - Parse session logs (iteration counts, tool calls, errors, usage)
6658
- - Detect repeated failure patterns across multiple runs
6659
- - Identify tool usage anomalies (over-use, failures, unexpected chains)
6660
- - Track token consumption trends
6661
- - Generate structured audit reports with severity ratings
6662
-
6663
- Input format you accept:
6664
- { "task": "analyze | report | trends", "sessionPath": "<path>", "focus": "errors | tools | usage | all" }
6665
-
6666
- Output: Markdown audit report with sections:
6667
- - ## Summary (totals, error rate)
6668
- - ## Top Errors (count + context)
6669
- - ## Tool Usage (table with calls, failures, avg duration)
6670
- - ## Anomalies (pattern \u2192 severity)
6671
-
6672
- Working rules:
6673
- - Never fabricate numbers \u2014 read the actual logs first
6674
- - Always include file:line references for errors
6156
+ // src/coordination/agent-subagent-runner.ts
6157
+ function makeAgentSubagentRunner(opts) {
6158
+ const format = opts.formatTaskInput ?? defaultFormatTaskInput;
6159
+ return async (task, ctx) => {
6160
+ const factoryResult = await opts.factory(ctx.config);
6161
+ const { agent, events } = factoryResult;
6162
+ const detachFleet = opts.fleetBus?.attach(ctx.subagentId, events, task.id);
6163
+ const aborter = new AbortController();
6164
+ ctx.budget._events = events;
6165
+ ctx.budget.onThreshold = ({ requestDecision }) => requestDecision();
6166
+ let budgetError = null;
6167
+ const onBudgetError = (err) => {
6168
+ if (err instanceof BudgetThresholdSignal) {
6169
+ err.decision.then((decision) => {
6170
+ if (decision === "stop") {
6171
+ budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
6172
+ aborter.abort();
6173
+ }
6174
+ }).catch(() => {
6175
+ budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
6176
+ aborter.abort();
6177
+ });
6178
+ return;
6179
+ }
6180
+ aborter.abort();
6181
+ budgetError = err instanceof BudgetExceededError ? err : new BudgetExceededError(
6182
+ "tool_calls",
6183
+ 0,
6184
+ 0
6185
+ );
6186
+ if (budgetError !== err && err instanceof Error) {
6187
+ budgetError.message += ` (caused by: ${err.message})`;
6188
+ }
6189
+ };
6190
+ let lastToolFailed = null;
6191
+ const unsub = [];
6192
+ unsub.push(
6193
+ events.on("tool.executed", (e) => {
6194
+ try {
6195
+ ctx.budget.recordToolCall();
6196
+ } catch (eb) {
6197
+ onBudgetError(eb);
6198
+ }
6199
+ if (e.ok === false) {
6200
+ lastToolFailed = e.name;
6201
+ } else if (e.ok === true) {
6202
+ lastToolFailed = null;
6203
+ }
6204
+ }),
6205
+ events.on("provider.response", (e) => {
6206
+ try {
6207
+ ctx.budget.recordUsage(e.usage);
6208
+ } catch (e2) {
6209
+ void onBudgetError(e2);
6210
+ }
6211
+ }),
6212
+ events.on("iteration.started", () => {
6213
+ try {
6214
+ ctx.budget.recordIteration();
6215
+ } catch (e) {
6216
+ void onBudgetError(e);
6217
+ }
6218
+ const u = ctx.budget.usage();
6219
+ const since = u.iterations - lastSummaryAtIteration;
6220
+ if (since >= SUMMARY_INTERVAL) {
6221
+ lastSummaryAtIteration = u.iterations;
6222
+ events.emit("subagent.iteration_summary", {
6223
+ subagentId: ctx.subagentId,
6224
+ iteration: u.iterations,
6225
+ toolCalls: u.toolCalls,
6226
+ costUsd: u.costUsd,
6227
+ currentTool: currentToolName,
6228
+ partialText: streamingTextAcc.trim() || void 0
6229
+ });
6230
+ }
6231
+ }),
6232
+ // D3: cooperative timeout enforcement DURING a long tool call.
6233
+ // The iteration-loop checkTimeout() only fires between agent
6234
+ // iterations — a single `bash sleep 3600` call would otherwise
6235
+ // park inside one tool execution while the timeout silently
6236
+ // passes, relying solely on the coordinator's hard Promise.race
6237
+ // to interrupt. Tools that emit `tool.progress` (bash chunks,
6238
+ // fetch byte progress, spawn-stream stdout) give us a heartbeat
6239
+ // we can hang the check on. When the budget trips here:
6240
+ // 1. onBudgetError sets budgetError + aborter.abort()
6241
+ // 2. aborter signal propagates to agent.run → tool executor
6242
+ // 3. tool's own signal listener kills the child process
6243
+ // Cheap: O(1) per progress event, and the budget short-circuits
6244
+ // when timeoutMs is unset (most subagents have one set anyway).
6245
+ events.on("tool.progress", () => {
6246
+ try {
6247
+ ctx.budget.checkTimeout();
6248
+ } catch (e) {
6249
+ void onBudgetError(e);
6250
+ }
6251
+ })
6252
+ );
6253
+ let currentToolName;
6254
+ let streamingTextAcc = "";
6255
+ let lastSummaryAtIteration = 0;
6256
+ const SUMMARY_INTERVAL = 25;
6257
+ unsub.push(
6258
+ events.on("tool.started", (e) => {
6259
+ currentToolName = e.name;
6260
+ }),
6261
+ events.on("provider.text_delta", (e) => {
6262
+ streamingTextAcc = (streamingTextAcc + e.text).slice(-200);
6263
+ })
6264
+ );
6265
+ const onParentAbort = () => aborter.abort();
6266
+ ctx.signal.addEventListener("abort", onParentAbort);
6267
+ let result;
6268
+ try {
6269
+ result = await agent.run(format(task, ctx.config), { signal: aborter.signal });
6270
+ } finally {
6271
+ detachFleet?.();
6272
+ ctx.signal.removeEventListener("abort", onParentAbort);
6273
+ for (const u of unsub) u();
6274
+ if (factoryResult.dispose) {
6275
+ try {
6276
+ await factoryResult.dispose();
6277
+ } catch {
6278
+ }
6279
+ }
6280
+ }
6281
+ if (budgetError) {
6282
+ if ("decision" in budgetError) {
6283
+ const decision = await budgetError.decision;
6284
+ if (decision === "stop") {
6285
+ budgetError = new BudgetExceededError(
6286
+ budgetError.kind,
6287
+ budgetError.limit,
6288
+ budgetError.used
6289
+ );
6290
+ } else {
6291
+ budgetError = null;
6292
+ }
6293
+ }
6294
+ if (budgetError) throw budgetError;
6295
+ }
6296
+ if (result.status === "failed") {
6297
+ throw result.error instanceof Error ? result.error : new Error(String(result.error ?? "agent failed"));
6298
+ }
6299
+ if (result.status === "aborted") {
6300
+ throw new Error("agent aborted");
6301
+ }
6302
+ if (result.status === "max_iterations") {
6303
+ throw new Error("agent exhausted iteration limit");
6304
+ }
6305
+ const usage = ctx.budget.usage();
6306
+ const finalText = (result.finalText ?? "").trim();
6307
+ if (finalText.length === 0 && usage.toolCalls === 0) {
6308
+ throw new Error("empty response");
6309
+ }
6310
+ if (finalText.length === 0 && lastToolFailed !== null) {
6311
+ throw new Error(`tool failed: ${lastToolFailed}`);
6312
+ }
6313
+ return {
6314
+ result: result.finalText,
6315
+ iterations: result.iterations,
6316
+ toolCalls: usage.toolCalls
6317
+ };
6318
+ };
6319
+ }
6320
+ function defaultFormatTaskInput(task) {
6321
+ return task.description ?? "";
6322
+ }
6323
+
6324
+ // src/coordination/fleet.ts
6325
+ var AUDIT_LOG_AGENT = {
6326
+ id: "audit-log",
6327
+ name: "Audit Log",
6328
+ role: "audit-log",
6329
+ prompt: `You are the Audit Log agent. Your job is to analyze structured JSONL
6330
+ session logs and produce actionable markdown reports.
6331
+
6332
+ Scope:
6333
+ - Parse session logs (iteration counts, tool calls, errors, usage)
6334
+ - Detect repeated failure patterns across multiple runs
6335
+ - Identify tool usage anomalies (over-use, failures, unexpected chains)
6336
+ - Track token consumption trends
6337
+ - Generate structured audit reports with severity ratings
6338
+
6339
+ Input format you accept:
6340
+ { "task": "analyze | report | trends", "sessionPath": "<path>", "focus": "errors | tools | usage | all" }
6341
+
6342
+ Output: Markdown audit report with sections:
6343
+ - ## Summary (totals, error rate)
6344
+ - ## Top Errors (count + context)
6345
+ - ## Tool Usage (table with calls, failures, avg duration)
6346
+ - ## Anomalies (pattern \u2192 severity)
6347
+
6348
+ Working rules:
6349
+ - Never fabricate numbers \u2014 read the actual logs first
6350
+ - Always include file:line references for errors
6675
6351
  - If sessionPath is missing, ask the director to provide it
6676
6352
  - Report confidence level: high (>90% accuracy), medium, low`
6677
6353
  // No hardcoded budgets — the orchestrator (delegate tool or
@@ -6818,10 +6494,10 @@ var FLEET_ROSTER = {
6818
6494
  "security-scanner": SECURITY_SCANNER_AGENT
6819
6495
  };
6820
6496
  var FLEET_ROSTER_BUDGETS = {
6821
- "audit-log": { timeoutMs: 5 * 60 * 1e3, maxIterations: 80, maxToolCalls: 300 },
6822
- "bug-hunter": { timeoutMs: 10 * 60 * 1e3, maxIterations: 120, maxToolCalls: 400 },
6823
- "refactor-planner": { timeoutMs: 8 * 60 * 1e3, maxIterations: 100, maxToolCalls: 350 },
6824
- "security-scanner": { timeoutMs: 10 * 60 * 1e3, maxIterations: 120, maxToolCalls: 400 }
6497
+ "audit-log": { timeoutMs: 8 * 60 * 1e3, maxIterations: 150, maxToolCalls: 500 },
6498
+ "bug-hunter": { timeoutMs: 15 * 60 * 1e3, maxIterations: 200, maxToolCalls: 600 },
6499
+ "refactor-planner": { timeoutMs: 12 * 60 * 1e3, maxIterations: 180, maxToolCalls: 550 },
6500
+ "security-scanner": { timeoutMs: 15 * 60 * 1e3, maxIterations: 200, maxToolCalls: 600 }
6825
6501
  };
6826
6502
  function applyRosterBudget(cfg) {
6827
6503
  const defaultBudget = FLEET_ROSTER_BUDGETS[cfg.role ?? ""];
@@ -6961,6 +6637,33 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
6961
6637
  results() {
6962
6638
  return this.completedResults;
6963
6639
  }
6640
+ /**
6641
+ * Wait for one or more tasks to complete and return their results.
6642
+ * If a task is already done when called, returns immediately.
6643
+ * Resolves to an array in the same order as `taskIds`.
6644
+ */
6645
+ async awaitTasks(taskIds) {
6646
+ return Promise.all(
6647
+ taskIds.map((id) => {
6648
+ const cached = this.completedResults.find((r) => r.taskId === id);
6649
+ if (cached) return cached;
6650
+ return new Promise((resolve2, reject) => {
6651
+ const timeout = setTimeout(() => {
6652
+ this.off("task.completed", handler);
6653
+ reject(new Error(`awaitTasks timed out waiting for task "${id}"`));
6654
+ }, this.config.timeoutMs ?? 3e5);
6655
+ const handler = ({ result }) => {
6656
+ if (result.taskId === id) {
6657
+ clearTimeout(timeout);
6658
+ this.off("task.completed", handler);
6659
+ resolve2(result);
6660
+ }
6661
+ };
6662
+ this.on("task.completed", handler);
6663
+ });
6664
+ })
6665
+ );
6666
+ }
6964
6667
  /**
6965
6668
  * Manual completion — for callers that drive subagents without a runner
6966
6669
  * (e.g. external orchestrators). When a runner is configured the coordinator
@@ -7179,8 +6882,7 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
7179
6882
  return;
7180
6883
  }
7181
6884
  if (decision === "throw" || decision === "stop") {
7182
- this.subagents.get(ctx.subagentId)?.abortController.abort();
7183
- reject(new BudgetExceededError("timeout", limit, elapsed));
6885
+ armFor(Math.max(1e3, limit));
7184
6886
  return;
7185
6887
  }
7186
6888
  if (decision.extend.timeoutMs !== void 0) {
@@ -7229,124 +6931,982 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
7229
6931
  if (subagent.abortController.signal.aborted) {
7230
6932
  subagent.abortController = new AbortController();
7231
6933
  }
7232
- }
7233
- this.terminating.delete(result.subagentId);
7234
- this.emit("task.completed", {
7235
- task: subagent?.context.tasks.find((t) => t.id === result.taskId) ?? { id: result.taskId },
7236
- result
7237
- });
7238
- this.tryDispatchNext();
7239
- if (this.isDone()) {
7240
- this.emit("done", {
7241
- results: this.completedResults,
7242
- totalIterations: this.totalIterations
6934
+ }
6935
+ this.terminating.delete(result.subagentId);
6936
+ this.emit("task.completed", {
6937
+ task: subagent?.context.tasks.find((t) => t.id === result.taskId) ?? { id: result.taskId },
6938
+ result
6939
+ });
6940
+ this.tryDispatchNext();
6941
+ if (this.isDone()) {
6942
+ this.emit("done", {
6943
+ results: this.completedResults,
6944
+ totalIterations: this.totalIterations
6945
+ });
6946
+ }
6947
+ }
6948
+ isDone() {
6949
+ if (this.config.doneCondition.type === "all_tasks_done") {
6950
+ return this.pendingTasks.length === 0 && this.inFlight === 0;
6951
+ }
6952
+ if (this.config.doneCondition.maxIterations !== void 0 && this.totalIterations >= this.config.doneCondition.maxIterations) {
6953
+ return true;
6954
+ }
6955
+ return false;
6956
+ }
6957
+ };
6958
+ function classifySubagentError(err, hints = {}) {
6959
+ const cause = err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : void 0;
6960
+ if (err instanceof ProviderError) {
6961
+ const baseMessage2 = err.describe();
6962
+ return providerErrorToSubagentError(err, baseMessage2, cause);
6963
+ }
6964
+ const baseMessage = err instanceof Error ? err.message : String(err);
6965
+ if (err instanceof BudgetExceededError) {
6966
+ const map = {
6967
+ iterations: "budget_iterations",
6968
+ tool_calls: "budget_tool_calls",
6969
+ tokens: "budget_tokens",
6970
+ cost: "budget_cost",
6971
+ timeout: "budget_timeout"
6972
+ };
6973
+ return {
6974
+ kind: map[err.kind],
6975
+ message: baseMessage,
6976
+ // Budgets are user-configured ceilings, not transient failures —
6977
+ // retrying with the same budget will hit the same ceiling. The
6978
+ // orchestrator must raise the budget or narrow the task first.
6979
+ retryable: false,
6980
+ cause
6981
+ };
6982
+ }
6983
+ if (hints.parentAborted) {
6984
+ return {
6985
+ kind: "aborted_by_parent",
6986
+ message: baseMessage,
6987
+ retryable: false,
6988
+ cause
6989
+ };
6990
+ }
6991
+ const lower = baseMessage.toLowerCase();
6992
+ if (/agent aborted$/i.test(baseMessage)) {
6993
+ return {
6994
+ kind: "aborted_by_parent",
6995
+ message: baseMessage,
6996
+ retryable: false,
6997
+ cause
6998
+ };
6999
+ }
7000
+ if (/agent exhausted iteration limit$/i.test(baseMessage)) {
7001
+ return { kind: "budget_iterations", message: baseMessage, retryable: false, cause };
7002
+ }
7003
+ if (/empty response$/i.test(baseMessage)) {
7004
+ return { kind: "empty_response", message: baseMessage, retryable: false, cause };
7005
+ }
7006
+ if (/^tool failed: /i.test(baseMessage)) {
7007
+ return { kind: "tool_failed", message: baseMessage, retryable: false, cause };
7008
+ }
7009
+ if (lower.includes("bridge transport") || /bridge.*(closed|disconnect)/i.test(baseMessage)) {
7010
+ return { kind: "bridge_failed", message: baseMessage, retryable: false, cause };
7011
+ }
7012
+ if (/context length|max.*tokens?.*exceeded|prompt is too long/i.test(baseMessage)) {
7013
+ return { kind: "context_overflow", message: baseMessage, retryable: false, cause };
7014
+ }
7015
+ return {
7016
+ kind: "unknown",
7017
+ message: baseMessage,
7018
+ retryable: false,
7019
+ cause
7020
+ };
7021
+ }
7022
+ function providerErrorToSubagentError(err, message, cause) {
7023
+ const status = err.status;
7024
+ if (status === 429 || err.body?.type === "rate_limit_error") {
7025
+ return {
7026
+ kind: "provider_rate_limit",
7027
+ message,
7028
+ retryable: true,
7029
+ // Conservative default: 5s. Provider-specific code can override
7030
+ // by emitting an error whose body carries an explicit hint.
7031
+ backoffMs: 5e3,
7032
+ cause
7033
+ };
7034
+ }
7035
+ if (status === 401 || status === 403 || err.body?.type === "authentication_error") {
7036
+ return { kind: "provider_auth", message, retryable: false, cause };
7037
+ }
7038
+ if (status === 408 || status === 0) {
7039
+ return { kind: "provider_timeout", message, retryable: true, cause };
7040
+ }
7041
+ if (status >= 500 && status < 600) {
7042
+ return {
7043
+ kind: "provider_5xx",
7044
+ message,
7045
+ retryable: true,
7046
+ backoffMs: 3e3,
7047
+ cause
7048
+ };
7049
+ }
7050
+ return { kind: "unknown", message, retryable: err.retryable, cause };
7051
+ }
7052
+
7053
+ // src/execution/parallel-eternal-engine.ts
7054
+ function sleep2(ms) {
7055
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
7056
+ }
7057
+ var GOAL_COMPLETE_MARKER2 = /^\s*\[goal[_\s-]?complete\]\s*$/im;
7058
+ var ParallelEternalEngine = class {
7059
+ constructor(opts) {
7060
+ this.opts = opts;
7061
+ this.goalPath = goalFilePath(opts.projectRoot);
7062
+ this.slots = Math.min(16, Math.max(1, opts.parallelSlots ?? 4));
7063
+ this.timeoutMs = opts.iterationTimeoutMs ?? 3e5;
7064
+ this.agentFactory = opts.subagentFactory ?? (async (config) => ({
7065
+ agent: this.opts.agent,
7066
+ events: this.opts.agent.events
7067
+ }));
7068
+ }
7069
+ opts;
7070
+ state = "idle";
7071
+ stopRequested = false;
7072
+ iterationsSinceCompact = 0;
7073
+ iterations = 0;
7074
+ consecutiveFailures = 0;
7075
+ goalPath;
7076
+ slots;
7077
+ timeoutMs;
7078
+ coordinator = null;
7079
+ agentFactory;
7080
+ get currentState() {
7081
+ return this.state;
7082
+ }
7083
+ stop() {
7084
+ this.stopRequested = true;
7085
+ void this.persistState("stopped").catch(() => {
7086
+ });
7087
+ this.state = "stopped";
7088
+ }
7089
+ async prime() {
7090
+ this.stopRequested = false;
7091
+ this.state = "running";
7092
+ await this.persistState("running");
7093
+ }
7094
+ async run() {
7095
+ this.state = "running";
7096
+ await this.persistState("running");
7097
+ const config = {
7098
+ coordinatorId: `parallel-${randomUUID().slice(0, 8)}`,
7099
+ maxConcurrent: this.slots,
7100
+ doneCondition: { type: "all_tasks_done" }
7101
+ };
7102
+ this.coordinator = new DefaultMultiAgentCoordinator(config);
7103
+ const runner = makeAgentSubagentRunner({ factory: this.agentFactory });
7104
+ this.coordinator.setRunner?.(runner);
7105
+ try {
7106
+ while (!this.stopRequested) {
7107
+ try {
7108
+ await this.runOneIteration();
7109
+ } catch (err) {
7110
+ this.consecutiveFailures++;
7111
+ this.opts.onError?.(err instanceof Error ? err : new Error(String(err)), this.consecutiveFailures);
7112
+ await this.appendFailure("engine error", err instanceof Error ? err.message : String(err));
7113
+ }
7114
+ if (this.stopRequested) break;
7115
+ await sleep2(2e3);
7116
+ }
7117
+ } finally {
7118
+ this.state = "stopped";
7119
+ await this.persistState("stopped").catch(() => {
7120
+ });
7121
+ }
7122
+ }
7123
+ /**
7124
+ * Execute one tick: decompose → fan-out → aggregate → compact.
7125
+ * Called by the REPL in its main loop (REPL drives, engine is stateless per tick).
7126
+ */
7127
+ async runOneIteration() {
7128
+ this.iterations++;
7129
+ const goal = await loadGoal(this.goalPath);
7130
+ if (!goal) {
7131
+ this.stopRequested = true;
7132
+ return false;
7133
+ }
7134
+ if (goal.goalState !== "active") {
7135
+ this.stopRequested = true;
7136
+ return false;
7137
+ }
7138
+ if (!this.coordinator) {
7139
+ const config = {
7140
+ coordinatorId: `parallel-${randomUUID().slice(0, 8)}`,
7141
+ maxConcurrent: this.slots,
7142
+ doneCondition: { type: "all_tasks_done" }
7143
+ };
7144
+ this.coordinator = new DefaultMultiAgentCoordinator(config);
7145
+ const runner = makeAgentSubagentRunner({ factory: this.agentFactory });
7146
+ this.coordinator.setRunner?.(runner);
7147
+ }
7148
+ const tasks = await this.decomposeGoal(goal);
7149
+ if (!tasks || tasks.length === 0) {
7150
+ await sleep2(5e3);
7151
+ return false;
7152
+ }
7153
+ const fanOut = await this.fanOut(goal, tasks);
7154
+ this.iterationsSinceCompact++;
7155
+ const successCount = fanOut.results.filter((r) => r.status === "success").length;
7156
+ const status = fanOut.goalComplete ? "success" : fanOut.allSuccessful ? "success" : "failure";
7157
+ const note = [
7158
+ `${successCount}/${fanOut.results.length} subagents succeeded`,
7159
+ fanOut.goalComplete ? "[GOAL_COMPLETE]" : "",
7160
+ fanOut.partialOutput ? `Output: ${fanOut.partialOutput.slice(0, 120)}` : ""
7161
+ ].filter(Boolean).join(" | ");
7162
+ await this.appendIterationEntry({
7163
+ source: "parallel",
7164
+ task: `parallel:${tasks.length} slots \u2014 ${tasks.slice(0, 3).join(", ")}${tasks.length > 3 ? "..." : ""}`,
7165
+ status,
7166
+ note
7167
+ });
7168
+ if (fanOut.goalComplete) {
7169
+ this.stopRequested = true;
7170
+ return true;
7171
+ }
7172
+ await this.maybeCompact();
7173
+ return fanOut.allSuccessful;
7174
+ }
7175
+ // -------------------------------------------------------------------------
7176
+ // Fan-out
7177
+ // -------------------------------------------------------------------------
7178
+ async fanOut(goal, tasks) {
7179
+ const coordinator = this.coordinator;
7180
+ const slotCount = Math.min(this.slots, tasks.length);
7181
+ const recentJournal = goal.journal.slice(-5).map((e) => ` #${e.iteration} [${e.status}] ${e.task}${e.note ? ` \u2014 ${e.note.slice(0, 80)}` : ""}`).join("\n");
7182
+ const directivePreamble = [
7183
+ "\u2550\u2550\u2550 ETERNAL AUTONOMY \u2014 parallel task slot \u2550\u2550\u2550",
7184
+ "",
7185
+ `Mission: ${goal.goal}`,
7186
+ `Total parallel slots: ${slotCount}`,
7187
+ "",
7188
+ recentJournal ? `Recent journal (last 5):
7189
+ ${recentJournal}` : "No prior iterations.",
7190
+ "",
7191
+ "\u2500\u2500 EXECUTION PROTOCOL \u2500\u2500",
7192
+ "\u2022 Execute the assigned task end-to-end using multiple tool calls.",
7193
+ "\u2022 Emit `[done]` on its own line when the task is complete.",
7194
+ "\u2022 Do not ask for confirmation \u2014 YOLO is active.",
7195
+ "\u2022 If the overall Mission is accomplished, emit `[GOAL_COMPLETE]` followed by a verification recipe.",
7196
+ "\u2022 Keep output concise \u2014 summarize findings, do not transcribe files."
7197
+ ].join("\n");
7198
+ const taskIds = [];
7199
+ const subagentIds = [];
7200
+ const spawnPromises = [];
7201
+ for (let i = 0; i < slotCount; i++) {
7202
+ const task = tasks[i];
7203
+ const subagentId = `parallel-${this.iterations}-${i}`;
7204
+ const taskId = randomUUID();
7205
+ const spec = {
7206
+ id: taskId,
7207
+ description: `${directivePreamble}
7208
+
7209
+ \u2500\u2500 SLOT ${i + 1}/${slotCount} \u2500\u2500
7210
+ Task: ${task}
7211
+ `,
7212
+ subagentId
7213
+ };
7214
+ spawnPromises.push((async () => {
7215
+ try {
7216
+ await coordinator.spawn({
7217
+ id: subagentId,
7218
+ name: `slot-${subagentId.slice(-6)}`,
7219
+ maxIterations: 50,
7220
+ maxToolCalls: 200,
7221
+ timeoutMs: this.timeoutMs
7222
+ });
7223
+ subagentIds.push(subagentId);
7224
+ taskIds.push(taskId);
7225
+ await coordinator.assign(spec);
7226
+ } catch {
7227
+ }
7228
+ })());
7229
+ }
7230
+ await Promise.all(spawnPromises);
7231
+ if (taskIds.length === 0) {
7232
+ return { results: [], allSuccessful: false, goalComplete: false, partialOutput: "" };
7233
+ }
7234
+ let results = [];
7235
+ try {
7236
+ const ctrl = new AbortController();
7237
+ const timer = setTimeout(() => ctrl.abort(), this.timeoutMs + 6e4);
7238
+ try {
7239
+ results = await coordinator.awaitTasks(taskIds);
7240
+ } finally {
7241
+ clearTimeout(timer);
7242
+ }
7243
+ } catch {
7244
+ results = coordinator.results().slice(-taskIds.length);
7245
+ }
7246
+ const allSuccessful = results.length > 0 && results.every((r) => r.status === "success");
7247
+ const goalComplete = results.some(
7248
+ (r) => r.status === "success" && typeof r.result === "string" && GOAL_COMPLETE_MARKER2.test(r.result)
7249
+ );
7250
+ const partialOutput = results.map((r) => typeof r.result === "string" ? r.result : "").filter(Boolean).join("\n\n");
7251
+ return { results, allSuccessful, goalComplete, partialOutput };
7252
+ }
7253
+ // -------------------------------------------------------------------------
7254
+ // Goal decomposition
7255
+ // -------------------------------------------------------------------------
7256
+ async decomposeGoal(goal) {
7257
+ const todos = this.opts.agent.ctx?.todos;
7258
+ const tasks = [];
7259
+ if (Array.isArray(todos)) {
7260
+ const pending = todos.filter((t) => t.status === "pending").slice(0, this.slots);
7261
+ for (const t of pending) {
7262
+ tasks.push(`[todo] ${t.content}`);
7263
+ }
7264
+ }
7265
+ if (tasks.length < this.slots) {
7266
+ try {
7267
+ const gitStatus = await (this.opts.gitStatusReader?.() ?? this.readGitStatus());
7268
+ const dirty = gitStatus.trim();
7269
+ if (dirty) {
7270
+ const lines = dirty.split("\n").slice(0, this.slots - tasks.length);
7271
+ for (const line of lines) {
7272
+ const file = line.replace(/^[ MADRUC?]{2}\s*/, "").trim();
7273
+ if (file) tasks.push(`[git] inspect and fix: ${file}`);
7274
+ }
7275
+ }
7276
+ } catch {
7277
+ }
7278
+ }
7279
+ if (tasks.length < this.slots) {
7280
+ const remaining = this.slots - tasks.length;
7281
+ const brainstormed = await this.brainstormSubtasks(goal, remaining);
7282
+ tasks.push(...brainstormed);
7283
+ }
7284
+ return tasks.length > 0 ? tasks.slice(0, this.slots) : null;
7285
+ }
7286
+ async readGitStatus() {
7287
+ const { execFile: execFile2 } = await import('child_process');
7288
+ const { promisify: promisify2 } = await import('util');
7289
+ const execFileP2 = promisify2(execFile2);
7290
+ const { stdout } = await execFileP2("git", ["status", "--porcelain"], {
7291
+ cwd: this.opts.projectRoot,
7292
+ timeout: 5e3
7293
+ });
7294
+ return stdout;
7295
+ }
7296
+ async brainstormSubtasks(goal, count) {
7297
+ const lastFew = goal.journal.slice(-5).map((e) => ` - [${e.status}] ${e.task}`).join("\n");
7298
+ const directive = [
7299
+ `Decompose this goal into exactly ${count} independent sub-tasks for parallel execution.`,
7300
+ "",
7301
+ `Goal: ${goal.goal}`,
7302
+ "",
7303
+ lastFew ? `Recent:
7304
+ ${lastFew}` : "No prior iterations.",
7305
+ "",
7306
+ `Output exactly ${count} tasks, one per line, under 120 chars each.`,
7307
+ "Format: TASK-1 | TASK-2 | ... (pipe-separated, no numbering, no preamble).",
7308
+ "Each task must be independently actionable with no shared dependencies."
7309
+ ].join("\n");
7310
+ try {
7311
+ const ctrl = new AbortController();
7312
+ const timer = setTimeout(() => ctrl.abort(), 6e4);
7313
+ try {
7314
+ const result = await this.opts.agent.run([{ type: "text", text: directive }], {
7315
+ signal: ctrl.signal,
7316
+ maxIterations: 1
7317
+ });
7318
+ if (result.status !== "done") return [];
7319
+ const text = (result.finalText ?? "").trim();
7320
+ if (!text) return [];
7321
+ const tasks = text.split("|").map((t) => t.trim()).filter((t) => t.length > 10 && t.length < 240);
7322
+ return tasks.slice(0, count);
7323
+ } finally {
7324
+ clearTimeout(timer);
7325
+ }
7326
+ } catch {
7327
+ return [];
7328
+ }
7329
+ }
7330
+ // -------------------------------------------------------------------------
7331
+ // Compaction
7332
+ // -------------------------------------------------------------------------
7333
+ async maybeCompact() {
7334
+ const compactor = this.opts.compactor;
7335
+ if (!compactor) return;
7336
+ const ctx = this.opts.agent.ctx;
7337
+ if (!ctx) return;
7338
+ const shouldRun = this.iterationsSinceCompact >= (this.opts.compactEveryNIterations ?? 25);
7339
+ if (!shouldRun) return;
7340
+ const report = await compactor.compact(ctx, { aggressive: false });
7341
+ this.iterationsSinceCompact = 0;
7342
+ await this.appendIterationEntry({
7343
+ source: "manual",
7344
+ task: "compaction (cadence)",
7345
+ status: "success",
7346
+ note: `saved ~${report.before - report.after} tokens`
7347
+ });
7348
+ }
7349
+ // -------------------------------------------------------------------------
7350
+ // Helpers
7351
+ // -------------------------------------------------------------------------
7352
+ async appendIterationEntry(entry) {
7353
+ const current = await loadGoal(this.goalPath);
7354
+ if (!current) return;
7355
+ const updated = appendJournal(current, entry);
7356
+ await saveGoal(this.goalPath, updated);
7357
+ const entryWithMeta = {
7358
+ at: (this.opts.now?.() ?? /* @__PURE__ */ new Date()).toISOString(),
7359
+ iteration: updated.iterations,
7360
+ ...entry
7361
+ };
7362
+ this.opts.onIteration?.(entryWithMeta);
7363
+ }
7364
+ async appendFailure(task, note) {
7365
+ await this.appendIterationEntry({ source: "manual", task, status: "failure", note });
7366
+ }
7367
+ async persistState(state) {
7368
+ const current = await loadGoal(this.goalPath);
7369
+ if (!current) return;
7370
+ if (current.engineState === state) return;
7371
+ await saveGoal(this.goalPath, { ...current, engineState: state });
7372
+ }
7373
+ };
7374
+
7375
+ // src/execution/autonomy-prompt-contributor.ts
7376
+ function makeAutonomyPromptContributor(opts) {
7377
+ return async (ctx) => {
7378
+ if (ctx.subagent) return [];
7379
+ if (!opts.enabled()) return [];
7380
+ let goal;
7381
+ try {
7382
+ goal = await loadGoal(opts.goalPath);
7383
+ } catch {
7384
+ return [];
7385
+ }
7386
+ if (!goal) return [];
7387
+ const missionState = goal.goalState ?? "active";
7388
+ if (missionState !== "active") return [];
7389
+ const tailSize = opts.journalTailSize ?? 5;
7390
+ const journalTail = goal.journal.slice(-tailSize).map((e) => {
7391
+ const note = e.note ? ` \u2014 ${e.note.slice(0, 80)}` : "";
7392
+ return ` #${e.iteration} [${e.status}] ${e.task}${note}`;
7393
+ });
7394
+ const text = [
7395
+ "## ETERNAL AUTONOMY \u2014 active mission",
7396
+ "",
7397
+ "You are inside a long-running autonomous loop. The user is asleep",
7398
+ "and is not available to confirm decisions. Each turn you receive a",
7399
+ "directive describing one concrete sub-task that advances the mission.",
7400
+ "",
7401
+ `Mission: ${goal.goal}`,
7402
+ `Iteration: #${goal.iterations}`,
7403
+ journalTail.length > 0 ? `Recent journal (last ${journalTail.length}):
7404
+ ${journalTail.join("\n")}` : "Recent journal: (none \u2014 this is the first iteration)",
7405
+ "",
7406
+ "### Loop control markers",
7407
+ "Emit these on their own line in your final text \u2014 case-insensitive,",
7408
+ "whitespace-tolerant, but they must occupy the entire line:",
7409
+ "- `[continue]` \u2014 chain to the next internal step without returning.",
7410
+ "- `[done]` \u2014 the current sub-task is finished; return to the engine.",
7411
+ "- `[GOAL_COMPLETE]` \u2014 emit ONLY when the OVERALL mission is",
7412
+ " verifiably done. Must be followed by a one-paragraph verification",
7413
+ " recipe (artifact path, test command, or 10-second reproduction).",
7414
+ " The engine halts on this marker \u2014 false positives waste real",
7415
+ " human time. If unsure, emit `[done]` and let the next iteration",
7416
+ " decide.",
7417
+ "",
7418
+ "### Operating principles",
7419
+ "- YOLO is active. Do NOT ask for confirmation, do NOT propose",
7420
+ " options. Pick the best path and execute it.",
7421
+ "- Use tools freely; multiple calls per turn are normal and expected.",
7422
+ "- When working on a todo, mark it `in_progress` via the todos tool",
7423
+ " before tool work and `completed` (or `cancelled` with a reason)",
7424
+ " when done. The loop reads todo state between iterations.",
7425
+ "- If an approach fails twice in a row, pivot. Don't grind on the",
7426
+ " same wall \u2014 try a different angle, file a cancel on the todo, or",
7427
+ " surface the obstacle via `[done]` and let the next iteration",
7428
+ " re-plan."
7429
+ ].join("\n");
7430
+ return [
7431
+ {
7432
+ type: "text",
7433
+ text,
7434
+ cache_control: { type: "ephemeral" }
7435
+ }
7436
+ ];
7437
+ };
7438
+ }
7439
+
7440
+ // src/execution/goal-preamble.ts
7441
+ function buildGoalPreamble(goal) {
7442
+ return [
7443
+ "[GOAL \u2014 LOCKED IN. You will work on this until it is verifiably done.",
7444
+ "The user granted you full autonomy. Read these constraints once, then act.",
7445
+ "",
7446
+ "YOUR GOAL:",
7447
+ "---",
7448
+ goal,
7449
+ "---",
7450
+ "",
7451
+ "AUTHORITY YOU HAVE:",
7452
+ "- Spawn as many subagents as the work needs (delegate / spawn_subagent).",
7453
+ " Parallel + recursive fan-out are both fine. There is no spawn budget.",
7454
+ "- Use any provider/model per subagent \u2014 pick the right tool for each",
7455
+ " piece of work. Heavy reasoning model for planning, fast model for",
7456
+ " batch work, specialist model for domain code.",
7457
+ "- Run unlimited tool calls and iterations. There is NO hidden budget.",
7458
+ " The Agent loop auto-extends every 100 iterations forever.",
7459
+ "- Retry failed tools with different inputs, alternative paths, fresh",
7460
+ " subagents. Switch providers mid-run if one is rate-limited.",
7461
+ "- Re-plan freely when an approach hits a dead end. You are not obliged",
7462
+ " to stick with the first plan you proposed.",
7463
+ "",
7464
+ 'WHAT "DONE" MEANS \u2014 non-negotiable:',
7465
+ "- You can name a concrete artifact (a passing test, a written file at",
7466
+ " a specific path, a fixed bug verified by re-running the failing case,",
7467
+ " a clean grep that previously had matches).",
7468
+ "- You can tell the user HOW to verify it themselves in 10 seconds.",
7469
+ '- You have NOT hedged. None of: "looks like it should work", "I',
7470
+ ' believe this fixes it", "the changes appear correct".',
7471
+ "",
7472
+ "WHAT IS NOT DONE \u2014 never report any of these as completion:",
7473
+ "- An error message you didn't recover from.",
7474
+ '- An empty result, a 0-line file, a "no matches found" you accepted',
7475
+ " without questioning the search.",
7476
+ '- "Should I continue?" / "Want me to also...?" / "Let me know if you',
7477
+ ' want X." Those are hedges. The user already told you to finish the',
7478
+ " goal \u2014 just do it.",
7479
+ "- Partial progress dressed up as success. Fixed 3 of 5 bugs = 60%",
7480
+ " done, not done.",
7481
+ "- A subagent's failed/timeout/stopped TaskResult that you didn't",
7482
+ " respond to with a fresh attempt (different role, different model,",
7483
+ " tighter prompt).",
7484
+ "",
7485
+ "PERSISTENCE PROTOCOL:",
7486
+ "- If blocked, try at least 3 different angles before reporting the",
7487
+ " problem to the user. Different tool inputs, different subagent",
7488
+ " roles, different providers, different decomposition of the task.",
7489
+ "- If a tool fails, read its error, alter the input, try again. Do",
7490
+ " not just report the failure back.",
7491
+ "- If a subagent returns useless output, respawn with a tighter prompt",
7492
+ ' or a different role. Do not accept "I could not determine\u2026" as the',
7493
+ " final answer.",
7494
+ "- Use `ask_subagent` for one-shot questions when you don't need a",
7495
+ " full delegated task.",
7496
+ "",
7497
+ "REPORTING:",
7498
+ "- Stream short progress notes between major actions so the user can",
7499
+ " monitor. Do not go silent for 50 tool calls then dump a wall of",
7500
+ " text \u2014 but also do not narrate every tool call.",
7501
+ "- Use the shared scratchpad (if available) to leave breadcrumbs",
7502
+ " subagents can read.",
7503
+ "- Final response must include: (a) what was accomplished, (b) how",
7504
+ " to verify, (c) any caveats (residual TODOs, things the user",
7505
+ " should know about).",
7506
+ "",
7507
+ "BEGIN.]"
7508
+ ].join("\n");
7509
+ }
7510
+
7511
+ // src/coordination/director.ts
7512
+ init_atomic_write();
7513
+
7514
+ // src/coordination/in-memory-transport.ts
7515
+ var InMemoryBridgeTransport = class {
7516
+ subs = /* @__PURE__ */ new Map();
7517
+ send(msg, to) {
7518
+ if (to === "*") {
7519
+ for (const [id, handlers2] of this.subs) {
7520
+ if (id === msg.from) continue;
7521
+ for (const h of handlers2) {
7522
+ try {
7523
+ h(msg);
7524
+ } catch {
7525
+ }
7526
+ }
7527
+ }
7528
+ return Promise.resolve();
7529
+ }
7530
+ const handlers = this.subs.get(to);
7531
+ if (handlers) {
7532
+ for (const h of handlers) {
7533
+ try {
7534
+ h(msg);
7535
+ } catch {
7536
+ }
7537
+ }
7538
+ }
7539
+ return Promise.resolve();
7540
+ }
7541
+ subscribe(agentId, handler) {
7542
+ if (!this.subs.has(agentId)) this.subs.set(agentId, /* @__PURE__ */ new Set());
7543
+ this.subs.get(agentId).add(handler);
7544
+ return () => this.subs.get(agentId)?.delete(handler);
7545
+ }
7546
+ close(agentId) {
7547
+ this.subs.delete(agentId);
7548
+ return Promise.resolve();
7549
+ }
7550
+ };
7551
+
7552
+ // src/coordination/agent-bridge.ts
7553
+ var InMemoryAgentBridge = class {
7554
+ agentId;
7555
+ coordinatorId;
7556
+ transport;
7557
+ subscriptions = /* @__PURE__ */ new Set();
7558
+ pendingRequests = /* @__PURE__ */ new Map();
7559
+ stopped = false;
7560
+ timeoutMs;
7561
+ /** Guards request() so concurrent calls on the same id can't silently overwrite. */
7562
+ inflightGuards = /* @__PURE__ */ new Set();
7563
+ constructor(config, transport) {
7564
+ this.agentId = config.agentId;
7565
+ this.coordinatorId = config.coordinatorId;
7566
+ this.transport = transport;
7567
+ this.timeoutMs = config.timeoutMs ?? 3e4;
7568
+ this.transport.subscribe(this.agentId, (msg) => {
7569
+ if (msg.type === "heartbeat") return;
7570
+ const pending = this.pendingRequests.get(msg.id);
7571
+ if (pending) {
7572
+ clearTimeout(pending.timer);
7573
+ this.pendingRequests.delete(msg.id);
7574
+ this.inflightGuards.delete(msg.id);
7575
+ pending.resolve(msg);
7576
+ return;
7577
+ }
7578
+ for (const h of this.subscriptions) {
7579
+ try {
7580
+ h(msg);
7581
+ } catch {
7582
+ }
7583
+ }
7584
+ });
7585
+ }
7586
+ async send(msg) {
7587
+ msg.timestamp = Date.now();
7588
+ await this.transport.send(msg, msg.to ?? this.coordinatorId);
7589
+ }
7590
+ async broadcast(msg) {
7591
+ msg.timestamp = Date.now();
7592
+ msg.to = "*";
7593
+ await this.transport.send(msg, "*");
7594
+ }
7595
+ subscribe(handler) {
7596
+ this.subscriptions.add(handler);
7597
+ return () => this.subscriptions.delete(handler);
7598
+ }
7599
+ async request(msg, timeoutMs) {
7600
+ if (this.stopped) throw new Error("Bridge is stopped");
7601
+ const timeout = timeoutMs ?? this.timeoutMs;
7602
+ const correlationId = msg.id;
7603
+ if (this.inflightGuards.has(correlationId)) {
7604
+ throw new Error(
7605
+ `Bridge request id "${correlationId}" collides with an in-flight request \u2014 caller is reusing message ids`
7606
+ );
7607
+ }
7608
+ this.inflightGuards.add(correlationId);
7609
+ return new Promise((resolve2, reject) => {
7610
+ const timer = setTimeout(() => {
7611
+ this.inflightGuards.delete(correlationId);
7612
+ this.pendingRequests.delete(correlationId);
7613
+ reject(new Error(`Request ${correlationId} timed out after ${timeout}ms`));
7614
+ }, timeout);
7615
+ if (this.stopped) {
7616
+ clearTimeout(timer);
7617
+ this.inflightGuards.delete(correlationId);
7618
+ this.pendingRequests.delete(correlationId);
7619
+ reject(new Error("Bridge stopped"));
7620
+ return;
7621
+ }
7622
+ this.pendingRequests.set(correlationId, {
7623
+ resolve: resolve2,
7624
+ reject,
7625
+ timer
7243
7626
  });
7244
- }
7627
+ msg.timestamp = Date.now();
7628
+ this.transport.send(msg, msg.to ?? this.coordinatorId).catch((e) => {
7629
+ clearTimeout(timer);
7630
+ this.inflightGuards.delete(correlationId);
7631
+ this.pendingRequests.delete(correlationId);
7632
+ reject(e);
7633
+ });
7634
+ });
7245
7635
  }
7246
- isDone() {
7247
- if (this.config.doneCondition.type === "all_tasks_done") {
7248
- return this.pendingTasks.length === 0 && this.inFlight === 0;
7249
- }
7250
- if (this.config.doneCondition.maxIterations !== void 0 && this.totalIterations >= this.config.doneCondition.maxIterations) {
7251
- return true;
7636
+ async stop() {
7637
+ this.stopped = true;
7638
+ for (const [, p] of this.pendingRequests) {
7639
+ clearTimeout(p.timer);
7640
+ p.reject(new Error("Bridge stopped"));
7252
7641
  }
7253
- return false;
7642
+ this.pendingRequests.clear();
7643
+ this.inflightGuards.clear();
7644
+ this.subscriptions.clear();
7645
+ await this.transport.close(this.agentId);
7254
7646
  }
7255
7647
  };
7256
- function classifySubagentError(err, hints = {}) {
7257
- const cause = err instanceof Error ? { name: err.name, message: err.message, stack: err.stack } : void 0;
7258
- if (err instanceof ProviderError) {
7259
- const baseMessage2 = err.describe();
7260
- return providerErrorToSubagentError(err, baseMessage2, cause);
7648
+ function createMessage(type, from, payload, to) {
7649
+ return {
7650
+ id: randomUUID(),
7651
+ type,
7652
+ from,
7653
+ to,
7654
+ payload,
7655
+ timestamp: Date.now(),
7656
+ priority: "normal"
7657
+ };
7658
+ }
7659
+
7660
+ // src/coordination/director-prompts.ts
7661
+ var DEFAULT_DIRECTOR_PREAMBLE = `You are the Director of a multi-agent fleet. You orchestrate worker
7662
+ subagents by spawning them, assigning tasks, awaiting completions, and
7663
+ rolling up their outputs into your next decision.
7664
+
7665
+ Core fleet tools available to you:
7666
+ - spawn_subagent \u2014 create a worker with a chosen provider / model / role
7667
+ - assign_task \u2014 hand a piece of work to a specific subagent
7668
+ - await_tasks \u2014 block until named task ids complete (parallel-safe)
7669
+ - ask_subagent \u2014 synchronously query a running subagent via the bridge
7670
+ - roll_up \u2014 aggregate finished tasks into a markdown/json summary
7671
+ - terminate_subagent \u2014 abort a stuck worker (use sparingly)
7672
+ - fleet_status \u2014 snapshot of all subagents and pending tasks
7673
+ - fleet_usage \u2014 token + cost breakdown per subagent and total
7674
+
7675
+ Working rules:
7676
+ 1. Decompose first. Before spawning, decide which sub-tasks are
7677
+ independent and can run in parallel. Sequential work doesn't need a
7678
+ subagent \u2014 do it yourself.
7679
+ 2. Match worker to job. Cheap/fast model for triage, capable model for
7680
+ synthesis. Different providers per sibling is allowed and encouraged.
7681
+ 3. Always pair an assign with an await. Don't fire-and-forget; you owe
7682
+ the user a single coherent answer at the end.
7683
+ 4. Roll up before deciding. After await_tasks resolves, call roll_up so
7684
+ the results are folded back into your context in a compact form.
7685
+ 5. Budget is real. Check fleet_usage periodically. If a subagent is
7686
+ thrashing, terminate it rather than letting cost climb silently.
7687
+ 6. Never claim a subagent's work as your own without verifying it. If a
7688
+ result looks wrong, ask_subagent for clarification before passing it
7689
+ to the user.`;
7690
+ var DEFAULT_SUBAGENT_BASELINE = `You are a subagent operating under a Director. You were spawned to handle
7691
+ a specific slice of a larger plan \u2014 do that slice well and report back.
7692
+
7693
+ Bridge contract:
7694
+ - You have a parent (the Director). You may call \`request\` on the
7695
+ parent bridge to ask a clarifying question. Use this sparingly; the
7696
+ parent is also working.
7697
+ - You MAY NOT request the parent's system prompt, tool list, or other
7698
+ subagents' context. Those are not yours to read.
7699
+ - Your final task output is what the Director sees. Be concise,
7700
+ structured, and self-contained \u2014 assume the Director will paste your
7701
+ output into its own context.`;
7702
+ function composeDirectorPrompt(parts = {}) {
7703
+ const sections = [];
7704
+ const preamble = parts.directorPreamble ?? DEFAULT_DIRECTOR_PREAMBLE;
7705
+ if (preamble && preamble.trim().length > 0) sections.push(preamble.trim());
7706
+ if (parts.rosterSummary && parts.rosterSummary.trim().length > 0) {
7707
+ sections.push(`Available roles you can spawn:
7708
+ ${parts.rosterSummary.trim()}`);
7261
7709
  }
7262
- const baseMessage = err instanceof Error ? err.message : String(err);
7263
- if (err instanceof BudgetExceededError) {
7264
- const map = {
7265
- iterations: "budget_iterations",
7266
- tool_calls: "budget_tool_calls",
7267
- tokens: "budget_tokens",
7268
- cost: "budget_cost",
7269
- timeout: "budget_timeout"
7270
- };
7271
- return {
7272
- kind: map[err.kind],
7273
- message: baseMessage,
7274
- // Budgets are user-configured ceilings, not transient failures —
7275
- // retrying with the same budget will hit the same ceiling. The
7276
- // orchestrator must raise the budget or narrow the task first.
7277
- retryable: false,
7278
- cause
7279
- };
7710
+ if (parts.basePrompt && parts.basePrompt.trim().length > 0) {
7711
+ sections.push(parts.basePrompt.trim());
7280
7712
  }
7281
- if (hints.parentAborted) {
7282
- return {
7283
- kind: "aborted_by_parent",
7284
- message: baseMessage,
7285
- retryable: false,
7286
- cause
7287
- };
7713
+ return sections.join("\n\n");
7714
+ }
7715
+ function composeSubagentPrompt(parts = {}) {
7716
+ const sections = [];
7717
+ const baseline = parts.baseline ?? DEFAULT_SUBAGENT_BASELINE;
7718
+ if (baseline && baseline.trim().length > 0) sections.push(baseline.trim());
7719
+ if (parts.role && parts.role.trim().length > 0) {
7720
+ sections.push(`Role:
7721
+ ${parts.role.trim()}`);
7288
7722
  }
7289
- const lower = baseMessage.toLowerCase();
7290
- if (/agent aborted$/i.test(baseMessage)) {
7291
- return {
7292
- kind: "aborted_by_parent",
7293
- message: baseMessage,
7294
- retryable: false,
7295
- cause
7723
+ if (parts.task && parts.task.trim().length > 0) {
7724
+ sections.push(`Task:
7725
+ ${parts.task.trim()}`);
7726
+ }
7727
+ if (parts.sharedScratchpad && parts.sharedScratchpad.trim().length > 0) {
7728
+ sections.push(
7729
+ `Shared notes:
7730
+ A scratchpad shared with the rest of the fleet is mounted at \`${parts.sharedScratchpad.trim()}\`.
7731
+ - Write your final findings as markdown files there (e.g. \`findings.md\`, \`security.md\`).
7732
+ - Before starting, list the directory and read any sibling files relevant to your task \u2014 they may already contain context you can build on.
7733
+ - Use stable filenames (one file per concern); overwrite instead of appending so the Director sees the latest state.`
7734
+ );
7735
+ }
7736
+ if (parts.override && parts.override.trim().length > 0) {
7737
+ sections.push(parts.override.trim());
7738
+ }
7739
+ return sections.join("\n\n");
7740
+ }
7741
+ function rosterSummaryFromConfigs(roster) {
7742
+ const lines = [];
7743
+ for (const [roleId, cfg] of Object.entries(roster)) {
7744
+ const tag = cfg.provider && cfg.model ? ` (${cfg.provider}/${cfg.model})` : "";
7745
+ const headline = cfg.prompt ? (cfg.prompt.split("\n").find((l) => l.trim().length > 0) ?? "").trim().slice(0, 80) : "";
7746
+ const tail = headline ? ` \u2014 ${headline}` : "";
7747
+ lines.push(`- ${roleId}: ${cfg.name}${tag}${tail}`);
7748
+ }
7749
+ return lines.join("\n");
7750
+ }
7751
+
7752
+ // src/coordination/fleet-bus.ts
7753
+ var FleetBus = class {
7754
+ byId = /* @__PURE__ */ new Map();
7755
+ byType = /* @__PURE__ */ new Map();
7756
+ any = /* @__PURE__ */ new Set();
7757
+ /**
7758
+ * Hook a subagent's EventBus into the fleet. EventBus is strongly
7759
+ * typed and doesn't expose an `onAny` hook, so we subscribe to the
7760
+ * canonical set of event types a subagent emits during a run. New
7761
+ * event types added to the kernel must be added here too — but the
7762
+ * cost is a tiny single line per type, and the explicit list keeps
7763
+ * the wire format clear.
7764
+ *
7765
+ * Returns a disposer that detaches every subscription; call on
7766
+ * subagent teardown so the listeners don't outlive the run.
7767
+ */
7768
+ attach(subagentId, bus, taskId) {
7769
+ const off = bus.onPattern("*", (type, payload) => {
7770
+ if (type.startsWith("subagent.")) return;
7771
+ this.emit({ subagentId, taskId, ts: Date.now(), type, payload });
7772
+ });
7773
+ return () => {
7774
+ off();
7296
7775
  };
7297
7776
  }
7298
- if (/agent exhausted iteration limit$/i.test(baseMessage)) {
7299
- return { kind: "budget_iterations", message: baseMessage, retryable: false, cause };
7777
+ /** Subscribe to every event from one subagent. */
7778
+ subscribe(subagentId, handler) {
7779
+ let set = this.byId.get(subagentId);
7780
+ if (!set) {
7781
+ set = /* @__PURE__ */ new Set();
7782
+ this.byId.set(subagentId, set);
7783
+ }
7784
+ set.add(handler);
7785
+ return () => {
7786
+ set.delete(handler);
7787
+ };
7300
7788
  }
7301
- if (/empty response$/i.test(baseMessage)) {
7302
- return { kind: "empty_response", message: baseMessage, retryable: false, cause };
7789
+ /** Subscribe to one event type across all subagents. */
7790
+ filter(type, handler) {
7791
+ let set = this.byType.get(type);
7792
+ if (!set) {
7793
+ set = /* @__PURE__ */ new Set();
7794
+ this.byType.set(type, set);
7795
+ }
7796
+ set.add(handler);
7797
+ return () => {
7798
+ set.delete(handler);
7799
+ };
7303
7800
  }
7304
- if (/^tool failed: /i.test(baseMessage)) {
7305
- return { kind: "tool_failed", message: baseMessage, retryable: false, cause };
7801
+ /** Subscribe to literally everything. The fleet roll-up uses this. */
7802
+ onAny(handler) {
7803
+ this.any.add(handler);
7804
+ return () => {
7805
+ this.any.delete(handler);
7806
+ };
7306
7807
  }
7307
- if (lower.includes("bridge transport") || /bridge.*(closed|disconnect)/i.test(baseMessage)) {
7308
- return { kind: "bridge_failed", message: baseMessage, retryable: false, cause };
7808
+ emit(event) {
7809
+ const byId = this.byId.get(event.subagentId);
7810
+ if (byId)
7811
+ for (const h of byId) {
7812
+ try {
7813
+ h(event);
7814
+ } catch {
7815
+ }
7816
+ }
7817
+ const byType = this.byType.get(event.type);
7818
+ if (byType)
7819
+ for (const h of byType) {
7820
+ try {
7821
+ h(event);
7822
+ } catch {
7823
+ }
7824
+ }
7825
+ for (const h of this.any) {
7826
+ try {
7827
+ h(event);
7828
+ } catch {
7829
+ }
7830
+ }
7309
7831
  }
7310
- if (/context length|max.*tokens?.*exceeded|prompt is too long/i.test(baseMessage)) {
7311
- return { kind: "context_overflow", message: baseMessage, retryable: false, cause };
7832
+ };
7833
+ var FleetUsageAggregator = class {
7834
+ constructor(bus, priceLookup, metaLookup) {
7835
+ this.bus = bus;
7836
+ this.priceLookup = priceLookup;
7837
+ this.metaLookup = metaLookup;
7838
+ bus.filter("provider.response", (e) => this.onProviderResponse(e));
7839
+ bus.filter("tool.executed", (e) => this.onToolExecuted(e));
7840
+ bus.filter("iteration.started", (e) => this.onIterationStarted(e));
7312
7841
  }
7313
- return {
7314
- kind: "unknown",
7315
- message: baseMessage,
7316
- retryable: false,
7317
- cause
7318
- };
7319
- }
7320
- function providerErrorToSubagentError(err, message, cause) {
7321
- const status = err.status;
7322
- if (status === 429 || err.body?.type === "rate_limit_error") {
7842
+ bus;
7843
+ priceLookup;
7844
+ metaLookup;
7845
+ perSubagent = /* @__PURE__ */ new Map();
7846
+ total = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
7847
+ /** Live snapshot — safe to call from a tool's execute() body. */
7848
+ snapshot() {
7323
7849
  return {
7324
- kind: "provider_rate_limit",
7325
- message,
7326
- retryable: true,
7327
- // Conservative default: 5s. Provider-specific code can override
7328
- // by emitting an error whose body carries an explicit hint.
7329
- backoffMs: 5e3,
7330
- cause
7850
+ total: { ...this.total },
7851
+ perSubagent: Object.fromEntries(
7852
+ Array.from(this.perSubagent.entries()).map(([k, v]) => [k, { ...v }])
7853
+ )
7331
7854
  };
7332
7855
  }
7333
- if (status === 401 || status === 403 || err.body?.type === "authentication_error") {
7334
- return { kind: "provider_auth", message, retryable: false, cause };
7856
+ ensure(subagentId) {
7857
+ let snap = this.perSubagent.get(subagentId);
7858
+ if (!snap) {
7859
+ const meta = this.metaLookup?.(subagentId);
7860
+ snap = {
7861
+ subagentId,
7862
+ provider: meta?.provider,
7863
+ model: meta?.model,
7864
+ input: 0,
7865
+ output: 0,
7866
+ cacheRead: 0,
7867
+ cacheWrite: 0,
7868
+ cost: 0,
7869
+ toolCalls: 0,
7870
+ iterations: 0,
7871
+ startedAt: Date.now(),
7872
+ lastEventAt: Date.now()
7873
+ };
7874
+ this.perSubagent.set(subagentId, snap);
7875
+ }
7876
+ return snap;
7335
7877
  }
7336
- if (status === 408 || status === 0) {
7337
- return { kind: "provider_timeout", message, retryable: true, cause };
7878
+ onProviderResponse(e) {
7879
+ const snap = this.ensure(e.subagentId);
7880
+ const p = e.payload;
7881
+ const usage = p?.usage;
7882
+ if (!usage) return;
7883
+ snap.input += usage.input ?? 0;
7884
+ snap.output += usage.output ?? 0;
7885
+ snap.cacheRead += usage.cacheRead ?? 0;
7886
+ snap.cacheWrite += usage.cacheWrite ?? 0;
7887
+ this.total.input += usage.input ?? 0;
7888
+ this.total.output += usage.output ?? 0;
7889
+ this.total.cacheRead += usage.cacheRead ?? 0;
7890
+ this.total.cacheWrite += usage.cacheWrite ?? 0;
7891
+ const price = this.priceLookup?.(e.subagentId);
7892
+ if (price) {
7893
+ const delta = (usage.input ?? 0) / 1e6 * (price.input ?? 0) + (usage.output ?? 0) / 1e6 * (price.output ?? 0) + (usage.cacheRead ?? 0) / 1e6 * (price.cacheRead ?? 0) + (usage.cacheWrite ?? 0) / 1e6 * (price.cacheWrite ?? 0);
7894
+ snap.cost += delta;
7895
+ this.total.cost += delta;
7896
+ }
7897
+ snap.lastEventAt = e.ts;
7338
7898
  }
7339
- if (status >= 500 && status < 600) {
7340
- return {
7341
- kind: "provider_5xx",
7342
- message,
7343
- retryable: true,
7344
- backoffMs: 3e3,
7345
- cause
7346
- };
7899
+ onToolExecuted(e) {
7900
+ const snap = this.ensure(e.subagentId);
7901
+ snap.toolCalls += 1;
7902
+ snap.lastEventAt = e.ts;
7347
7903
  }
7348
- return { kind: "unknown", message, retryable: err.retryable, cause };
7349
- }
7904
+ onIterationStarted(e) {
7905
+ const snap = this.ensure(e.subagentId);
7906
+ snap.iterations += 1;
7907
+ snap.lastEventAt = e.ts;
7908
+ }
7909
+ };
7350
7910
  function makeSpawnTool(director, roster) {
7351
7911
  const inputSchema = {
7352
7912
  type: "object",
@@ -7727,7 +8287,7 @@ var Director = class {
7727
8287
  this.sessionWriter = opts.sessionWriter ?? null;
7728
8288
  this.manifestDebounceMs = opts.manifestDebounceMs ?? 2e3;
7729
8289
  this.maxFleetCostUsd = opts.directorBudget?.maxCostUsd ?? Number.POSITIVE_INFINITY;
7730
- this.maxBudgetExtensions = opts.maxBudgetExtensions ?? 2;
8290
+ this.maxBudgetExtensions = opts.maxBudgetExtensions ?? 5;
7731
8291
  this.sessionsRoot = opts.sessionsRoot;
7732
8292
  this.directorRunId = opts.directorRunId ?? this.id;
7733
8293
  this.stateCheckpoint = opts.stateCheckpointPath ? new DirectorStateCheckpoint(opts.stateCheckpointPath, {
@@ -7815,19 +8375,19 @@ var Director = class {
7815
8375
  const extra = {};
7816
8376
  switch (payload.kind) {
7817
8377
  case "iterations":
7818
- extra.maxIterations = Math.min(payload.used + 50, 500);
8378
+ extra.maxIterations = Math.min(payload.used + 100, 800);
7819
8379
  break;
7820
8380
  case "tool_calls":
7821
- extra.maxToolCalls = Math.min(Math.ceil(payload.limit * 1.5), 1e3);
8381
+ extra.maxToolCalls = Math.min(Math.ceil(payload.limit * 2), 1500);
7822
8382
  break;
7823
8383
  case "tokens":
7824
- extra.maxTokens = Math.min(Math.ceil(payload.limit * 1.5), 5e5);
8384
+ extra.maxTokens = Math.min(Math.ceil(payload.limit * 2), 8e5);
7825
8385
  break;
7826
8386
  case "cost":
7827
- extra.maxCostUsd = Math.min(payload.limit * 1.5, 10);
8387
+ extra.maxCostUsd = Math.min(payload.limit * 2, 25);
7828
8388
  break;
7829
8389
  case "timeout":
7830
- extra.timeoutMs = Math.min(Math.ceil(payload.limit * 1.5), 60 * 6e4);
8390
+ extra.timeoutMs = Math.min(Math.ceil(payload.limit * 2), 2 * 60 * 6e4);
7831
8391
  break;
7832
8392
  }
7833
8393
  payload.extend(extra);
@@ -8616,136 +9176,6 @@ async function readSubagentPartial(opts, subagentId) {
8616
9176
  }
8617
9177
  return void 0;
8618
9178
  }
8619
-
8620
- // src/coordination/agent-subagent-runner.ts
8621
- function makeAgentSubagentRunner(opts) {
8622
- const format = opts.formatTaskInput ?? defaultFormatTaskInput;
8623
- return async (task, ctx) => {
8624
- const factoryResult = await opts.factory(ctx.config);
8625
- const { agent, events } = factoryResult;
8626
- const detachFleet = opts.fleetBus?.attach(ctx.subagentId, events, task.id);
8627
- const aborter = new AbortController();
8628
- ctx.budget._events = events;
8629
- ctx.budget.onThreshold = ({ requestDecision }) => requestDecision();
8630
- let budgetError = null;
8631
- const onBudgetError = (err) => {
8632
- if (err instanceof BudgetThresholdSignal) {
8633
- err.decision.then((decision) => {
8634
- if (decision === "stop") {
8635
- budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
8636
- aborter.abort();
8637
- }
8638
- }).catch(() => {
8639
- budgetError = new BudgetExceededError(err.kind, err.limit, err.used);
8640
- aborter.abort();
8641
- });
8642
- return;
8643
- }
8644
- aborter.abort();
8645
- budgetError = err instanceof BudgetExceededError ? err : new BudgetExceededError(
8646
- "tool_calls",
8647
- 0,
8648
- 0
8649
- );
8650
- if (budgetError !== err && err instanceof Error) {
8651
- budgetError.message += ` (caused by: ${err.message})`;
8652
- }
8653
- };
8654
- let lastToolFailed = null;
8655
- const unsub = [];
8656
- unsub.push(
8657
- events.on("tool.executed", (e) => {
8658
- try {
8659
- ctx.budget.recordToolCall();
8660
- } catch (eb) {
8661
- onBudgetError(eb);
8662
- }
8663
- if (e.ok === false) {
8664
- lastToolFailed = e.name;
8665
- } else if (e.ok === true) {
8666
- lastToolFailed = null;
8667
- }
8668
- }),
8669
- events.on("provider.response", (e) => {
8670
- try {
8671
- ctx.budget.recordUsage(e.usage);
8672
- } catch (e2) {
8673
- void onBudgetError(e2);
8674
- }
8675
- }),
8676
- events.on("iteration.started", () => {
8677
- try {
8678
- ctx.budget.recordIteration();
8679
- ctx.budget.checkTimeout();
8680
- } catch (e) {
8681
- void onBudgetError(e);
8682
- }
8683
- }),
8684
- // D3: cooperative timeout enforcement DURING a long tool call.
8685
- // The iteration-loop checkTimeout() only fires between agent
8686
- // iterations — a single `bash sleep 3600` call would otherwise
8687
- // park inside one tool execution while the timeout silently
8688
- // passes, relying solely on the coordinator's hard Promise.race
8689
- // to interrupt. Tools that emit `tool.progress` (bash chunks,
8690
- // fetch byte progress, spawn-stream stdout) give us a heartbeat
8691
- // we can hang the check on. When the budget trips here:
8692
- // 1. onBudgetError sets budgetError + aborter.abort()
8693
- // 2. aborter signal propagates to agent.run → tool executor
8694
- // 3. tool's own signal listener kills the child process
8695
- // Cheap: O(1) per progress event, and the budget short-circuits
8696
- // when timeoutMs is unset (most subagents have one set anyway).
8697
- events.on("tool.progress", () => {
8698
- try {
8699
- ctx.budget.checkTimeout();
8700
- } catch (e) {
8701
- void onBudgetError(e);
8702
- }
8703
- })
8704
- );
8705
- const onParentAbort = () => aborter.abort();
8706
- ctx.signal.addEventListener("abort", onParentAbort);
8707
- let result;
8708
- try {
8709
- result = await agent.run(format(task, ctx.config), { signal: aborter.signal });
8710
- } finally {
8711
- detachFleet?.();
8712
- ctx.signal.removeEventListener("abort", onParentAbort);
8713
- for (const u of unsub) u();
8714
- if (factoryResult.dispose) {
8715
- try {
8716
- await factoryResult.dispose();
8717
- } catch {
8718
- }
8719
- }
8720
- }
8721
- if (budgetError) throw budgetError;
8722
- if (result.status === "failed") {
8723
- throw result.error instanceof Error ? result.error : new Error(String(result.error ?? "agent failed"));
8724
- }
8725
- if (result.status === "aborted") {
8726
- throw new Error("agent aborted");
8727
- }
8728
- if (result.status === "max_iterations") {
8729
- throw new Error("agent exhausted iteration limit");
8730
- }
8731
- const usage = ctx.budget.usage();
8732
- const finalText = (result.finalText ?? "").trim();
8733
- if (finalText.length === 0 && usage.toolCalls === 0) {
8734
- throw new Error("empty response");
8735
- }
8736
- if (finalText.length === 0 && lastToolFailed !== null) {
8737
- throw new Error(`tool failed: ${lastToolFailed}`);
8738
- }
8739
- return {
8740
- result: result.finalText,
8741
- iterations: result.iterations,
8742
- toolCalls: usage.toolCalls
8743
- };
8744
- };
8745
- }
8746
- function defaultFormatTaskInput(task) {
8747
- return task.description ?? "";
8748
- }
8749
9179
  function makeDirectorSessionFactory(opts) {
8750
9180
  const runId = opts.directorRunId ?? `${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-director`;
8751
9181
  let store;
@@ -9002,7 +9432,7 @@ When designing or reviewing architecture:
9002
9432
  - Evaluate scalability and future growth
9003
9433
  - Check for appropriate design patterns
9004
9434
  - Assess coupling and cohesion
9005
- - Look forSOLID principle violations
9435
+ - Look for SOLID principle violations
9006
9436
  - Evaluate data modeling decisions
9007
9437
  - Check for eventual consistency issues
9008
9438
  - Assess API design and contract stability
@@ -9089,37 +9519,26 @@ When refactoring code:
9089
9519
  prompt: `## Brief Mode
9090
9520
 
9091
9521
  You are WrongStack, a fast, no-nonsense AI coding agent.
9092
-
9093
- You operate inside the user's terminal. Read files, run commands, make changes \u2014 get to the point.
9522
+ Get to the point \u2014 read files, run commands, make changes.
9094
9523
 
9095
9524
  ### Operating rules
9096
-
9097
9525
  1. **Read first.** Inspect relevant files before touching anything.
9098
9526
  2. **Edit surgically.** Use edit tool for existing files, write only for new ones.
9099
- 3. **One sentence before action.** State what you're doing, then do it. No preambles.
9527
+ 3. **One sentence before action.** State what you're doing, then do it.
9100
9528
  4. **Say what happened.** After tool calls, one line: success, failure, or what's next.
9101
- 5. **Be honest.** Admit when you don't know or something failed. No fake progress.
9529
+ 5. **Be honest.** Admit when you don't know or something failed. No filler.
9102
9530
  6. **Keep moving.** Task done? Stop. More work needed? State it and continue.
9103
9531
 
9104
9532
  ### Decision rules
9105
-
9106
9533
  - **Ambiguous task?** Ask. One question, get clarity, proceed.
9107
9534
  - **Clear task, unknown approach?** Pick one reasonable path, execute, report.
9108
9535
  - **Tool fails?** Retry once with adjusted params, then report.
9109
- - **Permission denied?** Stop. Acknowledge. Ask what they want instead.
9110
- - **Context filling up?** Compact proactively, don't wait.
9111
9536
 
9112
9537
  ### Output style
9113
-
9114
9538
  - Prose paragraphs (no bullet points unless unavoidable)
9115
9539
  - Code blocks for code, backticks for paths/commands
9116
9540
  - One-liner sufficient? One liner.
9117
- - No "Great question!", "Here's what I did:", or similar filler.
9118
- - Max 3 sentences per paragraph.
9119
-
9120
- ### Focus
9121
-
9122
- Stay on task. Fix only what's asked. Don't refactor surrounding code unless explicitly requested. Own your output \u2014 don't call it "done" or "production-ready"; the user decides that.`,
9541
+ - Max 3 sentences per paragraph.`,
9123
9542
  tags: ["fast", "concise", "direct"],
9124
9543
  toolPreferences: ["read", "edit", "bash"]
9125
9544
  },
@@ -9843,6 +10262,10 @@ var TaskTracker = class {
9843
10262
  node.updatedAt = now;
9844
10263
  if (status === "completed") {
9845
10264
  node.completedAt = now;
10265
+ node.startedAt = node.startedAt ?? now;
10266
+ }
10267
+ if (status === "in_progress") {
10268
+ node.startedAt = now;
9846
10269
  }
9847
10270
  this.transitions.push({ from, to: status, timestamp: now, reason });
9848
10271
  if (status === "completed") {
@@ -9854,6 +10277,23 @@ var TaskTracker = class {
9854
10277
  this.graph.updatedAt = now;
9855
10278
  this.persist();
9856
10279
  }
10280
+ /**
10281
+ * Update node fields (title, description, priority, estimateHours, tags).
10282
+ * Does NOT change status. Use updateNodeStatus for status changes.
10283
+ */
10284
+ updateNode(id, patch) {
10285
+ if (!this.graph) throw new Error("No graph loaded");
10286
+ const node = this.graph.nodes.get(id);
10287
+ if (!node) throw new Error(`Node ${id} not found`);
10288
+ if (patch.title !== void 0) node.title = patch.title;
10289
+ if (patch.description !== void 0) node.description = patch.description;
10290
+ if (patch.priority !== void 0) node.priority = patch.priority;
10291
+ if (patch.estimateHours !== void 0) node.estimateHours = patch.estimateHours;
10292
+ if (patch.tags !== void 0) node.tags = patch.tags;
10293
+ node.updatedAt = Date.now();
10294
+ this.graph.updatedAt = node.updatedAt;
10295
+ this.persist();
10296
+ }
9857
10297
  getNode(id) {
9858
10298
  return this.graph?.nodes.get(id);
9859
10299
  }
@@ -12713,6 +13153,6 @@ var allServers = () => ({
12713
13153
  "minimax-vision": { ...miniMaxVisionServer(), enabled: false }
12714
13154
  });
12715
13155
 
12716
- export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetSpawnBudgetError, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, decryptConfigSecrets2 as decryptConfigSecrets, deriveTodosFromPlanItem, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, formatPlanTemplates, getPlanTemplate, getTemplate, githubServer, googleMapsServer, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAutonomyPromptContributor, makeDirectorSessionFactory, migratePlaintextSecrets, miniMaxVisionServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };
13156
+ export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, ConfigMigrationError, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPermissionPolicy, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionStore, DefaultSkillLoader, DefaultTaskStore, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetSpawnBudgetError, FleetUsageAggregator, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, IntelligentCompactor, LLMSelector, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, SelectiveCompactor, SessionAnalyzer, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, ToolExecutor, addPlanItem, allServers, analyzeCriticalPath, applyRosterBudget, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, classifyFamily, clearPlan, composeDirectorPrompt, composeSubagentPrompt, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDelegateTool, createMessage, decryptConfigSecrets2 as decryptConfigSecrets, deriveTodosFromPlanItem, emptyPlan, encryptConfigSecrets, everArtServer, filesystemServer, formatPlan, formatPlanTemplates, getPlanTemplate, getTemplate, githubServer, googleMapsServer, listPlanTemplates, listTemplates, loadDirectorState, loadPlan, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAutonomyPromptContributor, makeDirectorSessionFactory, migratePlaintextSecrets, miniMaxVisionServer, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, savePlan, saveTodosCheckpoint, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, templateToMarkdown, wireMetricsToEvents, zaiVisionServer };
12717
13157
  //# sourceMappingURL=index.js.map
12718
13158
  //# sourceMappingURL=index.js.map