@wrongstack/core 0.6.0 → 0.6.3

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 (41) hide show
  1. package/dist/{agent-bridge-BKNiE1VH.d.ts → agent-bridge-eb7qnNrd.d.ts} +1 -1
  2. package/dist/coordination/index.d.ts +5 -5
  3. package/dist/coordination/index.js +183 -87
  4. package/dist/coordination/index.js.map +1 -1
  5. package/dist/defaults/index.d.ts +10 -10
  6. package/dist/defaults/index.js +596 -114
  7. package/dist/defaults/index.js.map +1 -1
  8. package/dist/{events-DPQKFX7W.d.ts → events-BHuIHekD.d.ts} +27 -4
  9. package/dist/execution/index.d.ts +149 -6
  10. package/dist/execution/index.js +401 -21
  11. package/dist/execution/index.js.map +1 -1
  12. package/dist/extension/index.d.ts +2 -2
  13. package/dist/{goal-store-BQ3YX1h1.d.ts → goal-store-DVCfj7Ff.d.ts} +20 -0
  14. package/dist/{index-B0qTujQW.d.ts → index-BOn9NK7D.d.ts} +1 -1
  15. package/dist/{index-DkdRz6yK.d.ts → index-CPcDqvZh.d.ts} +11 -4
  16. package/dist/index.d.ts +50 -16
  17. package/dist/index.js +831 -125
  18. package/dist/index.js.map +1 -1
  19. package/dist/infrastructure/index.d.ts +2 -2
  20. package/dist/infrastructure/index.js +1 -1
  21. package/dist/infrastructure/index.js.map +1 -1
  22. package/dist/kernel/index.d.ts +2 -2
  23. package/dist/kernel/index.js.map +1 -1
  24. package/dist/{multi-agent-Cpp7FXUl.d.ts → multi-agent-CxSb-9dQ.d.ts} +30 -5
  25. package/dist/observability/index.d.ts +1 -1
  26. package/dist/observability/index.js +1 -1
  27. package/dist/observability/index.js.map +1 -1
  28. package/dist/{path-resolver--g_hKJ7V.d.ts → path-resolver-CMGNadvq.d.ts} +1 -1
  29. package/dist/{plan-templates-CKJs_sYh.d.ts → plan-templates-BJflQY2i.d.ts} +1 -1
  30. package/dist/{provider-runner-hl4Il3xS.d.ts → provider-runner-BFgNXpaP.d.ts} +1 -1
  31. package/dist/sdd/index.d.ts +2 -2
  32. package/dist/storage/index.d.ts +3 -3
  33. package/dist/storage/index.js +3 -0
  34. package/dist/storage/index.js.map +1 -1
  35. package/dist/{tool-executor-B03CRwu-.d.ts → tool-executor-FoxBjULX.d.ts} +1 -1
  36. package/dist/types/index.d.ts +7 -7
  37. package/dist/types/index.js +30 -4
  38. package/dist/types/index.js.map +1 -1
  39. package/dist/utils/index.js +1 -1
  40. package/dist/utils/index.js.map +1 -1
  41. package/package.json +5 -1
package/dist/index.js CHANGED
@@ -1347,7 +1347,7 @@ function round4(n) {
1347
1347
  }
1348
1348
 
1349
1349
  // src/utils/token-estimate.ts
1350
- var RoughTokenEstimate = (text) => Math.max(1, Math.ceil(text.length / 4));
1350
+ var RoughTokenEstimate = (text, charsPerToken = 3.5) => Math.max(1, Math.ceil(text.length / charsPerToken));
1351
1351
  var ESTIMATE_CACHE = /* @__PURE__ */ new Map();
1352
1352
  var ESTIMATE_CACHE_MAX_SIZE = 1e4;
1353
1353
  function getCachedEstimate(key, compute) {
@@ -1526,7 +1526,7 @@ var HybridCompactor = class {
1526
1526
  eliseThreshold;
1527
1527
  estimator;
1528
1528
  constructor(opts = {}) {
1529
- this.preserveK = opts.preserveK ?? 10;
1529
+ this.preserveK = opts.preserveK ?? 5;
1530
1530
  this.eliseThreshold = opts.eliseThreshold ?? 2e3;
1531
1531
  this.estimator = opts.estimator ?? estimateTextTokens;
1532
1532
  }
@@ -1570,6 +1570,17 @@ var HybridCompactor = class {
1570
1570
  preserveStart = i;
1571
1571
  }
1572
1572
  }
1573
+ for (let i = preserveStart; i < messages.length; i++) {
1574
+ const m = messages[i];
1575
+ if (!m || typeof m.content === "string" || !Array.isArray(m.content)) continue;
1576
+ const hasToolUse2 = m.content.some((b) => b.type === "tool_use");
1577
+ if (hasToolUse2 && i + 1 < messages.length) {
1578
+ const next = messages[i + 1];
1579
+ if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => b.type === "tool_result")) {
1580
+ preserveStart = i + 1;
1581
+ }
1582
+ }
1583
+ }
1573
1584
  let saved = 0;
1574
1585
  let changed = false;
1575
1586
  const nextMessages = new Array(messages.length);
@@ -1591,7 +1602,7 @@ var HybridCompactor = class {
1591
1602
  const elided = {
1592
1603
  type: "tool_result",
1593
1604
  tool_use_id: b.tool_use_id,
1594
- content: `[elided: ~${tokens} tokens removed. Call the tool again if needed.]`,
1605
+ content: `[elided: ~${tokens} tokens]`,
1595
1606
  is_error: b.is_error
1596
1607
  };
1597
1608
  return elided;
@@ -2934,13 +2945,17 @@ var ToolExecutor = class {
2934
2945
  const ctrl = new AbortController();
2935
2946
  const timer = setTimeout(() => ctrl.abort(new Error("tool timeout")), timeoutMs);
2936
2947
  const combined = AbortSignal.any([parentSignal, ctrl.signal]);
2948
+ let cleanupCalled = false;
2949
+ let caught = false;
2937
2950
  try {
2938
2951
  if (typeof tool.executeStream === "function") {
2939
2952
  return await this.runStreamedTool(tool, input, ctx, combined, toolUseId);
2940
2953
  }
2941
2954
  return await tool.execute(input, ctx, { signal: combined });
2942
2955
  } catch (err) {
2956
+ caught = true;
2943
2957
  if (combined.aborted && typeof tool.cleanup === "function") {
2958
+ cleanupCalled = true;
2944
2959
  try {
2945
2960
  await tool.cleanup(input, ctx);
2946
2961
  } catch {
@@ -2949,6 +2964,16 @@ var ToolExecutor = class {
2949
2964
  throw err;
2950
2965
  } finally {
2951
2966
  clearTimeout(timer);
2967
+ if (combined.aborted && !caught) {
2968
+ if (!cleanupCalled && typeof tool.cleanup === "function") {
2969
+ try {
2970
+ await tool.cleanup(input, ctx);
2971
+ } catch {
2972
+ }
2973
+ }
2974
+ const reason = combined.reason instanceof Error ? combined.reason : new Error(typeof combined.reason === "string" ? combined.reason : "aborted");
2975
+ throw reason;
2976
+ }
2952
2977
  }
2953
2978
  }
2954
2979
  async runStreamedTool(tool, input, ctx, signal, toolUseId) {
@@ -3006,7 +3031,8 @@ var ToolExecutor = class {
3006
3031
  if (subjectKey) {
3007
3032
  const v = obj[subjectKey];
3008
3033
  if (typeof v === "string") {
3009
- return subjectKey === "path" || subjectKey === "file" || subjectKey === "files" ? normalizePath(v) : escapeGlob(v);
3034
+ const isPathKey = subjectKey === "path" || subjectKey === "file" || subjectKey === "files";
3035
+ return isPathKey ? normalizePath(v) : escapeGlob(v);
3010
3036
  }
3011
3037
  }
3012
3038
  if (toolName === "bash" && typeof obj.command === "string") {
@@ -6277,17 +6303,23 @@ async function streamProviderToResponse(provider, req, signal, ctx, events) {
6277
6303
  handleTextDelta(state, ev.text);
6278
6304
  events.emit("provider.text_delta", { ctx, text: ev.text });
6279
6305
  break;
6280
- case "tool_use_start":
6281
- handleToolUseStart(state, ev);
6282
- events.emit("provider.tool_use_start", { ctx, id: ev.id, name: ev.name });
6306
+ case "tool_use_start": {
6307
+ const idVal = ev.id;
6308
+ const nameVal = ev.name;
6309
+ handleToolUseStart(state, { id: idVal, name: nameVal });
6310
+ const emittedPayload = { ctx, id: idVal ?? "unknown", name: nameVal ?? "unknown" };
6311
+ events.emit("provider.tool_use_start", emittedPayload);
6283
6312
  break;
6313
+ }
6284
6314
  case "tool_use_input_delta":
6285
6315
  handleToolUseInputDelta(state, ev);
6286
6316
  break;
6287
- case "tool_use_stop":
6317
+ case "tool_use_stop": {
6318
+ const stoppedName = state.tools.get(ev.id)?.name ?? "unknown";
6288
6319
  handleToolUseStop(state, ev);
6289
- events.emit("provider.tool_use_stop", { ctx, id: ev.id });
6320
+ events.emit("provider.tool_use_stop", { ctx, id: ev.id, name: stoppedName });
6290
6321
  break;
6322
+ }
6291
6323
  case "thinking_start":
6292
6324
  handleThinkingStart(state, ev);
6293
6325
  break;
@@ -6475,7 +6507,28 @@ var IntelligentCompactor = class {
6475
6507
  try {
6476
6508
  summaryText = await this.callSummarizer(toSummarize, ctx);
6477
6509
  } catch {
6478
- summaryText = `[${toSummarize.length} earlier turns omitted \u2014 key decisions and file states preserved in context]`;
6510
+ const toolNames = /* @__PURE__ */ new Set();
6511
+ const filePaths = /* @__PURE__ */ new Set();
6512
+ let userTurns = 0, assistantTurns = 0;
6513
+ for (const m of toSummarize) {
6514
+ if (m.role === "user") userTurns++;
6515
+ else if (m.role === "assistant") {
6516
+ assistantTurns++;
6517
+ if (Array.isArray(m.content)) {
6518
+ for (const b of m.content) {
6519
+ if (b.type === "tool_use") toolNames.add(b.name ?? "unknown");
6520
+ }
6521
+ }
6522
+ }
6523
+ const text = typeof m.content === "string" ? m.content : "";
6524
+ const matches = text.matchAll(/(?:[\w.,\-/@]+\/)*[\w.,\-/@]+\.\w+/g);
6525
+ for (const m_ of matches) filePaths.add(m_[0]);
6526
+ }
6527
+ const parts = [`${toSummarize.length} turns (${userTurns} user, ${assistantTurns} assistant)`];
6528
+ if (toolNames.size > 0) parts.push(`tools: ${[...toolNames].join(", ")}`);
6529
+ if (filePaths.size > 0) parts.push(`files: ${[...filePaths].slice(0, 10).join(", ")}`);
6530
+ summaryText = parts.join(" | ");
6531
+ if (!summaryText) summaryText = `${toSummarize.length} earlier turns omitted`;
6479
6532
  }
6480
6533
  const summaryMsg = {
6481
6534
  role: "system",
@@ -6559,6 +6612,17 @@ var IntelligentCompactor = class {
6559
6612
  preserveStart = i;
6560
6613
  }
6561
6614
  }
6615
+ for (let i = preserveStart; i < messages.length; i++) {
6616
+ const m = messages[i];
6617
+ if (!m || typeof m.content === "string" || !Array.isArray(m.content)) continue;
6618
+ const hasToolUse2 = m.content.some((b) => b.type === "tool_use");
6619
+ if (hasToolUse2 && i + 1 < messages.length) {
6620
+ const next = messages[i + 1];
6621
+ if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => b.type === "tool_result")) {
6622
+ preserveStart = i + 1;
6623
+ }
6624
+ }
6625
+ }
6562
6626
  let saved = 0;
6563
6627
  let changed = false;
6564
6628
  const nextMessages = new Array(messages.length);
@@ -7073,7 +7137,15 @@ var AutoCompactionMiddleware = class {
7073
7137
  }
7074
7138
  async compact(ctx, aggressive, pressure) {
7075
7139
  try {
7076
- await this.compactor.compact(ctx, { aggressive });
7140
+ const report = await this.compactor.compact(ctx, { aggressive });
7141
+ this.events?.emit("compaction.fired", {
7142
+ level: pressure.level,
7143
+ tokens: pressure.tokens,
7144
+ load: pressure.load,
7145
+ maxContext: this._maxContext,
7146
+ report,
7147
+ aggressive
7148
+ });
7077
7149
  } catch (err) {
7078
7150
  const error = err instanceof Error ? err : new Error(String(err));
7079
7151
  const fatal = this.failureMode === "throw" || this.failureMode === "throw_on_hard" && pressure.level === "hard";
@@ -7303,6 +7375,8 @@ function emptyGoal(goal) {
7303
7375
  lastActivityAt: now,
7304
7376
  iterations: 0,
7305
7377
  engineState: "idle",
7378
+ goalState: "active",
7379
+ todoAttempts: {},
7306
7380
  journal: []
7307
7381
  };
7308
7382
  }
@@ -7340,6 +7414,7 @@ function formatGoal(goal, journalLimit = 10) {
7340
7414
  lines.push(`Set: ${goal.setAt}`);
7341
7415
  lines.push(`Last activity: ${goal.lastActivityAt}`);
7342
7416
  lines.push(`Iterations: ${goal.iterations}`);
7417
+ lines.push(`Mission: ${goal.goalState ?? "active"}`);
7343
7418
  lines.push(`Engine: ${goal.engineState}`);
7344
7419
  const usage = summarizeUsage(goal);
7345
7420
  if (usage.iterationsWithUsage > 0) {
@@ -7363,6 +7438,8 @@ function formatGoal(goal, journalLimit = 10) {
7363
7438
 
7364
7439
  // src/execution/eternal-autonomy.ts
7365
7440
  var execFileP = promisify(execFile);
7441
+ var BRAINSTORM_DONE = /* @__PURE__ */ Symbol("brainstorm-done");
7442
+ var GOAL_COMPLETE_MARKER = /^\s*\[goal[_\s-]?complete\]\s*$/im;
7366
7443
  var EternalAutonomyEngine = class {
7367
7444
  constructor(opts) {
7368
7445
  this.opts = opts;
@@ -7372,6 +7449,14 @@ var EternalAutonomyEngine = class {
7372
7449
  state = "idle";
7373
7450
  stopRequested = false;
7374
7451
  consecutiveFailures = 0;
7452
+ consecutiveBrainstormDone = 0;
7453
+ /**
7454
+ * Count of consecutive transient (recoverable) provider failures. Drives
7455
+ * the exponential backoff between iterations. Reset on the first
7456
+ * successful iteration so a single bad afternoon doesn't permanently
7457
+ * slow the loop down.
7458
+ */
7459
+ consecutiveTransientRetries = 0;
7375
7460
  currentCtrl = null;
7376
7461
  iterationsSinceCompact = 0;
7377
7462
  goalPath;
@@ -7441,9 +7526,16 @@ var EternalAutonomyEngine = class {
7441
7526
  this.stopRequested = true;
7442
7527
  return false;
7443
7528
  }
7529
+ const missionState = goal.goalState ?? "active";
7530
+ if (missionState !== "active") {
7531
+ this.stopRequested = true;
7532
+ return false;
7533
+ }
7444
7534
  const action = await this.decide(goal);
7445
7535
  if (!action) {
7446
- await sleep(5e3);
7536
+ if (!this.stopRequested) {
7537
+ await sleep(5e3);
7538
+ }
7447
7539
  return false;
7448
7540
  }
7449
7541
  const ctrl = new AbortController();
@@ -7454,13 +7546,29 @@ var EternalAutonomyEngine = class {
7454
7546
  );
7455
7547
  let status = "success";
7456
7548
  let note;
7549
+ let finalText = "";
7550
+ let isTransientFailure = false;
7457
7551
  const tc = this.opts.agent.ctx?.tokenCounter;
7458
7552
  const beforeUsage = tc?.total?.();
7459
7553
  const beforeCost = tc?.estimateCost?.().total;
7460
7554
  try {
7461
7555
  const result = await this.opts.agent.run(
7462
7556
  [{ type: "text", text: action.directive }],
7463
- { signal: ctrl.signal }
7557
+ {
7558
+ signal: ctrl.signal,
7559
+ // Enable per-call autonomous continuation so the agent can chain
7560
+ // multiple internal tool/response cycles end-to-end on one
7561
+ // directive instead of returning to the engine after a single
7562
+ // round-trip. The model uses `[continue]` / `[done]` markers
7563
+ // (or the `continue_to_next_iteration` tool) to control the
7564
+ // inner loop. Without this flag the engine produced shallow
7565
+ // iterations and almost never let a real task finish.
7566
+ autonomousContinue: true,
7567
+ // Cap the inner loop so a runaway agent.run can't burn through
7568
+ // the iteration timeout — the engine's own outer loop is the
7569
+ // long-running thing, each tick should be bounded.
7570
+ maxIterations: this.opts.iterationMaxAgentSteps ?? 50
7571
+ }
7464
7572
  );
7465
7573
  if (result.status === "aborted") {
7466
7574
  status = "aborted";
@@ -7468,22 +7576,30 @@ var EternalAutonomyEngine = class {
7468
7576
  } else if (result.status === "failed") {
7469
7577
  status = "failure";
7470
7578
  note = result.error?.describe?.() ?? "agent run failed";
7579
+ isTransientFailure = result.error?.recoverable === true;
7471
7580
  } else if (result.status === "max_iterations") {
7472
7581
  status = "failure";
7473
7582
  note = `max iterations (${result.iterations})`;
7474
7583
  } else {
7475
7584
  status = "success";
7476
- const tail = (result.finalText ?? "").slice(0, 240).replace(/\s+/g, " ").trim();
7585
+ finalText = result.finalText ?? "";
7586
+ const tail = finalText.slice(0, 240).replace(/\s+/g, " ").trim();
7477
7587
  if (tail) note = tail;
7478
7588
  }
7479
7589
  } catch (err) {
7480
7590
  const isAbort = err instanceof Error && (err.name === "AbortError" || err.message.includes("abort"));
7481
7591
  status = isAbort ? "aborted" : "failure";
7482
7592
  note = err instanceof Error ? err.message : String(err);
7593
+ if (!isAbort && typeof err?.recoverable === "boolean") {
7594
+ isTransientFailure = err.recoverable;
7595
+ }
7483
7596
  } finally {
7484
7597
  clearTimeout(timer);
7485
7598
  this.currentCtrl = null;
7486
7599
  }
7600
+ if (action.source === "todo" && action.todoId && status !== "success") {
7601
+ await this.bumpTodoAttempt(action.todoId);
7602
+ }
7487
7603
  const afterUsage = tc?.total?.();
7488
7604
  const afterCost = tc?.estimateCost?.().total;
7489
7605
  const tokens = beforeUsage && afterUsage ? {
@@ -7516,6 +7632,14 @@ var EternalAutonomyEngine = class {
7516
7632
  costUsd
7517
7633
  });
7518
7634
  if (status === "failure") {
7635
+ if (isTransientFailure) {
7636
+ this.consecutiveTransientRetries++;
7637
+ const delay = this.computeTransientBackoffMs();
7638
+ if (delay > 0) {
7639
+ await this.sleepInterruptible(delay);
7640
+ }
7641
+ return false;
7642
+ }
7519
7643
  this.consecutiveFailures++;
7520
7644
  return false;
7521
7645
  }
@@ -7524,6 +7648,12 @@ var EternalAutonomyEngine = class {
7524
7648
  this.consecutiveFailures++;
7525
7649
  return false;
7526
7650
  }
7651
+ this.consecutiveTransientRetries = 0;
7652
+ if (GOAL_COMPLETE_MARKER.test(finalText)) {
7653
+ await this.markGoalCompleted(action, finalText);
7654
+ this.stopRequested = true;
7655
+ return true;
7656
+ }
7527
7657
  this.iterationsSinceCompact++;
7528
7658
  await this.maybeCompact().catch((err) => {
7529
7659
  this.opts.onError?.(
@@ -7587,11 +7717,12 @@ var EternalAutonomyEngine = class {
7587
7717
  async decide(goal) {
7588
7718
  const forceBrainstorm = this.consecutiveFailures >= (this.opts.failureBudget ?? 3);
7589
7719
  if (!forceBrainstorm) {
7590
- const todo = this.pickPendingTodo();
7720
+ const todo = this.pickPendingTodo(goal);
7591
7721
  if (todo) {
7592
7722
  return {
7593
7723
  source: "todo",
7594
7724
  task: todo.content,
7725
+ todoId: todo.id,
7595
7726
  directive: this.buildDirective(goal, "todo", todo.content)
7596
7727
  };
7597
7728
  }
@@ -7605,17 +7736,38 @@ var EternalAutonomyEngine = class {
7605
7736
  }
7606
7737
  }
7607
7738
  const brainstormed = await this.brainstormTask(goal);
7739
+ if (brainstormed === BRAINSTORM_DONE) {
7740
+ this.consecutiveBrainstormDone++;
7741
+ const threshold = this.opts.brainstormDoneStopThreshold ?? 3;
7742
+ if (this.consecutiveBrainstormDone >= threshold) {
7743
+ await this.markGoalCompleted(
7744
+ { source: "brainstorm", task: "no further work", directive: "" },
7745
+ `brainstorm returned DONE ${this.consecutiveBrainstormDone}x in a row`
7746
+ );
7747
+ this.stopRequested = true;
7748
+ }
7749
+ return null;
7750
+ }
7608
7751
  if (!brainstormed) return null;
7752
+ this.consecutiveBrainstormDone = 0;
7609
7753
  return {
7610
7754
  source: "brainstorm",
7611
7755
  task: brainstormed,
7612
7756
  directive: this.buildDirective(goal, "brainstorm", brainstormed)
7613
7757
  };
7614
7758
  }
7615
- pickPendingTodo() {
7759
+ pickPendingTodo(goal) {
7616
7760
  const todos = this.opts.agent.ctx.todos;
7617
7761
  if (!Array.isArray(todos)) return null;
7618
- return todos.find((t2) => t2.status === "pending") ?? null;
7762
+ const attempts = goal.todoAttempts ?? {};
7763
+ const ceiling = this.opts.todoMaxAttempts ?? 3;
7764
+ for (const t2 of todos) {
7765
+ if (t2.status !== "pending") continue;
7766
+ const used = attempts[t2.id] ?? 0;
7767
+ if (used >= ceiling) continue;
7768
+ return t2;
7769
+ }
7770
+ return null;
7619
7771
  }
7620
7772
  async pickGitTask() {
7621
7773
  let out;
@@ -7652,7 +7804,10 @@ ${lastFew}` : "No prior iterations yet.",
7652
7804
  "- One sentence, imperative form, under 200 chars.",
7653
7805
  "- No preamble, no explanation, no markdown \u2014 just the task line.",
7654
7806
  "- If recent iterations show repeated failures on the same target, pivot.",
7655
- "- If the goal appears fully accomplished, output exactly: DONE"
7807
+ "- If the goal appears fully accomplished AND you can name a concrete",
7808
+ " artifact / test / output that proves it, output exactly: DONE",
7809
+ "- Be conservative with DONE: if the recent journal contains failures",
7810
+ " or aborted entries, the goal is almost certainly NOT done."
7656
7811
  ].join("\n");
7657
7812
  try {
7658
7813
  const ctrl = new AbortController();
@@ -7664,9 +7819,11 @@ ${lastFew}` : "No prior iterations yet.",
7664
7819
  );
7665
7820
  if (result.status !== "done") return null;
7666
7821
  const text = (result.finalText ?? "").trim();
7667
- if (!text || text === "DONE") return null;
7822
+ if (!text) return null;
7823
+ if (/^DONE\.?$/i.test(text)) return BRAINSTORM_DONE;
7668
7824
  const firstLine = text.split("\n").find((l) => l.trim().length > 0)?.trim();
7669
7825
  if (!firstLine) return null;
7826
+ if (/^DONE\.?$/i.test(firstLine)) return BRAINSTORM_DONE;
7670
7827
  return firstLine.slice(0, 240);
7671
7828
  } finally {
7672
7829
  clearTimeout(timer);
@@ -7676,19 +7833,82 @@ ${lastFew}` : "No prior iterations yet.",
7676
7833
  }
7677
7834
  }
7678
7835
  buildDirective(goal, source, task) {
7836
+ const recentJournal = goal.journal.slice(-5).map((e) => ` #${e.iteration} [${e.status}] ${e.task}${e.note ? ` \u2014 ${e.note.slice(0, 80)}` : ""}`).join("\n");
7679
7837
  return [
7680
- "[ETERNAL AUTONOMY \u2014 iteration directive]",
7838
+ "\u2550\u2550\u2550 ETERNAL AUTONOMY \u2014 iteration directive \u2550\u2550\u2550",
7681
7839
  "",
7682
- `Goal: ${goal.goal}`,
7840
+ `Mission: ${goal.goal}`,
7841
+ `Iteration: #${goal.iterations + 1}`,
7683
7842
  `Source: ${source}`,
7684
7843
  `Task: ${task}`,
7685
7844
  "",
7686
- "Execute this task end-to-end using the tools available to you. Make the",
7687
- "changes, run tests if relevant, and commit / push as appropriate. Do not",
7688
- "ask for confirmation \u2014 YOLO mode is active. When the task is done, stop;",
7689
- "the loop will pick the next action."
7845
+ recentJournal ? `Recent journal (last 5):
7846
+ ${recentJournal}` : "No prior iterations.",
7847
+ "",
7848
+ "\u2500\u2500 EXECUTION PROTOCOL \u2500\u2500",
7849
+ "You are inside a long-running autonomous loop. Each iteration you",
7850
+ "execute ONE concrete task that advances the Mission. No user is",
7851
+ "available to clarify \u2014 make defensible decisions and move forward.",
7852
+ "",
7853
+ "1. EXECUTE END-TO-END",
7854
+ " \u2022 Use multiple tool calls freely. Emit `[continue]` on its own line",
7855
+ " to chain to the next internal step without returning.",
7856
+ " \u2022 When this iteration's Task is finished (real artifact / passing",
7857
+ " test / applied diff / clean output), emit `[done]` on its own line.",
7858
+ " \u2022 Do not stop on the first obstacle \u2014 try at least 3 distinct",
7859
+ " approaches before giving up. YOLO is active; no confirmations.",
7860
+ "",
7861
+ "2. UPDATE TODO STATE (when Source is `todo`)",
7862
+ " \u2022 Mark this todo `in_progress` via the todos tool before tool work.",
7863
+ " \u2022 Mark it `completed` on success, with a one-line outcome note.",
7864
+ " \u2022 If you cannot make progress after 2 distinct attempts, mark it",
7865
+ " `cancelled` with the obstacle. The loop will skip it next time.",
7866
+ "",
7867
+ "3. MISSION-COMPLETE PROTOCOL",
7868
+ " \u2022 If \u2014 and ONLY if \u2014 the OVERALL Mission (not just this Task) is",
7869
+ " verifiably accomplished, emit on its own line:",
7870
+ " [GOAL_COMPLETE]",
7871
+ " followed by a one-paragraph verification recipe (artifact path,",
7872
+ " test command, or 10-second reproduction). This halts the loop.",
7873
+ " \u2022 NEVER emit [GOAL_COMPLETE] on optimism, partial progress, or",
7874
+ ' "looks fine". Required: a concrete artifact that proves it AND',
7875
+ " no recent journal failures contradicting completion.",
7876
+ " \u2022 If unsure, emit `[done]` instead and let the next iteration",
7877
+ " decide. The loop is patient; false completion is not.",
7878
+ "",
7879
+ "4. NO INTERACTIVITY",
7880
+ " \u2022 Do not ask questions, do not request confirmation, do not propose",
7881
+ " options. Pick the best path and execute. The user is asleep."
7690
7882
  ].join("\n");
7691
7883
  }
7884
+ /**
7885
+ * Exponential backoff for transient provider errors. `2^N * base`
7886
+ * capped at `transientBackoffMaxMs`. Zero base disables backoff.
7887
+ * Public-private to keep `runOneIteration` readable; the value is
7888
+ * recomputed each call from the current retry count, so callers
7889
+ * don't have to track state.
7890
+ */
7891
+ computeTransientBackoffMs() {
7892
+ const base = this.opts.transientBackoffBaseMs ?? 2e3;
7893
+ const cap = this.opts.transientBackoffMaxMs ?? 6e4;
7894
+ if (base <= 0) return 0;
7895
+ const exponent = Math.max(0, this.consecutiveTransientRetries - 1);
7896
+ return Math.min(cap, base * Math.pow(2, exponent));
7897
+ }
7898
+ /**
7899
+ * Sleep that wakes early if `stopRequested` flips. Polls every 250 ms
7900
+ * so SIGINT / `/autonomy stop` can land in the middle of a long
7901
+ * backoff instead of waiting up to a minute for the timer.
7902
+ */
7903
+ async sleepInterruptible(totalMs) {
7904
+ const step = 250;
7905
+ let remaining = totalMs;
7906
+ while (remaining > 0 && !this.stopRequested) {
7907
+ const chunk = Math.min(step, remaining);
7908
+ await sleep(chunk);
7909
+ remaining -= chunk;
7910
+ }
7911
+ }
7692
7912
  async appendIterationEntry(entry) {
7693
7913
  const current = await loadGoal(this.goalPath);
7694
7914
  if (!current) {
@@ -7697,6 +7917,39 @@ ${lastFew}` : "No prior iterations yet.",
7697
7917
  const updated = appendJournal(current, entry);
7698
7918
  await saveGoal(this.goalPath, updated);
7699
7919
  }
7920
+ /**
7921
+ * Persistent per-todo failure counter. Skipped silently when the goal
7922
+ * file has been removed (graceful clear). Each non-success iteration
7923
+ * against a todo source bumps the counter by 1; `pickPendingTodo` reads
7924
+ * the counter to rotate past stuck todos once they cross `todoMaxAttempts`.
7925
+ */
7926
+ async bumpTodoAttempt(todoId) {
7927
+ const current = await loadGoal(this.goalPath);
7928
+ if (!current) return;
7929
+ const attempts = { ...current.todoAttempts ?? {} };
7930
+ attempts[todoId] = (attempts[todoId] ?? 0) + 1;
7931
+ await saveGoal(this.goalPath, { ...current, todoAttempts: attempts });
7932
+ }
7933
+ /**
7934
+ * Flip the mission to `completed` and journal it. Called from two
7935
+ * paths: (a) `[GOAL_COMPLETE]` marker in a successful iteration's
7936
+ * finalText, (b) `brainstorm` returning DONE consecutively past the
7937
+ * configured threshold. Idempotent — re-entry is a no-op once the
7938
+ * goal is already `completed`.
7939
+ */
7940
+ async markGoalCompleted(action, note) {
7941
+ const current = await loadGoal(this.goalPath);
7942
+ if (!current) return;
7943
+ if (current.goalState === "completed") return;
7944
+ const withFlag = { ...current, goalState: "completed" };
7945
+ const withEntry = appendJournal(withFlag, {
7946
+ source: action.source,
7947
+ task: `MISSION COMPLETE \u2014 ${action.task}`.slice(0, 240),
7948
+ status: "success",
7949
+ note: note.slice(0, 240)
7950
+ });
7951
+ await saveGoal(this.goalPath, withEntry);
7952
+ }
7700
7953
  async appendFailure(task, note) {
7701
7954
  await this.appendIterationEntry({ source: "manual", task, status: "failure", note });
7702
7955
  }
@@ -7711,6 +7964,142 @@ function sleep(ms) {
7711
7964
  return new Promise((resolve5) => setTimeout(resolve5, ms));
7712
7965
  }
7713
7966
 
7967
+ // src/execution/autonomy-prompt-contributor.ts
7968
+ function makeAutonomyPromptContributor(opts) {
7969
+ return async (ctx) => {
7970
+ if (ctx.subagent) return [];
7971
+ if (!opts.enabled()) return [];
7972
+ let goal;
7973
+ try {
7974
+ goal = await loadGoal(opts.goalPath);
7975
+ } catch {
7976
+ return [];
7977
+ }
7978
+ if (!goal) return [];
7979
+ const missionState = goal.goalState ?? "active";
7980
+ if (missionState !== "active") return [];
7981
+ const tailSize = opts.journalTailSize ?? 5;
7982
+ const journalTail = goal.journal.slice(-tailSize).map((e) => {
7983
+ const note = e.note ? ` \u2014 ${e.note.slice(0, 80)}` : "";
7984
+ return ` #${e.iteration} [${e.status}] ${e.task}${note}`;
7985
+ });
7986
+ const text = [
7987
+ "## ETERNAL AUTONOMY \u2014 active mission",
7988
+ "",
7989
+ "You are inside a long-running autonomous loop. The user is asleep",
7990
+ "and is not available to confirm decisions. Each turn you receive a",
7991
+ "directive describing one concrete sub-task that advances the mission.",
7992
+ "",
7993
+ `Mission: ${goal.goal}`,
7994
+ `Iteration: #${goal.iterations}`,
7995
+ journalTail.length > 0 ? `Recent journal (last ${journalTail.length}):
7996
+ ${journalTail.join("\n")}` : "Recent journal: (none \u2014 this is the first iteration)",
7997
+ "",
7998
+ "### Loop control markers",
7999
+ "Emit these on their own line in your final text \u2014 case-insensitive,",
8000
+ "whitespace-tolerant, but they must occupy the entire line:",
8001
+ "- `[continue]` \u2014 chain to the next internal step without returning.",
8002
+ "- `[done]` \u2014 the current sub-task is finished; return to the engine.",
8003
+ "- `[GOAL_COMPLETE]` \u2014 emit ONLY when the OVERALL mission is",
8004
+ " verifiably done. Must be followed by a one-paragraph verification",
8005
+ " recipe (artifact path, test command, or 10-second reproduction).",
8006
+ " The engine halts on this marker \u2014 false positives waste real",
8007
+ " human time. If unsure, emit `[done]` and let the next iteration",
8008
+ " decide.",
8009
+ "",
8010
+ "### Operating principles",
8011
+ "- YOLO is active. Do NOT ask for confirmation, do NOT propose",
8012
+ " options. Pick the best path and execute it.",
8013
+ "- Use tools freely; multiple calls per turn are normal and expected.",
8014
+ "- When working on a todo, mark it `in_progress` via the todos tool",
8015
+ " before tool work and `completed` (or `cancelled` with a reason)",
8016
+ " when done. The loop reads todo state between iterations.",
8017
+ "- If an approach fails twice in a row, pivot. Don't grind on the",
8018
+ " same wall \u2014 try a different angle, file a cancel on the todo, or",
8019
+ " surface the obstacle via `[done]` and let the next iteration",
8020
+ " re-plan."
8021
+ ].join("\n");
8022
+ return [
8023
+ {
8024
+ type: "text",
8025
+ text,
8026
+ cache_control: { type: "ephemeral" }
8027
+ }
8028
+ ];
8029
+ };
8030
+ }
8031
+
8032
+ // src/execution/goal-preamble.ts
8033
+ function buildGoalPreamble(goal) {
8034
+ return [
8035
+ "[GOAL \u2014 LOCKED IN. You will work on this until it is verifiably done.",
8036
+ "The user granted you full autonomy. Read these constraints once, then act.",
8037
+ "",
8038
+ "YOUR GOAL:",
8039
+ "---",
8040
+ goal,
8041
+ "---",
8042
+ "",
8043
+ "AUTHORITY YOU HAVE:",
8044
+ "- Spawn as many subagents as the work needs (delegate / spawn_subagent).",
8045
+ " Parallel + recursive fan-out are both fine. There is no spawn budget.",
8046
+ "- Use any provider/model per subagent \u2014 pick the right tool for each",
8047
+ " piece of work. Heavy reasoning model for planning, fast model for",
8048
+ " batch work, specialist model for domain code.",
8049
+ "- Run unlimited tool calls and iterations. There is NO hidden budget.",
8050
+ " The Agent loop auto-extends every 100 iterations forever.",
8051
+ "- Retry failed tools with different inputs, alternative paths, fresh",
8052
+ " subagents. Switch providers mid-run if one is rate-limited.",
8053
+ "- Re-plan freely when an approach hits a dead end. You are not obliged",
8054
+ " to stick with the first plan you proposed.",
8055
+ "",
8056
+ 'WHAT "DONE" MEANS \u2014 non-negotiable:',
8057
+ "- You can name a concrete artifact (a passing test, a written file at",
8058
+ " a specific path, a fixed bug verified by re-running the failing case,",
8059
+ " a clean grep that previously had matches).",
8060
+ "- You can tell the user HOW to verify it themselves in 10 seconds.",
8061
+ '- You have NOT hedged. None of: "looks like it should work", "I',
8062
+ ' believe this fixes it", "the changes appear correct".',
8063
+ "",
8064
+ "WHAT IS NOT DONE \u2014 never report any of these as completion:",
8065
+ "- An error message you didn't recover from.",
8066
+ '- An empty result, a 0-line file, a "no matches found" you accepted',
8067
+ " without questioning the search.",
8068
+ '- "Should I continue?" / "Want me to also...?" / "Let me know if you',
8069
+ ' want X." Those are hedges. The user already told you to finish the',
8070
+ " goal \u2014 just do it.",
8071
+ "- Partial progress dressed up as success. Fixed 3 of 5 bugs = 60%",
8072
+ " done, not done.",
8073
+ "- A subagent's failed/timeout/stopped TaskResult that you didn't",
8074
+ " respond to with a fresh attempt (different role, different model,",
8075
+ " tighter prompt).",
8076
+ "",
8077
+ "PERSISTENCE PROTOCOL:",
8078
+ "- If blocked, try at least 3 different angles before reporting the",
8079
+ " problem to the user. Different tool inputs, different subagent",
8080
+ " roles, different providers, different decomposition of the task.",
8081
+ "- If a tool fails, read its error, alter the input, try again. Do",
8082
+ " not just report the failure back.",
8083
+ "- If a subagent returns useless output, respawn with a tighter prompt",
8084
+ ' or a different role. Do not accept "I could not determine\u2026" as the',
8085
+ " final answer.",
8086
+ "- Use `ask_subagent` for one-shot questions when you don't need a",
8087
+ " full delegated task.",
8088
+ "",
8089
+ "REPORTING:",
8090
+ "- Stream short progress notes between major actions so the user can",
8091
+ " monitor. Do not go silent for 50 tool calls then dump a wall of",
8092
+ " text \u2014 but also do not narrate every tool call.",
8093
+ "- Use the shared scratchpad (if available) to leave breadcrumbs",
8094
+ " subagents can read.",
8095
+ "- Final response must include: (a) what was accomplished, (b) how",
8096
+ " to verify, (c) any caveats (residual TODOs, things the user",
8097
+ " should know about).",
8098
+ "",
8099
+ "BEGIN.]"
8100
+ ].join("\n");
8101
+ }
8102
+
7714
8103
  // src/coordination/director.ts
7715
8104
  init_atomic_write();
7716
8105
 
@@ -7823,40 +8212,12 @@ var FleetBus = class {
7823
8212
  * subagent teardown so the listeners don't outlive the run.
7824
8213
  */
7825
8214
  attach(subagentId, bus, taskId) {
7826
- const FORWARDED_TYPES = [
7827
- "tool.started",
7828
- "tool.executed",
7829
- "tool.progress",
7830
- "tool.confirm_needed",
7831
- "iteration.started",
7832
- "iteration.completed",
7833
- "provider.text_delta",
7834
- // Subagent extended-thinking output. Forwarded so the FleetPanel /
7835
- // /fleet log can surface "the planner is thinking…" instead of a
7836
- // silent gap between iteration.started and the first text_delta.
7837
- "provider.thinking_delta",
7838
- "provider.response",
7839
- "provider.retry",
7840
- "provider.error",
7841
- "session.started",
7842
- "session.ended",
7843
- "session.damaged",
7844
- "compaction.fired",
7845
- "compaction.failed",
7846
- "token.threshold",
7847
- // Subagent hit a soft budget limit — coordinator can extend or stop.
7848
- "budget.threshold_reached"
7849
- ];
7850
- const offs = [];
7851
- for (const t2 of FORWARDED_TYPES) {
7852
- offs.push(
7853
- bus.on(t2, (payload) => {
7854
- this.emit({ subagentId, taskId, ts: Date.now(), type: t2, payload });
7855
- })
7856
- );
7857
- }
8215
+ const off = bus.onPattern("*", (type, payload) => {
8216
+ if (type.startsWith("subagent.")) return;
8217
+ this.emit({ subagentId, taskId, ts: Date.now(), type, payload });
8218
+ });
7858
8219
  return () => {
7859
- for (const off of offs) off();
8220
+ off();
7860
8221
  };
7861
8222
  }
7862
8223
  /** Subscribe to every event from one subagent. */
@@ -8021,7 +8382,7 @@ var BudgetThresholdSignal = class extends Error {
8021
8382
  this.decision = decision;
8022
8383
  }
8023
8384
  };
8024
- var SubagentBudget = class {
8385
+ var SubagentBudget = class _SubagentBudget {
8025
8386
  limits;
8026
8387
  iterations = 0;
8027
8388
  toolCalls = 0;
@@ -8030,6 +8391,26 @@ var SubagentBudget = class {
8030
8391
  costUsd = 0;
8031
8392
  startTime = null;
8032
8393
  _onThreshold;
8394
+ /**
8395
+ * Tracks which budget kinds currently have an extension request
8396
+ * in flight. While a kind is here, further `checkLimit` calls for the
8397
+ * same kind are no-ops — without this dedup, every `recordIteration`
8398
+ * after the limit is reached spawns a fresh decision Promise (until
8399
+ * the first one lands and patches limits), flooding the FleetBus
8400
+ * with redundant threshold events. Cleared in `checkLimitAsync`'s
8401
+ * `finally`.
8402
+ */
8403
+ pendingExtensions = /* @__PURE__ */ new Set();
8404
+ /**
8405
+ * Hard cap on how long `checkLimitAsync` waits for the coordinator to
8406
+ * respond before defaulting to 'stop'. Without this fallback an absent
8407
+ * or hung listener (Director not built / event filter detached mid-run)
8408
+ * leaves the budget over-limit and never enforces anything, since
8409
+ * `checkLimit` returns synchronously via `void this.checkLimitAsync`.
8410
+ * Hardcoded for now — most fleets set their own per-task timeout that
8411
+ * dwarfs this anyway. 30 s matches the existing event-emit timeoutMs.
8412
+ */
8413
+ static DECISION_TIMEOUT_MS = 3e4;
8033
8414
  /**
8034
8415
  * Injected by the runner when wiring the budget to its EventBus.
8035
8416
  * Used by `checkLimitAsync` to emit `budget.threshold_reached` events.
@@ -8072,56 +8453,92 @@ var SubagentBudget = class {
8072
8453
  if (kind === "timeout" || !this._onThreshold) {
8073
8454
  throw new BudgetExceededError(kind, limit, used);
8074
8455
  }
8075
- void this.checkLimitAsync(kind, used, limit);
8456
+ const bus = this._events;
8457
+ if (!bus || bus.listenerCount("budget.threshold_reached") === 0) {
8458
+ throw new BudgetExceededError(kind, limit, used);
8459
+ }
8460
+ if (this.pendingExtensions.has(kind)) return;
8461
+ this.pendingExtensions.add(kind);
8462
+ const decision = this.negotiateExtension(kind, used, limit);
8463
+ throw new BudgetThresholdSignal(kind, limit, used, decision);
8076
8464
  }
8077
8465
  /**
8078
- * Async threshold negotiation with the coordinator. Fire-and-forget
8079
- * any error thrown here becomes an unhandled rejection in the test environment
8080
- * because the runner's catch only handles the synchronous throw from `checkLimit`.
8466
+ * Drive the threshold handler to a decision. Resolves with `'stop'`
8467
+ * (signal the runner to abort) or `{ extend: ... }` (limits already
8468
+ * patched in-place; the runner should not abort). Always releases the
8469
+ * `pendingExtensions` slot in `finally`.
8470
+ *
8471
+ * The 'continue' return from a sync handler is treated as
8472
+ * `{ extend: {} }` — keep going without patching, next overrun will
8473
+ * fire a fresh signal.
8081
8474
  */
8082
- async checkLimitAsync(kind, used, limit) {
8083
- const result = this._onThreshold({
8084
- kind,
8085
- used,
8086
- limit,
8087
- // Inject a requestDecision helper the handler can call to emit the
8088
- // budget.threshold_reached event and wait for the coordinator's verdict.
8089
- // The runner wires this by injecting its EventBus into ctx.budget._events.
8090
- requestDecision: () => {
8091
- return new Promise((resolve5) => {
8092
- this._events?.emit("budget.threshold_reached", {
8093
- kind,
8094
- used,
8095
- limit,
8096
- timeoutMs: 3e4,
8097
- extend: (extra) => resolve5({ extend: extra }),
8098
- deny: () => resolve5("stop")
8475
+ async negotiateExtension(kind, used, limit) {
8476
+ try {
8477
+ const result = this._onThreshold({
8478
+ kind,
8479
+ used,
8480
+ limit,
8481
+ // Inject a requestDecision helper the handler can call to emit the
8482
+ // budget.threshold_reached event and wait for the coordinator's verdict.
8483
+ // A hard fallback timer guarantees the promise eventually resolves
8484
+ // even if no listener responds — without it, an absent/detached
8485
+ // Director would leave the budget permanently in "asking" state.
8486
+ requestDecision: () => {
8487
+ const bus = this._events;
8488
+ if (!bus || bus.listenerCount("budget.threshold_reached") === 0) {
8489
+ return Promise.resolve("stop");
8490
+ }
8491
+ return new Promise((resolve5) => {
8492
+ let resolved = false;
8493
+ const respond = (d) => {
8494
+ if (resolved) return;
8495
+ resolved = true;
8496
+ resolve5(d);
8497
+ };
8498
+ const fallback = setTimeout(
8499
+ () => respond("stop"),
8500
+ _SubagentBudget.DECISION_TIMEOUT_MS
8501
+ );
8502
+ bus.emit("budget.threshold_reached", {
8503
+ kind,
8504
+ used,
8505
+ limit,
8506
+ timeoutMs: _SubagentBudget.DECISION_TIMEOUT_MS,
8507
+ extend: (extra) => {
8508
+ clearTimeout(fallback);
8509
+ respond({ extend: extra });
8510
+ },
8511
+ deny: () => {
8512
+ clearTimeout(fallback);
8513
+ respond("stop");
8514
+ }
8515
+ });
8099
8516
  });
8100
- });
8517
+ }
8518
+ });
8519
+ if (result === "throw") return "stop";
8520
+ if (result === "continue") return { extend: {} };
8521
+ const decision = await result;
8522
+ if (decision === "stop") return "stop";
8523
+ const ext = decision.extend;
8524
+ if (ext.maxIterations !== void 0) {
8525
+ this.limits.maxIterations = ext.maxIterations;
8101
8526
  }
8102
- });
8103
- if (result === "throw") {
8104
- throw new BudgetExceededError(kind, limit, used);
8105
- }
8106
- if (result === "continue") {
8107
- return;
8108
- }
8109
- const decision = await result;
8110
- if (decision === "stop") {
8111
- throw new BudgetExceededError(kind, limit, used);
8112
- }
8113
- const ext = decision.extend;
8114
- if (ext.maxIterations !== void 0) {
8115
- this.limits.maxIterations = ext.maxIterations;
8116
- }
8117
- if (ext.maxToolCalls !== void 0) {
8118
- this.limits.maxToolCalls = ext.maxToolCalls;
8119
- }
8120
- if (ext.maxTokens !== void 0) {
8121
- this.limits.maxTokens = ext.maxTokens;
8122
- }
8123
- if (ext.maxCostUsd !== void 0) {
8124
- this.limits.maxCostUsd = ext.maxCostUsd;
8527
+ if (ext.maxToolCalls !== void 0) {
8528
+ this.limits.maxToolCalls = ext.maxToolCalls;
8529
+ }
8530
+ if (ext.maxTokens !== void 0) {
8531
+ this.limits.maxTokens = ext.maxTokens;
8532
+ }
8533
+ if (ext.maxCostUsd !== void 0) {
8534
+ this.limits.maxCostUsd = ext.maxCostUsd;
8535
+ }
8536
+ if (ext.timeoutMs !== void 0) {
8537
+ this.limits.timeoutMs = ext.timeoutMs;
8538
+ }
8539
+ return decision;
8540
+ } finally {
8541
+ this.pendingExtensions.delete(kind);
8125
8542
  }
8126
8543
  }
8127
8544
  recordIteration() {
@@ -8404,6 +8821,19 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
8404
8821
  setRunner(runner) {
8405
8822
  this.runner = runner;
8406
8823
  }
8824
+ /**
8825
+ * Change the in-flight dispatch ceiling at runtime. Lowering does NOT
8826
+ * preempt running tasks — already-dispatched subagents finish their
8827
+ * current task; only future dispatches respect the new cap. Raising
8828
+ * immediately tries to fill the freed slots from the pending queue.
8829
+ */
8830
+ setMaxConcurrent(n) {
8831
+ if (!Number.isFinite(n) || n < 1) {
8832
+ throw new Error(`maxConcurrent must be a finite integer >= 1, got ${n}`);
8833
+ }
8834
+ this.config.maxConcurrent = Math.floor(n);
8835
+ this.tryDispatchNext();
8836
+ }
8407
8837
  async spawn(subagent) {
8408
8838
  const id = subagent.id || randomUUID();
8409
8839
  if (this.subagents.has(id)) {
@@ -8663,14 +9093,65 @@ var DefaultMultiAgentCoordinator = class extends EventEmitter {
8663
9093
  this.recordCompletion(result);
8664
9094
  }
8665
9095
  async executeWithTimeout(runner, task, ctx, budget) {
8666
- const timeoutMs = budget.limits.timeoutMs;
8667
- if (timeoutMs === void 0) return runner(task, ctx);
9096
+ const initialTimeoutMs = budget.limits.timeoutMs;
9097
+ if (initialTimeoutMs === void 0) return runner(task, ctx);
9098
+ const start = Date.now();
8668
9099
  let timer = null;
8669
9100
  const timeoutPromise = new Promise((_, reject) => {
8670
- timer = setTimeout(() => {
8671
- this.subagents.get(ctx.subagentId)?.abortController.abort();
8672
- reject(new BudgetExceededError("timeout", timeoutMs, Date.now()));
8673
- }, timeoutMs);
9101
+ const armFor = (ms) => {
9102
+ if (timer) clearTimeout(timer);
9103
+ timer = setTimeout(async () => {
9104
+ const elapsed = Date.now() - start;
9105
+ const limit = budget.limits.timeoutMs ?? initialTimeoutMs;
9106
+ if (!budget.onThreshold) {
9107
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
9108
+ reject(new BudgetExceededError("timeout", limit, elapsed));
9109
+ return;
9110
+ }
9111
+ try {
9112
+ const result = budget.onThreshold({
9113
+ kind: "timeout",
9114
+ used: elapsed,
9115
+ limit,
9116
+ requestDecision: () => new Promise((resolveDecision) => {
9117
+ budget._events?.emit("budget.threshold_reached", {
9118
+ kind: "timeout",
9119
+ used: elapsed,
9120
+ limit,
9121
+ timeoutMs: 3e4,
9122
+ extend: (extra) => resolveDecision({ extend: extra }),
9123
+ deny: () => resolveDecision("stop")
9124
+ });
9125
+ })
9126
+ });
9127
+ const decision = typeof result === "string" ? result : await result;
9128
+ if (decision === "continue") {
9129
+ armFor(Math.max(1e3, limit));
9130
+ return;
9131
+ }
9132
+ if (decision === "throw" || decision === "stop") {
9133
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
9134
+ reject(new BudgetExceededError("timeout", limit, elapsed));
9135
+ return;
9136
+ }
9137
+ if (decision.extend.timeoutMs !== void 0) {
9138
+ budget.limits.timeoutMs = decision.extend.timeoutMs;
9139
+ const newLimit = decision.extend.timeoutMs;
9140
+ const remaining = Math.max(1e3, newLimit - elapsed);
9141
+ armFor(remaining);
9142
+ return;
9143
+ }
9144
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
9145
+ reject(new BudgetExceededError("timeout", limit, elapsed));
9146
+ } catch (err) {
9147
+ this.subagents.get(ctx.subagentId)?.abortController.abort();
9148
+ reject(
9149
+ err instanceof BudgetExceededError ? err : new BudgetExceededError("timeout", limit, elapsed)
9150
+ );
9151
+ }
9152
+ }, ms);
9153
+ };
9154
+ armFor(initialTimeoutMs);
8674
9155
  });
8675
9156
  try {
8676
9157
  return await Promise.race([runner(task, ctx), timeoutPromise]);
@@ -9281,7 +9762,7 @@ var Director = class {
9281
9762
  return;
9282
9763
  }
9283
9764
  extendCounts.set(guardKey, prior + 1);
9284
- setTimeout(() => {
9765
+ setImmediate(() => {
9285
9766
  const extra = {};
9286
9767
  switch (payload.kind) {
9287
9768
  case "iterations":
@@ -9296,9 +9777,12 @@ var Director = class {
9296
9777
  case "cost":
9297
9778
  extra.maxCostUsd = Math.min(payload.limit * 1.5, 10);
9298
9779
  break;
9780
+ case "timeout":
9781
+ extra.timeoutMs = Math.min(Math.ceil(payload.limit * 1.5), 60 * 6e4);
9782
+ break;
9299
9783
  }
9300
9784
  payload.extend(extra);
9301
- }, Math.min(payload.timeoutMs, 3e4));
9785
+ });
9302
9786
  });
9303
9787
  }
9304
9788
  /** Best-effort session-writer append. Swallows failures — the director
@@ -10093,6 +10577,7 @@ function makeAgentSubagentRunner(opts) {
10093
10577
  const detachFleet = opts.fleetBus?.attach(ctx.subagentId, events, task.id);
10094
10578
  const aborter = new AbortController();
10095
10579
  ctx.budget._events = events;
10580
+ ctx.budget.onThreshold = ({ requestDecision }) => requestDecision();
10096
10581
  let budgetError = null;
10097
10582
  const onBudgetError = (err) => {
10098
10583
  if (err instanceof BudgetThresholdSignal) {
@@ -12923,7 +13408,7 @@ function wireMetricsToEvents(events, sink) {
12923
13408
  events.on("token.threshold", (e) => sink.gauge("agent.tokens.used", e.used)),
12924
13409
  events.on("compaction.fired", (e) => {
12925
13410
  sink.counter("compaction.fired.total");
12926
- sink.histogram("compaction.reduction_tokens", e.before - e.after);
13411
+ sink.histogram("compaction.reduction_tokens", e.report.before - e.report.after);
12927
13412
  }),
12928
13413
  events.on(
12929
13414
  "mcp.server.connected",
@@ -16118,16 +16603,16 @@ Use \`/security report <number>\` to view a specific report.` };
16118
16603
  }
16119
16604
  const index = parseInt(reportId, 10) - 1;
16120
16605
  if (!isNaN(index) && reports[index]) {
16121
- const { readFile: readFile29 } = await import('fs/promises');
16122
- const content = await readFile29(join(reportsDir, reports[index]), "utf-8");
16606
+ const { readFile: readFile30 } = await import('fs/promises');
16607
+ const content = await readFile30(join(reportsDir, reports[index]), "utf-8");
16123
16608
  return { message: `# Security Report
16124
16609
 
16125
16610
  ${content}` };
16126
16611
  }
16127
16612
  const match = reports.find((r) => r.includes(reportId));
16128
16613
  if (match) {
16129
- const { readFile: readFile29 } = await import('fs/promises');
16130
- const content = await readFile29(join(reportsDir, match), "utf-8");
16614
+ const { readFile: readFile30 } = await import('fs/promises');
16615
+ const content = await readFile30(join(reportsDir, match), "utf-8");
16131
16616
  return { message: `# Security Report
16132
16617
 
16133
16618
  ${content}` };
@@ -16382,6 +16867,226 @@ var FleetManager = class {
16382
16867
  return { pending, live: [] };
16383
16868
  }
16384
16869
  };
16870
+ function createMcpControlTool(opts) {
16871
+ const { getConfig, configPath, registry } = opts;
16872
+ const inputSchema = {
16873
+ type: "object",
16874
+ properties: {
16875
+ action: {
16876
+ type: "string",
16877
+ enum: ["list", "search", "enable", "disable", "restart"],
16878
+ description: "The management action to perform."
16879
+ },
16880
+ /** Filter for `search`. Matches server name or description case-insensitively. */
16881
+ query: {
16882
+ type: "string",
16883
+ description: "Search term for `search` action. Matches server name or description."
16884
+ },
16885
+ /** Target server name for `enable`, `disable`, `restart`. */
16886
+ server: {
16887
+ type: "string",
16888
+ description: 'Server name (e.g. "github", "filesystem", "brave-search").'
16889
+ }
16890
+ },
16891
+ required: ["action"]
16892
+ };
16893
+ return {
16894
+ name: "mcp_control",
16895
+ description: "Manage MCP server lifecycle: list available servers, search by name or capability, enable or disable servers at runtime, restart running servers.",
16896
+ category: "mcp",
16897
+ permission: "auto",
16898
+ mutating: false,
16899
+ riskTier: "standard",
16900
+ inputSchema,
16901
+ async execute(raw, ctx) {
16902
+ const input = raw;
16903
+ return mcpControlDispatch(input, { getConfig, configPath, registry });
16904
+ }
16905
+ };
16906
+ }
16907
+ async function mcpControlDispatch(input, deps) {
16908
+ const { action, query, server } = input;
16909
+ switch (action) {
16910
+ case "list":
16911
+ return renderList(deps);
16912
+ case "search":
16913
+ return renderSearch(query ?? "", deps);
16914
+ case "enable":
16915
+ return runEnable(server, deps);
16916
+ case "disable":
16917
+ return runDisable(server, deps);
16918
+ case "restart":
16919
+ return runRestart(server, deps);
16920
+ default:
16921
+ return `Unknown action "${action}". Use one of: list, search, enable, disable, restart.`;
16922
+ }
16923
+ }
16924
+ function renderList(deps) {
16925
+ const configured = deps.getConfig().mcpServers ?? {};
16926
+ const live = deps.registry.describe();
16927
+ if (Object.keys(configured).length === 0) {
16928
+ return [
16929
+ "No MCP servers configured.",
16930
+ ' Use `mcp_control({ action: "search" })` to see available presets,',
16931
+ ' then `mcp_control({ action: "enable", server: "<name>" })` to add one.'
16932
+ ].join("\n");
16933
+ }
16934
+ const lines = [];
16935
+ const liveMap = new Map(live.map((s) => [s.name, s]));
16936
+ for (const [name, cfg] of Object.entries(configured)) {
16937
+ const liveInfo = liveMap.get(name);
16938
+ const toolCount = liveInfo ? ` (${liveInfo.toolCount} tools)` : "";
16939
+ const stateStr = liveInfo ? badge(liveInfo.state) : dim("\u25CB not loaded");
16940
+ const enabled = cfg.enabled === false ? `${dim("disabled")} ` : `${green("\u25CF enabled")} `;
16941
+ lines.push(` ${bold(name)} ${enabled}${stateStr}${toolCount}`);
16942
+ if (cfg.description) lines.push(` ${dim(cfg.description)}`);
16943
+ }
16944
+ lines.push("");
16945
+ lines.push(dim(' Use `mcp_control({ action: "search", query: "<keyword>" })` to find servers.'));
16946
+ lines.push(dim(' Use `mcp_control({ action: "enable", server: "<name>" })` to start a server.'));
16947
+ return lines.join("\n");
16948
+ }
16949
+ function renderSearch(query, deps) {
16950
+ const configured = deps.getConfig().mcpServers ?? {};
16951
+ const all = allServers();
16952
+ const q = query.toLowerCase();
16953
+ const configuredNames = new Set(Object.keys(configured));
16954
+ const configuredEntries = Object.entries(configured).filter(
16955
+ ([name, cfg]) => name.toLowerCase().includes(q) || (cfg.description ?? "").toLowerCase().includes(q)
16956
+ );
16957
+ const unconfiguredEntries = Object.entries(all).filter(([name]) => !configuredNames.has(name)).filter(
16958
+ ([name, cfg]) => name.toLowerCase().includes(q) || (cfg.description ?? "").toLowerCase().includes(q)
16959
+ );
16960
+ const lines = [];
16961
+ if (configuredEntries.length > 0) {
16962
+ lines.push(bold('Configured servers matching "') + query + '":');
16963
+ for (const [name, cfg] of configuredEntries) {
16964
+ lines.push(` ${bold(name)} ${cfg.description ?? cfg.transport}`);
16965
+ }
16966
+ lines.push("");
16967
+ }
16968
+ if (unconfiguredEntries.length > 0) {
16969
+ lines.push(bold('Available presets matching "') + query + '":');
16970
+ for (const [name, cfg] of unconfiguredEntries) {
16971
+ const warn = cfg.permission === "deny" ? red(" \u26A0 confirm required") : "";
16972
+ lines.push(` ${bold(name)} ${cfg.description ?? cfg.transport}${warn}`);
16973
+ }
16974
+ lines.push("");
16975
+ }
16976
+ if (configuredEntries.length === 0 && unconfiguredEntries.length === 0) {
16977
+ return `No servers match "${query}". Try a shorter keyword or \`mcp_control({ action: "list" })\`.`;
16978
+ }
16979
+ const total = configuredEntries.length + unconfiguredEntries.length;
16980
+ lines.push(dim(` ${total} server${total !== 1 ? "s" : ""} shown. Run \`enable\` on one to activate it.`));
16981
+ return lines.join("\n");
16982
+ }
16983
+ async function runEnable(name, deps) {
16984
+ if (!name) return '`server` is required for enable. Example: { action: "enable", server: "github" }';
16985
+ const all = allServers();
16986
+ const configured = deps.getConfig().mcpServers ?? {};
16987
+ const cfg = configured[name] ?? all[name];
16988
+ if (!cfg) {
16989
+ const known = Object.keys(all).join(", ");
16990
+ return `Unknown server "${name}". Available presets: ${known}`;
16991
+ }
16992
+ const full = await readConfig(deps.configPath);
16993
+ const mcpServers = {
16994
+ ...full.mcpServers ?? {}
16995
+ };
16996
+ mcpServers[name] = { ...cfg, enabled: true };
16997
+ full.mcpServers = mcpServers;
16998
+ await writeConfig(deps.configPath, full);
16999
+ try {
17000
+ const live = deps.registry.describe().find((s) => s.name === name);
17001
+ if (live && live.state === "connected") {
17002
+ return `${green("\u25CF")} Server "${name}" is already running (${live.toolCount} tools registered).`;
17003
+ }
17004
+ await deps.registry.start({ ...cfg, enabled: true });
17005
+ const updated = deps.registry.describe().find((s) => s.name === name);
17006
+ return `${green("\u2713 Enabled and started")} "${name}"${updated ? ` (${updated.toolCount} tools registered).` : "."}`;
17007
+ } catch (err) {
17008
+ return `${red("\u2717 Failed to start")} "${name}": ${err instanceof Error ? err.message : String(err)}`;
17009
+ }
17010
+ }
17011
+ async function runDisable(name, deps) {
17012
+ if (!name) return '`server` is required for disable. Example: { action: "disable", server: "github" }';
17013
+ const configured = deps.getConfig().mcpServers ?? {};
17014
+ if (!configured[name]) {
17015
+ return `Server "${name}" is not in config. Add it with \`mcp_control({ action: "enable", server: "${name}" })\`.`;
17016
+ }
17017
+ const full = await readConfig(deps.configPath);
17018
+ const mcpServers = {
17019
+ ...full.mcpServers ?? {}
17020
+ };
17021
+ const existing = mcpServers[name];
17022
+ mcpServers[name] = { ...existing, enabled: false };
17023
+ full.mcpServers = mcpServers;
17024
+ await writeConfig(deps.configPath, full);
17025
+ try {
17026
+ await deps.registry.stop(name);
17027
+ return `${yellow("\u25CB Disabled")} "${name}". It will not be started on next boot.`;
17028
+ } catch {
17029
+ return `${yellow("\u25CB Disabled")} "${name}" (it was not running). Config updated.`;
17030
+ }
17031
+ }
17032
+ async function runRestart(name, deps) {
17033
+ if (!name) return '`server` is required for restart. Example: { action: "restart", server: "github" }';
17034
+ const configured = deps.getConfig().mcpServers ?? {};
17035
+ if (!configured[name]) {
17036
+ return `Server "${name}" is not configured. Use \`mcp_control({ action: "enable", server: "${name}" })\` first.`;
17037
+ }
17038
+ try {
17039
+ await deps.registry.restart(name);
17040
+ const updated = deps.registry.describe().find((s) => s.name === name);
17041
+ return `${green("\u2713 Restarted")} "${name}"${updated ? ` (${updated.toolCount} tools registered).` : "."}`;
17042
+ } catch (err) {
17043
+ return `${red("\u2717 Restart failed")} for "${name}": ${err instanceof Error ? err.message : String(err)}`;
17044
+ }
17045
+ }
17046
+ async function readConfig(p) {
17047
+ try {
17048
+ return JSON.parse(await fsp2.readFile(p, "utf8"));
17049
+ } catch {
17050
+ return {};
17051
+ }
17052
+ }
17053
+ async function writeConfig(p, cfg) {
17054
+ const raw = JSON.stringify(cfg, null, 2);
17055
+ const tmp = p + ".tmp";
17056
+ await fsp2.writeFile(tmp, raw, "utf8");
17057
+ await fsp2.rename(tmp, p);
17058
+ }
17059
+ function bold(s) {
17060
+ return `\x1B[1m${s}\x1B[0m`;
17061
+ }
17062
+ function dim(s) {
17063
+ return `\x1B[2m${s}\x1B[0m`;
17064
+ }
17065
+ function green(s) {
17066
+ return `\x1B[32m${s}\x1B[0m`;
17067
+ }
17068
+ function yellow(s) {
17069
+ return `\x1B[33m${s}\x1B[0m`;
17070
+ }
17071
+ function red(s) {
17072
+ return `\x1B[31m${s}\x1B[0m`;
17073
+ }
17074
+ function badge(state) {
17075
+ switch (state) {
17076
+ case "connected":
17077
+ return green("\u25CF connected");
17078
+ case "connecting":
17079
+ return `\x1B[36m\u25D0 connecting\x1B[0m`;
17080
+ case "reconnecting":
17081
+ return `\x1B[36m\u25D1 reconnecting\x1B[0m`;
17082
+ case "disconnected":
17083
+ return dim("\u25CB disconnected");
17084
+ case "failed":
17085
+ return red("\u2717 failed");
17086
+ default:
17087
+ return dim(state);
17088
+ }
17089
+ }
16385
17090
 
16386
17091
  // src/extension/registry.ts
16387
17092
  var ExtensionRegistry = class {
@@ -16844,6 +17549,7 @@ var Agent = class {
16844
17549
  let effectiveLimit = opts.maxIterations ?? this.maxIterations;
16845
17550
  const hasHardLimit = effectiveLimit > 0 && Number.isFinite(effectiveLimit);
16846
17551
  let recoveryRetries = 0;
17552
+ const autonomousContinue = opts.autonomousContinue ?? this.autonomousContinue;
16847
17553
  const diRunner = this.container.has(TOKENS.ProviderRunner) ? this.container.resolve(TOKENS.ProviderRunner) : null;
16848
17554
  const baseRunner = diRunner ? (ctx, req) => diRunner.run({
16849
17555
  provider: ctx.provider,
@@ -16870,7 +17576,7 @@ var Agent = class {
16870
17576
  if (controller.signal.aborted) {
16871
17577
  return { status: "aborted", iterations };
16872
17578
  }
16873
- if (this.autonomousContinue) {
17579
+ if (autonomousContinue) {
16874
17580
  consumeAutonomousContinue(this.ctx);
16875
17581
  }
16876
17582
  const limitCheck = await this.checkIterationLimit(
@@ -16949,18 +17655,18 @@ var Agent = class {
16949
17655
  const toolUses = res.content.filter(isToolUseBlock);
16950
17656
  if (toolUses.length === 0) {
16951
17657
  this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
16952
- if (this.autonomousContinue && responseResult.directive === "continue") {
17658
+ if (autonomousContinue && responseResult.directive === "continue") {
16953
17659
  await this.compactContextIfNeeded();
16954
17660
  await this.extensions.runAfterIteration(this.ctx, i);
16955
17661
  continue;
16956
17662
  }
16957
- if (this.autonomousContinue && responseResult.directive === "stop") {
17663
+ if (autonomousContinue && responseResult.directive === "stop") {
16958
17664
  return { status: "done", iterations, finalText };
16959
17665
  }
16960
17666
  return { status: "done", iterations, finalText };
16961
17667
  }
16962
17668
  await this.executeTools(toolUses);
16963
- if (this.autonomousContinue && consumeAutonomousContinue(this.ctx)) {
17669
+ if (autonomousContinue && consumeAutonomousContinue(this.ctx)) {
16964
17670
  this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
16965
17671
  await this.compactContextIfNeeded();
16966
17672
  await this.extensions.runAfterIteration(this.ctx, i);
@@ -16969,10 +17675,10 @@ var Agent = class {
16969
17675
  this.events.emit("iteration.completed", { ctx: this.ctx, index: i });
16970
17676
  await this.compactContextIfNeeded();
16971
17677
  await this.extensions.runAfterIteration(this.ctx, i);
16972
- if (this.autonomousContinue && responseResult.directive === "continue") {
17678
+ if (autonomousContinue && responseResult.directive === "continue") {
16973
17679
  continue;
16974
17680
  }
16975
- if (this.autonomousContinue && responseResult.directive === "stop") {
17681
+ if (autonomousContinue && responseResult.directive === "stop") {
16976
17682
  return { status: "done", iterations, finalText };
16977
17683
  }
16978
17684
  }
@@ -17062,7 +17768,7 @@ var Agent = class {
17062
17768
  }
17063
17769
  }
17064
17770
  let directive = "none";
17065
- if (this.autonomousContinue && finalText) {
17771
+ if (finalText) {
17066
17772
  directive = parseContinueDirective(finalText);
17067
17773
  }
17068
17774
  return { finalText, aborted: false, done: false, directive };
@@ -18658,6 +19364,6 @@ function wrapApiForCapabilityCheck(plugin, api, log, enforce = false) {
18658
19364
  });
18659
19365
  }
18660
19366
 
18661
- export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, atomicWrite, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildChildEnv, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatGoal, formatPlan, formatPlanTemplates, formatTodosList, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, goalFilePath, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeContinueToNextIterationTool, makeDirectorSessionFactory, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseContinueDirective, parseSkillRef, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, securitySlashCommand, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
19367
+ export { AISpecBuilder, ALL_FLEET_AGENTS, AUDIT_LOG_AGENT, Agent, AgentError, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutonomousRunner, BUG_HUNTER_AGENT, BudgetExceededError, CONTEXT_WINDOW_MODES, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DefaultAttachmentStore, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FleetBus, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, GitignoreUpdater, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MAX_JOURNAL_ENTRIES, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, PROMETHEUS_CONTENT_TYPE, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, ScopedEventBus, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolError, ToolExecutor, ToolRegistry, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, atomicWrite, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, braveSearchServer, buildChildEnv, buildGoalPreamble, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildRecoveryStrategies, classifyFamily, clearPlan, color, compileGlob, compileUserRegex, composeDirectorPrompt, composeSubagentPrompt, computeTaskProgress, context7Server, contextManagerTool, createAutoExecutor, createContextManagerTool, createDefaultPipelines, createDelegateTool, createMcpControlTool, createMessage, createSecuritySlashCommand, createToolOutputSerializer, decryptConfigSecrets, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, downloadGitHubTarball, emptyGoal, emptyPlan, encryptConfigSecrets, ensureDir, estimateRequestTokens, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, extractRunEnv, filesystemServer, findCriticalPath, formatContextWindowModeList, formatGoal, formatPlan, formatPlanTemplates, formatTodosList, getContextWindowMode, getPlanTemplate, getTemplate, githubServer, goalFilePath, googleMapsServer, isAgentError, isConfigError, isContextWindowModeId, isImageBlock, isPluginError, isSessionError, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTodosCheckpoint, loadUserModes, makeAgentSubagentRunner, makeAutonomyPromptContributor, makeContinueToNextIterationTool, makeDirectorSessionFactory, matchAny, matchGlob, migratePlaintextSecrets, miniMaxVisionServer, normalizeToLf, parseContinueDirective, parseSkillRef, projectHash, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resolveContextWindowPolicy, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTodosCheckpoint, securitySlashCommand, sentinelServer, setPlanItemStatus, slackServer, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, unifiedDiff, unloadPlugins, validateAgainstSchema, wireMetricsToEvents, wrapAsState, zaiVisionServer };
18662
19368
  //# sourceMappingURL=index.js.map
18663
19369
  //# sourceMappingURL=index.js.map