@wrongstack/core 0.255.0 → 0.256.1

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 (101) hide show
  1. package/dist/{agent-bridge-l_DsFEbr.d.ts → agent-bridge-BrxWHEOm.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-DhYLgAJo.d.ts → agent-subagent-runner-US741uBH.d.ts} +17 -8
  3. package/dist/{brain-BaQsRNka.d.ts → brain-TjEEwSpw.d.ts} +1 -1
  4. package/dist/{compactor-BRfg3QPd.d.ts → compactor-C5sT4U7I.d.ts} +1 -1
  5. package/dist/{config-eSsrto5d.d.ts → config-DuAu23zm.d.ts} +16 -1
  6. package/dist/{context-CLz3z_E8.d.ts → context-CGdgA0q6.d.ts} +13 -0
  7. package/dist/coordination/index.d.ts +14 -14
  8. package/dist/coordination/index.js +21 -2
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +25 -25
  11. package/dist/defaults/index.js +238 -42
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/execution/index.d.ts +15 -15
  14. package/dist/execution/index.js +121 -22
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/execution/prompt-enhancer.d.ts +1 -1
  17. package/dist/extension/index.d.ts +6 -6
  18. package/dist/{goal-preamble-BgoPmZ8l.d.ts → goal-preamble-UiEkbNmW.d.ts} +21 -10
  19. package/dist/{index-BilZMsOK.d.ts → index-CC0Mcm05.d.ts} +9 -9
  20. package/dist/{index-Csoc_bKs.d.ts → index-CitPrI3a.d.ts} +20 -7
  21. package/dist/index.d.ts +112 -42
  22. package/dist/index.js +609 -111
  23. package/dist/index.js.map +1 -1
  24. package/dist/infrastructure/index.d.ts +6 -6
  25. package/dist/kernel/index.d.ts +10 -10
  26. package/dist/{llm-selector-D22R4AFz.d.ts → llm-selector-CJ4SyAFE.d.ts} +2 -2
  27. package/dist/{mcp-servers-DfXxCASH.d.ts → mcp-servers-D8YnLaEp.d.ts} +3 -3
  28. package/dist/models/index.d.ts +5 -5
  29. package/dist/{models-registry-DpanBg8D.d.ts → models-registry-ByZCdFuQ.d.ts} +1 -1
  30. package/dist/{multi-agent-coordinator-Bs-M0Mo6.d.ts → multi-agent-coordinator-DqTUEAeC.d.ts} +1 -1
  31. package/dist/{null-fleet-bus-CWdU1_cO.d.ts → null-fleet-bus-B5mfTJXT.d.ts} +17 -6
  32. package/dist/observability/index.d.ts +2 -2
  33. package/dist/{package-outdated-watcher-Dz-eNZlQ.d.ts → package-outdated-watcher-BSgR_kK-.d.ts} +3 -3
  34. package/dist/{parallel-eternal-engine-CAMabk-X.d.ts → parallel-eternal-engine-C0juOszP.d.ts} +24 -10
  35. package/dist/{path-resolver-B7VjhUHq.d.ts → path-resolver-CbkT-RMU.d.ts} +3 -3
  36. package/dist/{permission-DbWPbuoA.d.ts → permission-CwBBpCoF.d.ts} +1 -1
  37. package/dist/{permission-policy-AOk0LVsV.d.ts → permission-policy-B8rSu908.d.ts} +39 -2
  38. package/dist/{pipeline-Bxa3wDcy.d.ts → pipeline-JG8XoudC.d.ts} +2 -2
  39. package/dist/{plan-templates-D3guWwTi.d.ts → plan-templates-DPiQMkBz.d.ts} +5 -5
  40. package/dist/{provider-runner-C8_e4Lo1.d.ts → provider-runner-hM7EXlLI.d.ts} +3 -3
  41. package/dist/{retry-policy-BVnkbMET.d.ts → retry-policy-Tg7LXkoK.d.ts} +1 -1
  42. package/dist/sdd/index.d.ts +8 -8
  43. package/dist/{secret-vault-CeVNiy_f.d.ts → secret-vault-BkYkJWQs.d.ts} +1 -1
  44. package/dist/security/index.d.ts +4 -4
  45. package/dist/security/index.js +89 -18
  46. package/dist/security/index.js.map +1 -1
  47. package/dist/{selector-Cb4_9-hf.d.ts → selector-DWsqVjGf.d.ts} +1 -1
  48. package/dist/{session-event-bridge-BhtkkFFy.d.ts → session-event-bridge-BAFWdgQ3.d.ts} +1 -1
  49. package/dist/{session-reader-CCOssnBS.d.ts → session-reader-CqRvaL5v.d.ts} +1 -1
  50. package/dist/{skill-Bj6Ezqb8.d.ts → skill-DGIXCtdv.d.ts} +6 -0
  51. package/dist/skills/index.d.ts +1 -1
  52. package/dist/storage/index.d.ts +10 -10
  53. package/dist/storage/index.js +8 -1
  54. package/dist/storage/index.js.map +1 -1
  55. package/dist/types/index.d.ts +19 -19
  56. package/dist/types/index.js +83 -25
  57. package/dist/types/index.js.map +1 -1
  58. package/dist/utils/index.d.ts +2 -2
  59. package/dist/utils/index.js +3 -0
  60. package/dist/utils/index.js.map +1 -1
  61. package/package.json +1 -1
  62. package/skills/api-design/SKILL.md +1 -0
  63. package/skills/api-design/SKILL.save.md +26 -0
  64. package/skills/audit-log/SKILL.md +9 -2
  65. package/skills/audit-log/SKILL.save.md +22 -0
  66. package/skills/bug-hunter/SKILL.md +10 -2
  67. package/skills/bug-hunter/SKILL.save.md +33 -0
  68. package/skills/chimera/SKILL.md +12 -18
  69. package/skills/chimera/SKILL.save.md +26 -0
  70. package/skills/docker-deploy/SKILL.md +1 -0
  71. package/skills/docker-deploy/SKILL.save.md +23 -0
  72. package/skills/git-flow/SKILL.md +23 -2
  73. package/skills/git-flow/SKILL.save.md +25 -0
  74. package/skills/multi-agent/SKILL.md +23 -2
  75. package/skills/multi-agent/SKILL.save.md +26 -0
  76. package/skills/node-modern/SKILL.md +2 -1
  77. package/skills/node-modern/SKILL.save.md +21 -0
  78. package/skills/observability/SKILL.md +1 -0
  79. package/skills/observability/SKILL.save.md +34 -0
  80. package/skills/output-standards/SKILL.md +133 -0
  81. package/skills/output-standards/SKILL.save.md +21 -0
  82. package/skills/prompt-engineering/SKILL.md +2 -1
  83. package/skills/prompt-engineering/SKILL.save.md +29 -0
  84. package/skills/react-modern/SKILL.md +2 -1
  85. package/skills/react-modern/SKILL.save.md +24 -0
  86. package/skills/refactor-planner/SKILL.md +9 -2
  87. package/skills/refactor-planner/SKILL.save.md +26 -0
  88. package/skills/research-web/SKILL.md +1 -0
  89. package/skills/research-web/SKILL.save.md +25 -0
  90. package/skills/sdd/SKILL.md +2 -1
  91. package/skills/sdd/SKILL.save.md +19 -0
  92. package/skills/security-scanner/SKILL.md +10 -3
  93. package/skills/security-scanner/SKILL.save.md +23 -0
  94. package/skills/skill-creator/SKILL.md +2 -1
  95. package/skills/skill-creator/SKILL.save.md +20 -0
  96. package/skills/tech-stack/SKILL.md +13 -226
  97. package/skills/tech-stack/SKILL.save.md +25 -0
  98. package/skills/testing/SKILL.md +1 -0
  99. package/skills/testing/SKILL.save.md +22 -0
  100. package/skills/typescript-strict/SKILL.md +2 -1
  101. package/skills/typescript-strict/SKILL.save.md +19 -0
package/dist/index.js CHANGED
@@ -190,6 +190,10 @@ var init_session_registry = __esm({
190
190
  * Starts the heartbeat timer.
191
191
  */
192
192
  async register(entry) {
193
+ if (this.heartbeatTimer) {
194
+ clearInterval(this.heartbeatTimer);
195
+ this.heartbeatTimer = null;
196
+ }
193
197
  this.currentSessionId = entry.sessionId;
194
198
  const full = {
195
199
  ...entry,
@@ -201,7 +205,10 @@ var init_session_registry = __esm({
201
205
  await this.atomicUpdate((registry) => {
202
206
  const now = Date.now();
203
207
  for (const [id, existing] of Object.entries(registry)) {
204
- if (existing.pid === entry.pid) continue;
208
+ if (existing.pid === entry.pid) {
209
+ if (id !== entry.sessionId) delete registry[id];
210
+ continue;
211
+ }
205
212
  const heartbeatAge = now - new Date(existing.lastHeartbeatAt).getTime();
206
213
  if (heartbeatAge > STALE_TIMEOUT_MS && !pidAlive(existing.pid)) {
207
214
  delete registry[id];
@@ -3054,9 +3061,28 @@ var PATTERNS = [
3054
3061
  }
3055
3062
  ];
3056
3063
  var SCRUB_CHUNK_BYTES = 64 * 1024;
3064
+ function hasCredentialAnchors(text) {
3065
+ return text.includes("-----BEGIN") || // Private keys (most unique → cheap reject)
3066
+ text.includes("sk-") || // Anthropic + OpenAI keys
3067
+ text.includes("sk_") || // Stripe live/test keys
3068
+ text.includes("ghp_") || // GitHub PAT v1
3069
+ text.includes("github_pat_") || // GitHub PAT v2
3070
+ text.includes("eyJ") || // JWT
3071
+ text.includes("AKIA") || // AWS access key
3072
+ text.includes("AIza") || // GCP service key
3073
+ text.includes("xox") || // Slack token (xoxa/xoxb/xoxp/xoxo/xoxs)
3074
+ text.includes("Bearer ") || // Bearer token (space suffix reduces false positives)
3075
+ text.includes("/bot") || // Telegram bot token (URL path pattern)
3076
+ text.includes("_KEY=") || // High-entropy env vars: API_KEY=, SECRET_KEY=, ...
3077
+ text.includes("_TOKEN=") || // ACCESS_TOKEN=, AUTH_TOKEN=, ...
3078
+ text.includes("_SECRET=") || // API_SECRET=, CLIENT_SECRET=, ...
3079
+ text.includes("_PASSWORD=") || // DB_PASSWORD=, ROOT_PASSWORD=, ...
3080
+ text.includes("mongodb://") || text.includes("mongodb+srv://") || text.includes("postgres://") || text.includes("postgresql://") || text.includes("mysql://") || text.includes("redis://");
3081
+ }
3057
3082
  var DefaultSecretScrubber = class {
3058
3083
  scrub(text) {
3059
3084
  if (!text) return text;
3085
+ if (!hasCredentialAnchors(text)) return text;
3060
3086
  if (text.length <= SCRUB_CHUNK_BYTES) {
3061
3087
  return this.scrubOne(text);
3062
3088
  }
@@ -3074,6 +3100,7 @@ var DefaultSecretScrubber = class {
3074
3100
  return out.join("");
3075
3101
  }
3076
3102
  scrubOne(text) {
3103
+ if (!hasCredentialAnchors(text)) return text;
3077
3104
  let out = text;
3078
3105
  for (const p of PATTERNS) {
3079
3106
  out = out.replace(p.regex, (_match, group1, group2) => {
@@ -4111,10 +4138,14 @@ var ToolCapabilities = {
4111
4138
  SHELL_ARBITRARY: "shell.arbitrary",
4112
4139
  /** Can execute a restricted set of commands (the `exec` tool). */
4113
4140
  SHELL_RESTRICTED: "shell.restricted",
4141
+ /** Can read files inside the project (and possibly outside via symlinks if not guarded). */
4142
+ FS_READ: "fs.read",
4114
4143
  /** Can write / modify / delete files inside the project. */
4115
4144
  FS_WRITE: "fs.write",
4116
4145
  /** Can write files outside the current project root (very high risk). */
4117
4146
  FS_WRITE_OUTSIDE_PROJECT: "fs.write.outside-project",
4147
+ /** Can perform outbound network requests. */
4148
+ NET_OUTBOUND: "net.outbound",
4118
4149
  /** Proxies tools from external MCP servers (unknown capability). */
4119
4150
  MCP_PROXY: "mcp.proxy",
4120
4151
  /** Can spawn or manage subagents / multi-agent tasks. */
@@ -4351,7 +4382,7 @@ var ToolExecutor = class _ToolExecutor {
4351
4382
  const tool = this.registry.get(use.name);
4352
4383
  if (!tool) {
4353
4384
  const result = this.unknownToolResult(use, () => this.registry.list().map((t2) => t2.name));
4354
- budget = this.decrementBudget(result, budget);
4385
+ budget = this.budgetForString(result.content, budget);
4355
4386
  return { result, tool, durationMs: Date.now() - start };
4356
4387
  }
4357
4388
  const validation = validateAgainstSchema(use.input, tool.inputSchema);
@@ -4368,20 +4399,20 @@ ${errorDetails}
4368
4399
  Please call the tool again with arguments that match its inputSchema. You can use the "tool-help" tool with name="${tool.name}" to see the exact expected schema.`,
4369
4400
  is_error: true
4370
4401
  };
4371
- budget = this.decrementBudget(result, budget);
4402
+ budget = this.budgetForString(result.content, budget);
4372
4403
  return { result, tool, durationMs: Date.now() - start };
4373
4404
  }
4374
4405
  const toolDangerousCaps = getDangerousCapabilities(tool);
4375
4406
  if (hasMalformedArguments(use.input)) {
4376
4407
  const result = this.malformedInputResult(use, extractMalformedRaw(use.input));
4377
- budget = this.decrementBudget(result, budget);
4408
+ budget = this.budgetForString(result.content, budget);
4378
4409
  return { result, tool, durationMs: Date.now() - start };
4379
4410
  }
4380
4411
  if (this.opts.hookRunner?.has("PreToolUse")) {
4381
4412
  const pre = await this.opts.hookRunner.preToolUse(tool.name, use.input, ctx);
4382
4413
  if (pre.block) {
4383
4414
  const result = this.blockedByHookResult(use, pre.reason);
4384
- budget = this.decrementBudget(result, budget);
4415
+ budget = this.budgetForString(result.content, budget);
4385
4416
  return { result, tool, durationMs: Date.now() - start };
4386
4417
  }
4387
4418
  if (pre.input) {
@@ -4397,7 +4428,7 @@ Validation errors:
4397
4428
  ${errorDetails}`,
4398
4429
  is_error: true
4399
4430
  };
4400
- budget = this.decrementBudget(result, budget);
4431
+ budget = this.budgetForString(result.content, budget);
4401
4432
  return { result, tool, durationMs: Date.now() - start };
4402
4433
  }
4403
4434
  use = { ...use, input: pre.input };
@@ -4412,7 +4443,7 @@ ${errorDetails}`,
4412
4443
  }
4413
4444
  if (effectivePermission === "deny") {
4414
4445
  const result = this.deniedResult(use, decision.reason);
4415
- budget = this.decrementBudget(result, budget);
4446
+ budget = this.budgetForString(result.content, budget);
4416
4447
  return { result, tool, durationMs: Date.now() - start };
4417
4448
  }
4418
4449
  if (effectivePermission === "confirm") {
@@ -4425,7 +4456,7 @@ ${errorDetails}`,
4425
4456
  content: `Tool "${tool.name}" denied by user.`,
4426
4457
  is_error: true
4427
4458
  };
4428
- budget = this.decrementBudget(result, budget);
4459
+ budget = this.budgetForString(result.content, budget);
4429
4460
  return { result, tool, durationMs: Date.now() - start };
4430
4461
  }
4431
4462
  } else {
@@ -4449,7 +4480,8 @@ ${errorDetails}`,
4449
4480
  "tool.has_dangerous_capabilities": toolCapsForAudit.length > 0
4450
4481
  });
4451
4482
  try {
4452
- let result = await this.executeTool(tool, use, ctx, budget);
4483
+ let { block: result, bytes } = await this.executeTool(tool, use, ctx, budget);
4484
+ budget -= bytes;
4453
4485
  if (this.opts.hookRunner?.has("PostToolUse")) {
4454
4486
  const post = await this.opts.hookRunner.postToolUse(
4455
4487
  tool.name,
@@ -4458,12 +4490,13 @@ ${errorDetails}`,
4458
4490
  ctx
4459
4491
  );
4460
4492
  if (post.additionalContext) {
4461
- result = { ...result, content: `${result.content}
4493
+ const appended = `
4462
4494
 
4463
- ${post.additionalContext}` };
4495
+ ${post.additionalContext}`;
4496
+ result = { ...result, content: `${result.content}${appended}` };
4497
+ budget = Math.max(0, budget - Buffer.byteLength(appended, "utf8"));
4464
4498
  }
4465
4499
  }
4466
- budget = this.decrementBudget(result, budget);
4467
4500
  span?.setAttribute("tool.is_error", !!result.is_error);
4468
4501
  span?.setAttribute(
4469
4502
  "tool.output_bytes",
@@ -4480,7 +4513,7 @@ ${post.additionalContext}` };
4480
4513
  content: `Tool "${tool.name}" threw: ${scrubbed}`,
4481
4514
  is_error: true
4482
4515
  };
4483
- budget = this.decrementBudget(result, budget);
4516
+ budget = this.budgetForString(result.content, budget);
4484
4517
  if (err instanceof Error) span?.recordError(err);
4485
4518
  span?.setAttribute("tool.is_error", true);
4486
4519
  return { result, tool, durationMs: Date.now() - start };
@@ -4500,7 +4533,7 @@ ${post.additionalContext}` };
4500
4533
  content: `Tool "${use.name}" execution failed: ${scrubbed}`,
4501
4534
  is_error: true
4502
4535
  };
4503
- budget = this.decrementBudget(result, budget);
4536
+ budget = this.budgetForString(result.content, budget);
4504
4537
  return { result, tool: this.registry.get(use.name), durationMs: 0 };
4505
4538
  }
4506
4539
  };
@@ -4549,14 +4582,20 @@ ${post.additionalContext}` };
4549
4582
  const output = await this.runWithTimeout(tool, use.input, ctx.signal, ctx, use.id);
4550
4583
  const text = this.serializer.serialize(output);
4551
4584
  const scrubbed = this.opts.secretScrubber.scrub(text);
4552
- const { text: capped } = this.serializer.enforceCap(scrubbed, budget);
4585
+ const { text: capped, newBudget } = this.serializer.enforceCap(scrubbed, budget);
4553
4586
  this.opts.renderer?.writeToolResult(tool.name, capped, false);
4554
4587
  return {
4555
- type: "tool_result",
4556
- tool_use_id: use.id,
4557
- name: tool.name,
4558
- content: capped,
4559
- is_error: false
4588
+ block: {
4589
+ type: "tool_result",
4590
+ tool_use_id: use.id,
4591
+ name: tool.name,
4592
+ content: capped,
4593
+ is_error: false
4594
+ },
4595
+ // `budget - newBudget` is the exact byte count enforceCap spent
4596
+ // (capped at `budget` so a truncated output shows as `budget`
4597
+ // consumed, matching the pre-fix `decrementBudget` semantics).
4598
+ bytes: budget - newBudget
4560
4599
  };
4561
4600
  }
4562
4601
  async runWithTimeout(tool, input, parentSignal, ctx, toolUseId) {
@@ -4696,9 +4735,19 @@ ${excerpt}`;
4696
4735
  is_error: true
4697
4736
  };
4698
4737
  }
4699
- decrementBudget(result, budget) {
4700
- const contentBytes = typeof result.content === "string" ? Buffer.byteLength(result.content, "utf8") : Buffer.byteLength(JSON.stringify(result.content), "utf8");
4701
- return Math.max(0, budget - contentBytes);
4738
+ /**
4739
+ * Subtract a string-content result's UTF-8 byte length from the
4740
+ * iteration output budget. Used for synthesized results (unknown tool,
4741
+ * validation error, blocked, threw) where the content is a small
4742
+ * string built in the executor. The success path no longer goes
4743
+ * through here — `executeTool` carries the exact byte count it spent
4744
+ * in its return value, derived from `enforceCap`'s `newBudget`.
4745
+ *
4746
+ * Floors the result at 0 to match the pre-fix `decrementBudget`
4747
+ * semantics (over-budget spends don't underflow the running total).
4748
+ */
4749
+ budgetForString(content, budget) {
4750
+ return Math.max(0, budget - Buffer.byteLength(content, "utf8"));
4702
4751
  }
4703
4752
  /**
4704
4753
  * Compute the suggestedPattern string for a tool+input pair.
@@ -4804,10 +4853,19 @@ var ConversationState = class {
4804
4853
  this.emit({ kind: "message_appended", message });
4805
4854
  }
4806
4855
  replaceMessages(messages) {
4856
+ let hasToolBlock = false;
4807
4857
  for (const m of messages) {
4808
4858
  if (m._estTokens === void 0) {
4809
4859
  m._estTokens = computeMessageTokens(m);
4810
4860
  }
4861
+ if (!hasToolBlock && Array.isArray(m.content)) {
4862
+ for (const b of m.content) {
4863
+ if (b.type === "tool_use" || b.type === "tool_result") {
4864
+ hasToolBlock = true;
4865
+ break;
4866
+ }
4867
+ }
4868
+ }
4811
4869
  }
4812
4870
  const arr = this.ctx.messages;
4813
4871
  if (messages.length < arr.length) {
@@ -4816,9 +4874,7 @@ var ConversationState = class {
4816
4874
  for (let i = 0; i < messages.length; i++) {
4817
4875
  arr[i] = messages[i];
4818
4876
  }
4819
- if (messages.some(
4820
- (m) => Array.isArray(m.content) && m.content.some((b) => b.type === "tool_use" || b.type === "tool_result")
4821
- )) {
4877
+ if (hasToolBlock) {
4822
4878
  this.ctx.toolAdjacencyDirty = true;
4823
4879
  }
4824
4880
  this.emit({ kind: "messages_replaced", messages: [...messages] });
@@ -4897,6 +4953,19 @@ var Context = class {
4897
4953
  * on iterations where no tool content was added (pure text responses).
4898
4954
  */
4899
4955
  toolAdjacencyDirty = false;
4956
+ /**
4957
+ * H1: pre-computed total-request token estimate from the most recent
4958
+ * `estimateRequestTokens()` call in the agent loop's pre-flight step.
4959
+ * The middleware that decides when to compact, the `emitContextPct`
4960
+ * helper that drives the live context-fill bar, and the pre-flight
4961
+ * itself all need this number; previously each one walked the same
4962
+ * messages/system/tools arrays independently. Stashing it here lets
4963
+ * the three call sites share a single compute per iteration.
4964
+ *
4965
+ * The value is the **uncalibrated** total. Callers that want the
4966
+ * calibrated number apply the per-(provider,model) ratio themselves.
4967
+ */
4968
+ lastRequestTokens = void 0;
4900
4969
  constructor(init) {
4901
4970
  this.systemPrompt = init.systemPrompt;
4902
4971
  this.provider = init.provider;
@@ -6095,6 +6164,9 @@ async function expandGlob(pattern) {
6095
6164
  function completePartialObject(s) {
6096
6165
  if (!s.trim().startsWith("{")) return s;
6097
6166
  if (tryParse(s).ok) return s;
6167
+ return repairTruncated(s);
6168
+ }
6169
+ function repairTruncated(s) {
6098
6170
  const stack = [];
6099
6171
  let inString = false;
6100
6172
  let escaped = false;
@@ -9328,6 +9400,21 @@ var DefaultPermissionPolicy = class {
9328
9400
  promptDelegate;
9329
9401
  /** Pre-compiled wildcard patterns — rebuilt on reload for O(1) lookup. */
9330
9402
  wildcardEntries = [];
9403
+ /**
9404
+ * Evaluate-result cache. Keyed by `tool.name::subject` so repeated calls
9405
+ * with the same tool+input skip namespace matching, subject computation,
9406
+ * pattern matching (matchAny), and YOLO destructive gating.
9407
+ *
9408
+ * Cleared on any state change (reload, trust, deny, yolo toggle) because
9409
+ * the result depends on the full policy state. The write-tool smart-bypass
9410
+ * (step 7 in `evaluate()`) is not cached since `ctx.hasRead()` changes
9411
+ * dynamically within a session.
9412
+ *
9413
+ * LRU eviction is not needed — the cache is cleared on state changes
9414
+ * that are rare (trust file ops, user confirm) and the number of unique
9415
+ * tool+subject pairs per iteration is small (<50).
9416
+ */
9417
+ _evalCache = /* @__PURE__ */ new Map();
9331
9418
  constructor(opts) {
9332
9419
  this.trustFile = opts.trustFile;
9333
9420
  this.yolo = opts.yolo ?? false;
@@ -9346,6 +9433,7 @@ var DefaultPermissionPolicy = class {
9346
9433
  }
9347
9434
  /** Toggle YOLO (auto-approve) mode at runtime. */
9348
9435
  setYolo(enabled) {
9436
+ if (this.yolo !== enabled) this._evalCache.clear();
9349
9437
  this.yolo = enabled;
9350
9438
  }
9351
9439
  /** Check whether YOLO mode is currently active. */
@@ -9354,6 +9442,7 @@ var DefaultPermissionPolicy = class {
9354
9442
  }
9355
9443
  /** Toggle the destructive YOLO override at runtime. */
9356
9444
  setYoloDestructive(enabled) {
9445
+ if (this.yoloDestructive !== enabled) this._evalCache.clear();
9357
9446
  this.yoloDestructive = enabled;
9358
9447
  }
9359
9448
  /** Check whether the destructive YOLO override is active. */
@@ -9362,6 +9451,7 @@ var DefaultPermissionPolicy = class {
9362
9451
  }
9363
9452
  /** Toggle destructive confirmation gate (only meaningful when yolo is active). */
9364
9453
  setConfirmDestructive(enabled) {
9454
+ if (this.confirmDestructive !== enabled) this._evalCache.clear();
9365
9455
  this.confirmDestructive = enabled;
9366
9456
  }
9367
9457
  /** Check whether destructive confirmation gate is active. */
@@ -9382,6 +9472,7 @@ var DefaultPermissionPolicy = class {
9382
9472
  }
9383
9473
  this.sessionDenied.clear();
9384
9474
  this.sessionAllowed.clear();
9475
+ this._evalCache.clear();
9385
9476
  this.loaded = true;
9386
9477
  }
9387
9478
  async evaluate(tool, input, ctx) {
@@ -9389,44 +9480,60 @@ var DefaultPermissionPolicy = class {
9389
9480
  const namespaceEntry = this.findNamespaceEntry(tool.name);
9390
9481
  const entry = this.policy[tool.name] ?? namespaceEntry;
9391
9482
  const subject = this.subjectFor(tool.name, input, tool.subjectKey);
9392
- const subjectKey = `${tool.name}::${subject ?? tool.name}`;
9393
- if (this.sessionDenied.has(subjectKey)) {
9394
- return { permission: "deny", source: "deny", reason: "session soft deny (user pressed no)" };
9483
+ const cacheKey = `${tool.name}::${subject ?? tool.name}`;
9484
+ if (tool.name !== "write") {
9485
+ const cached = this._evalCache.get(cacheKey);
9486
+ if (cached !== void 0) return cached;
9487
+ }
9488
+ if (this.sessionDenied.has(cacheKey)) {
9489
+ const decision = { permission: "deny", source: "deny", reason: "session soft deny (user pressed no)" };
9490
+ this._evalCache.set(cacheKey, decision);
9491
+ return decision;
9395
9492
  }
9396
- if (this.sessionAllowed.has(subjectKey)) {
9397
- return {
9493
+ if (this.sessionAllowed.has(cacheKey)) {
9494
+ const decision = {
9398
9495
  permission: "auto",
9399
9496
  source: "trust",
9400
9497
  reason: "session soft allow (user pressed yes)"
9401
9498
  };
9499
+ this._evalCache.set(cacheKey, decision);
9500
+ return decision;
9402
9501
  }
9403
9502
  if (entry?.deny && subject && matchAny(entry.deny, subject)) {
9404
- return { permission: "deny", source: "deny", reason: "matched deny pattern" };
9503
+ const decision = { permission: "deny", source: "deny", reason: "matched deny pattern" };
9504
+ this._evalCache.set(cacheKey, decision);
9505
+ return decision;
9405
9506
  }
9406
9507
  if (tool.permission === "deny") {
9407
- return { permission: "deny", source: "default", reason: "tool default deny" };
9508
+ const decision = { permission: "deny", source: "default", reason: "tool default deny" };
9509
+ this._evalCache.set(cacheKey, decision);
9510
+ return decision;
9408
9511
  }
9409
9512
  if (entry?.allow && subject && matchAny(entry.allow, subject)) {
9410
- return { permission: "auto", source: "trust", reason: "matched allow pattern" };
9513
+ const decision = { permission: "auto", source: "trust", reason: "matched allow pattern" };
9514
+ this._evalCache.set(cacheKey, decision);
9515
+ return decision;
9411
9516
  }
9412
9517
  if (entry?.auto) {
9413
- return { permission: "auto", source: "trust" };
9518
+ const decision = { permission: "auto", source: "trust" };
9519
+ this._evalCache.set(cacheKey, decision);
9520
+ return decision;
9414
9521
  }
9415
9522
  if (this.yolo) {
9416
9523
  if (this.confirmDestructive) {
9417
9524
  const destructive = this.isDestructiveYoloCall(tool, input, ctx);
9418
9525
  if (destructive) {
9419
9526
  if (this.promptDelegate) {
9420
- const decision = await this.promptDelegate(tool, input, subject ?? tool.name);
9421
- if (decision === "always") {
9527
+ const decision2 = await this.promptDelegate(tool, input, subject ?? tool.name);
9528
+ if (decision2 === "always") {
9422
9529
  await this.trust({ tool: tool.name, pattern: subject ?? tool.name });
9423
9530
  return { permission: "auto", source: "user", reason: "destructive yolo always-allowed" };
9424
9531
  }
9425
- if (decision === "deny") {
9532
+ if (decision2 === "deny") {
9426
9533
  await this.deny({ tool: tool.name, pattern: subject ?? tool.name });
9427
9534
  return { permission: "deny", source: "user", reason: "user denied destructive yolo" };
9428
9535
  }
9429
- return { permission: decision === "yes" ? "auto" : "deny", source: "user" };
9536
+ return { permission: decision2 === "yes" ? "auto" : "deny", source: "user" };
9430
9537
  }
9431
9538
  return {
9432
9539
  permission: "confirm",
@@ -9436,7 +9543,9 @@ var DefaultPermissionPolicy = class {
9436
9543
  };
9437
9544
  }
9438
9545
  }
9439
- return { permission: "auto", source: "yolo" };
9546
+ const decision = { permission: "auto", source: "yolo" };
9547
+ this._evalCache.set(cacheKey, decision);
9548
+ return decision;
9440
9549
  }
9441
9550
  if (tool.name === "write" && subject) {
9442
9551
  if (ctx.hasRead(subject)) {
@@ -9448,7 +9557,9 @@ var DefaultPermissionPolicy = class {
9448
9557
  }
9449
9558
  }
9450
9559
  if (tool.permission === "auto" && !tool.mutating) {
9451
- return { permission: "auto", source: "default" };
9560
+ const decision = { permission: "auto", source: "default" };
9561
+ this._evalCache.set(cacheKey, decision);
9562
+ return decision;
9452
9563
  }
9453
9564
  if (this.promptDelegate) {
9454
9565
  const decision = await this.promptDelegate(tool, input, subject ?? tool.name);
@@ -9481,6 +9592,7 @@ var DefaultPermissionPolicy = class {
9481
9592
  const entry = this.policy[rule.tool] ?? {};
9482
9593
  entry.allow = Array.from(/* @__PURE__ */ new Set([...entry.allow ?? [], rule.pattern]));
9483
9594
  this.policy[rule.tool] = entry;
9595
+ this._evalCache.clear();
9484
9596
  try {
9485
9597
  await atomicWrite(this.trustFile, JSON.stringify(this.policy, null, 2));
9486
9598
  } catch (err) {
@@ -9498,6 +9610,7 @@ var DefaultPermissionPolicy = class {
9498
9610
  const entry = this.policy[rule.tool] ?? {};
9499
9611
  entry.deny = Array.from(/* @__PURE__ */ new Set([...entry.deny ?? [], rule.pattern]));
9500
9612
  this.policy[rule.tool] = entry;
9613
+ this._evalCache.clear();
9501
9614
  try {
9502
9615
  await atomicWrite(this.trustFile, JSON.stringify(this.policy, null, 2));
9503
9616
  } catch (err) {
@@ -9512,10 +9625,12 @@ var DefaultPermissionPolicy = class {
9512
9625
  /** Block this tool+pattern for the rest of this session (no trust file). */
9513
9626
  denyOnce(rule) {
9514
9627
  this.sessionDenied.set(`${rule.tool}::${rule.pattern}`, true);
9628
+ this._evalCache.clear();
9515
9629
  }
9516
9630
  /** Auto-approve this tool+pattern for the rest of this session (no trust file). */
9517
9631
  allowOnce(rule) {
9518
9632
  this.sessionAllowed.set(`${rule.tool}::${rule.pattern}`, true);
9633
+ this._evalCache.clear();
9519
9634
  }
9520
9635
  subjectFor(toolName, input, subjectKey) {
9521
9636
  if (!input || typeof input !== "object") return void 0;
@@ -9551,15 +9666,23 @@ var DefaultPermissionPolicy = class {
9551
9666
  }
9552
9667
  };
9553
9668
  var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
9669
+ allowedCapabilities;
9670
+ constructor(allowedCapabilities) {
9671
+ this.allowedCapabilities = allowedCapabilities ?? [
9672
+ ToolCapabilities.FS_READ,
9673
+ ToolCapabilities.NET_OUTBOUND
9674
+ ];
9675
+ }
9554
9676
  static isMcpTool(name) {
9555
9677
  return name.startsWith("mcp__");
9556
9678
  }
9557
9679
  async evaluate(tool) {
9558
- const hasDangerousCap = hasDangerousCapabilityForSubagents(tool);
9680
+ const caps = tool.capabilities ?? [];
9681
+ const hasAllowedCap = caps.some((c) => this.allowedCapabilities.includes(c));
9559
9682
  const isMcp = _AutoApprovePermissionPolicy.isMcpTool(tool.name);
9560
- const blocked = tool.permission === "deny" || hasDangerousCap || isMcp;
9683
+ const blocked = tool.permission === "deny" || isMcp || !hasAllowedCap;
9561
9684
  if (blocked) {
9562
- const reason = hasDangerousCap ? `tool declares dangerous capability (${tool.capabilities?.join(", ")}) \u2014 not auto-approved for subagents` : isMcp ? `MCP tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow it explicitly` : "tool default deny";
9685
+ const reason = isMcp ? `MCP tool ${tool.name} is not auto-approved for subagents \u2014 ask the leader to allow it explicitly` : tool.permission === "deny" ? "tool default deny" : `tool lacks allowed capability (has: ${caps.join(", ") || "none"}, allowed: ${this.allowedCapabilities.join(", ")})`;
9563
9686
  return {
9564
9687
  permission: "deny",
9565
9688
  source: "subagent_guard",
@@ -9579,6 +9702,35 @@ var AutoApprovePermissionPolicy = class _AutoApprovePermissionPolicy {
9579
9702
  async reload() {
9580
9703
  }
9581
9704
  };
9705
+ function stripFrontmatter(raw) {
9706
+ if (!raw.startsWith("---")) return raw;
9707
+ const end = raw.indexOf("\n---", 4);
9708
+ if (end === -1) return raw;
9709
+ let body = raw.slice(end + 4);
9710
+ if (body.startsWith("\n")) body = body.slice(1);
9711
+ return body;
9712
+ }
9713
+ function compactSkillBody(body) {
9714
+ const sections = [];
9715
+ const overviewMatch = body.match(/##\s*Overview\s*\n([\s\S]*?)(?=\n##|\n$|$)/i);
9716
+ const overview = overviewMatch?.[1];
9717
+ if (overview?.trim()) {
9718
+ sections.push(overview.trim().slice(0, 200));
9719
+ }
9720
+ const rulesMatch = body.match(/##\s*Rules\s*\n([\s\S]*?)(?=\n##|\n$|$)/i);
9721
+ const rules = rulesMatch?.[1];
9722
+ if (rules?.trim()) {
9723
+ const trimmed = rules.trim().slice(0, 350);
9724
+ const ruleLines = trimmed.split("\n").filter((l) => /^\s*[-*]\s/.test(l) || /^\s*\d+[.)]\s/.test(l)).slice(0, 6).join("\n");
9725
+ if (ruleLines) sections.push(ruleLines);
9726
+ }
9727
+ if (sections.length === 0) {
9728
+ const first = body.trim().slice(0, 200);
9729
+ if (first) sections.push(first);
9730
+ }
9731
+ const result = sections.join("\n\n");
9732
+ return result.length > 450 ? result.slice(0, 447) + "\u2026" : result;
9733
+ }
9582
9734
  var DefaultSkillLoader = class {
9583
9735
  dirs;
9584
9736
  cache;
@@ -9660,6 +9812,24 @@ var DefaultSkillLoader = class {
9660
9812
  if (!m) throw new Error(`Skill "${name}" not found`);
9661
9813
  return fsp3.readFile(m.path, "utf8");
9662
9814
  }
9815
+ async readSaveBody(name) {
9816
+ const m = await this.find(name);
9817
+ if (!m) throw new Error(`Skill "${name}" not found`);
9818
+ const savePath = path7.join(path7.dirname(m.path), "SKILL.save.md");
9819
+ try {
9820
+ return await fsp3.readFile(savePath, "utf8");
9821
+ } catch {
9822
+ const full = await fsp3.readFile(m.path, "utf8");
9823
+ const body = stripFrontmatter(full);
9824
+ const compact = compactSkillBody(body);
9825
+ if (compact) {
9826
+ return `## Overview
9827
+
9828
+ ${compact}`;
9829
+ }
9830
+ return body.trim().slice(0, 300);
9831
+ }
9832
+ }
9663
9833
  };
9664
9834
  function parseFrontmatter(raw) {
9665
9835
  if (!raw.startsWith("---")) return {};
@@ -10740,6 +10910,13 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
10740
10910
  tokens = this._estimator(ctx);
10741
10911
  } else if (msgCount === this._cachedMsgCount && toolCount === this._cachedToolCount && this._cachedTokens >= 0) {
10742
10912
  tokens = this._cachedTokens;
10913
+ } else if (this.tryStashedTokens(ctx, msgCount, toolCount) !== null) {
10914
+ const stashed = this.tryStashedTokens(ctx, msgCount, toolCount);
10915
+ const cal = getCalibrationState(`${ctx.provider?.id ?? "unknown"}/${ctx.model}`);
10916
+ tokens = cal.calibrated ? Math.round(stashed * Math.min(1.5, Math.max(0.5, cal.ratio))) : stashed;
10917
+ this._cachedTokens = tokens;
10918
+ this._cachedMsgCount = msgCount;
10919
+ this._cachedToolCount = toolCount;
10743
10920
  } else {
10744
10921
  tokens = estimateRequestTokensCalibrated(
10745
10922
  ctx.messages,
@@ -10772,6 +10949,25 @@ var AutoCompactionMiddleware = class _AutoCompactionMiddleware {
10772
10949
  return next(ctx);
10773
10950
  };
10774
10951
  }
10952
+ /**
10953
+ * H1: try to read a pre-computed token total from `ctx.lastRequestTokens`
10954
+ * (set by the agent loop's pre-flight or its restash in emitContextPct).
10955
+ * Returns the uncalibrated total when the stash is valid for the current
10956
+ * context shape (positive number, and the message count it was computed
10957
+ * at matches the current one — otherwise tool results have been appended
10958
+ * since and the value is stale). Returns null when missing or stale so
10959
+ * the caller falls back to a fresh walk.
10960
+ */
10961
+ tryStashedTokens(ctx, msgCount, toolCount) {
10962
+ const stashed = ctx.lastRequestTokens;
10963
+ if (typeof stashed !== "number" || stashed <= 0) return null;
10964
+ const stashedAt = ctx.meta?.["lastRequestTokensAt"];
10965
+ if (typeof stashedAt !== "object" || stashedAt === null) return null;
10966
+ const meta = stashedAt;
10967
+ if (meta.msgCount !== msgCount) return null;
10968
+ if (typeof meta.toolCount === "number" && meta.toolCount !== toolCount) return null;
10969
+ return stashed;
10970
+ }
10775
10971
  /**
10776
10972
  * Returns true when the previous compaction at the same or higher pressure
10777
10973
  * level reduced nothing and context has not grown materially since. Prevents
@@ -18679,6 +18875,17 @@ var Director = class _Director {
18679
18875
  * default cap.
18680
18876
  */
18681
18877
  taskCompletedListener = null;
18878
+ /**
18879
+ * Unsub handles for the two `FleetBus.filter()` calls installed in the
18880
+ * constructor for timeout-heartbeat tracking. Without capturing these
18881
+ * and calling them in `shutdown()`, repeated Director construction
18882
+ * (tests, hot reloads, `--director` restarts) accumulates 2 dangling
18883
+ * listeners per Director on the FleetBus, slowly drifting the
18884
+ * EventEmitter past its default cap. Mirrors the rationale on
18885
+ * `taskCompletedListener` above.
18886
+ */
18887
+ toolExecFilter = null;
18888
+ budgetFilter = null;
18682
18889
  /** Optional LLM classifier for smart dispatch. Passed from options. */
18683
18890
  dispatchClassifier;
18684
18891
  /** Leader agent's current context pressure (full request tokens). */
@@ -18816,10 +19023,10 @@ var Director = class _Director {
18816
19023
  const extendCounts = /* @__PURE__ */ new Map();
18817
19024
  const progressBySubagent = /* @__PURE__ */ new Map();
18818
19025
  const lastTimeoutProgress = /* @__PURE__ */ new Map();
18819
- this.fleet.filter("tool.executed", (e) => {
19026
+ this.toolExecFilter = this.fleet.filter("tool.executed", (e) => {
18820
19027
  progressBySubagent.set(e.subagentId, (progressBySubagent.get(e.subagentId) ?? 0) + 1);
18821
19028
  });
18822
- this.fleet.filter("budget.threshold_reached", (e) => {
19029
+ this.budgetFilter = this.fleet.filter("budget.threshold_reached", (e) => {
18823
19030
  const payload = e.payload;
18824
19031
  if (e.subagentId.startsWith("bug-hunter-") || e.subagentId.startsWith("refactor-planner-") || e.subagentId.startsWith("critic-")) {
18825
19032
  return;
@@ -19350,6 +19557,14 @@ var Director = class _Director {
19350
19557
  this.coordinator.off("task.completed", this.taskCompletedListener);
19351
19558
  this.taskCompletedListener = null;
19352
19559
  }
19560
+ if (this.toolExecFilter) {
19561
+ this.toolExecFilter();
19562
+ this.toolExecFilter = null;
19563
+ }
19564
+ if (this.budgetFilter) {
19565
+ this.budgetFilter();
19566
+ this.budgetFilter = null;
19567
+ }
19353
19568
  await this.coordinator.stopAll();
19354
19569
  for (const b of this.subagentBridges.values()) {
19355
19570
  await b.stop().catch((err) => this.logShutdownError("subagent_bridge_stop", err));
@@ -28728,15 +28943,15 @@ function createMcpControlTool(opts) {
28728
28943
  properties: {
28729
28944
  action: {
28730
28945
  type: "string",
28731
- enum: ["list", "search", "enable", "disable", "restart"],
28732
- description: "The management action to perform."
28946
+ enum: ["list", "search", "enable", "disable", "restart", "activate", "deactivate"],
28947
+ description: "The management action to perform. activate/deactivate toggle tool registration ephemerally without disconnecting."
28733
28948
  },
28734
28949
  /** Filter for `search`. Matches server name or description case-insensitively. */
28735
28950
  query: {
28736
28951
  type: "string",
28737
28952
  description: "Search term for `search` action. Matches server name or description."
28738
28953
  },
28739
- /** Target server name for `enable`, `disable`, `restart`. */
28954
+ /** Target server name for `enable`, `disable`, `restart`, `activate`, `deactivate`. */
28740
28955
  server: {
28741
28956
  type: "string",
28742
28957
  description: 'Server name (e.g. "github", "filesystem", "brave-search").'
@@ -28746,7 +28961,7 @@ function createMcpControlTool(opts) {
28746
28961
  };
28747
28962
  return {
28748
28963
  name: "mcp_control",
28749
- description: "Manage MCP server lifecycle: list available servers, search by name or capability, enable or disable servers at runtime, restart running servers.",
28964
+ description: "Manage MCP server lifecycle: list available servers, search by name or capability, enable or disable servers at runtime, restart running servers. Use activate/deactivate to ephemerally toggle tool registration without disconnecting \u2014 ideal for token-saving mode where MCP tools are lazy-loaded on demand.",
28750
28965
  category: "mcp",
28751
28966
  permission: "auto",
28752
28967
  mutating: true,
@@ -28771,8 +28986,12 @@ async function mcpControlDispatch(input, deps) {
28771
28986
  return server ? runDisable(server, deps) : "`server` is required for disable.";
28772
28987
  case "restart":
28773
28988
  return server ? runRestart(server, deps) : "`server` is required for restart.";
28989
+ case "activate":
28990
+ return server ? runActivate(server, deps) : "`server` is required for activate.";
28991
+ case "deactivate":
28992
+ return server ? runDeactivate(server, deps) : "`server` is required for deactivate.";
28774
28993
  default:
28775
- return `Unknown action "${action}". Use one of: list, search, enable, disable, restart.`;
28994
+ return `Unknown action "${action}". Use one of: list, search, enable, disable, restart, activate, deactivate.`;
28776
28995
  }
28777
28996
  }
28778
28997
  function renderList(deps) {
@@ -28897,6 +29116,36 @@ async function runRestart(name, deps) {
28897
29116
  return `${red("\u2717 Restart failed")} for "${name}": ${err instanceof Error ? err.message : String(err)}`;
28898
29117
  }
28899
29118
  }
29119
+ async function runActivate(name, deps) {
29120
+ if (!name) return "`server` is required for activate.";
29121
+ if (!deps.registry.activateServer) {
29122
+ return `Registry does not support ephemeral activation. Use \`enable\` to start "${name}" instead.`;
29123
+ }
29124
+ const live = deps.registry.describe().find((s) => s.name === name);
29125
+ if (!live) {
29126
+ return `Server "${name}" is not registered. Use \`mcp_control({ action: "enable", server: "${name}" })\` first.`;
29127
+ }
29128
+ if (live.state !== "connected") {
29129
+ return `Server "${name}" is not connected (state: ${live.state}). Use \`enable\` to start it first.`;
29130
+ }
29131
+ if (deps.registry.isActivated?.(name)) {
29132
+ return `${green("\u25CF")} Server "${name}" tools are already active. Use \`deactivate\` to hide them.`;
29133
+ }
29134
+ deps.registry.activateServer(name);
29135
+ const updated = deps.registry.describe().find((s) => s.name === name);
29136
+ return `${green("\u2713 Activated")} "${name}" \u2014 ${updated?.toolCount ?? 0} tool(s) now registered. Use \`mcp_control({ action: "deactivate", server: "${name}" })\` to hide them when done.`;
29137
+ }
29138
+ async function runDeactivate(name, deps) {
29139
+ if (!name) return "`server` is required for deactivate.";
29140
+ if (!deps.registry.deactivateServer) {
29141
+ return `Registry does not support ephemeral deactivation. Use \`disable\` to stop "${name}" instead.`;
29142
+ }
29143
+ if (!deps.registry.isActivated?.(name)) {
29144
+ return `Server "${name}" tools are not currently active.`;
29145
+ }
29146
+ const count = deps.registry.deactivateServer(name);
29147
+ return `${yellow("\u25CB Deactivated")} "${name}" \u2014 ${count} tool(s) unregistered. Server stays connected.`;
29148
+ }
28900
29149
  async function readConfig(p) {
28901
29150
  try {
28902
29151
  return JSON.parse(await fsp3.readFile(p, "utf8"));
@@ -28942,6 +29191,70 @@ function badge(state) {
28942
29191
  }
28943
29192
  }
28944
29193
 
29194
+ // src/tools/mcp-use.ts
29195
+ function createMcpUseTool(opts) {
29196
+ const { registry, toolRegistry } = opts;
29197
+ const inputSchema = {
29198
+ type: "object",
29199
+ properties: {
29200
+ server: {
29201
+ type: "string",
29202
+ description: 'MCP server name (e.g. "github", "filesystem", "brave-search"). Use mcp_control list or search first to discover available servers.'
29203
+ },
29204
+ tool: {
29205
+ type: "string",
29206
+ description: "Tool name on the MCP server to call (without the mcp__server__ prefix \u2014 just the bare tool name)."
29207
+ },
29208
+ input: {
29209
+ type: "object",
29210
+ description: "JSON input to pass to the tool. Use the tool's own input schema \u2014 check with mcp_control describe or the server's documentation.",
29211
+ properties: {},
29212
+ additionalProperties: true
29213
+ }
29214
+ },
29215
+ required: ["server", "tool", "input"]
29216
+ };
29217
+ return {
29218
+ name: "mcp_use",
29219
+ description: "Call an MCP tool on a lazy-loaded server. Activates the server temporarily, calls the tool, returns the result, and deactivates. Use this instead of the manual activate\u2192use\u2192deactivate cycle. First call mcp_control list/search to find the right server and tool name.",
29220
+ category: "mcp",
29221
+ permission: "auto",
29222
+ mutating: true,
29223
+ riskTier: "standard",
29224
+ inputSchema,
29225
+ async execute(raw) {
29226
+ const input = raw;
29227
+ const { server: serverName, tool: toolName, input: toolInput } = input;
29228
+ const servers = registry.describe();
29229
+ const serverInfo = servers.find((s) => s.name === serverName);
29230
+ if (!serverInfo) {
29231
+ return `Server "${serverName}" not found. Available: ${servers.map((s) => s.name).join(", ") || "none"}.`;
29232
+ }
29233
+ if (serverInfo.state !== "connected") {
29234
+ return `Server "${serverName}" is not connected (state: ${serverInfo.state}). Use \`mcp_control({ action: "enable", server: "${serverName}" })\` first.`;
29235
+ }
29236
+ if (registry.activateServer) {
29237
+ registry.activateServer(serverName);
29238
+ }
29239
+ try {
29240
+ const qualifiedName = `mcp__${serverName}__${toolName}`;
29241
+ const mcpTool = toolRegistry.get(qualifiedName);
29242
+ if (!mcpTool) {
29243
+ const allTools = toolRegistry.list().filter((t2) => t2.name.startsWith(`mcp__${serverName}__`)).map((t2) => t2.name.replace(`mcp__${serverName}__`, ""));
29244
+ const hint = allTools.length > 0 ? `Available tools on "${serverName}": ${allTools.join(", ")}.` : `No tools found on "${serverName}". The server may not have published any tools.`;
29245
+ return `Tool "${toolName}" not found on server "${serverName}". ${hint}`;
29246
+ }
29247
+ const result = await mcpTool.execute(toolInput ?? {}, {}, {});
29248
+ return result;
29249
+ } finally {
29250
+ if (registry.deactivateServer) {
29251
+ registry.deactivateServer(serverName);
29252
+ }
29253
+ }
29254
+ }
29255
+ };
29256
+ }
29257
+
28945
29258
  // src/extension/registry.ts
28946
29259
  var ExtensionRegistry = class {
28947
29260
  extensions = [];
@@ -29168,7 +29481,7 @@ function createAgentToolHandler(a) {
29168
29481
  a.ctx,
29169
29482
  a.perIterationOutputCapBytes
29170
29483
  );
29171
- return { result, durationMs: Date.now() - start };
29484
+ return { result: result.block, durationMs: Date.now() - start };
29172
29485
  } catch (err) {
29173
29486
  const msg = err instanceof Error ? err.message : String(err);
29174
29487
  return {
@@ -29310,9 +29623,10 @@ function createAgentToolHandler(a) {
29310
29623
  // src/core/continue-to-next-iteration.ts
29311
29624
  function parseContinueDirective(text) {
29312
29625
  const LINE_MARKERS = /^\s*\[(continue|next step|proceed|done)\]\s*$/gim;
29626
+ const tail = text.length <= DIRECTIVE_SCAN_WINDOW ? text : text.slice(text.length - DIRECTIVE_SCAN_WINDOW);
29313
29627
  let match;
29314
29628
  let lastDirective = "none";
29315
- while ((match = LINE_MARKERS.exec(text)) !== null) {
29629
+ while ((match = LINE_MARKERS.exec(tail)) !== null) {
29316
29630
  const value = (match[1] ?? "").toLowerCase();
29317
29631
  if (value === "continue" || value === "next step" || value === "proceed") {
29318
29632
  lastDirective = "continue";
@@ -29322,6 +29636,7 @@ function parseContinueDirective(text) {
29322
29636
  }
29323
29637
  return lastDirective;
29324
29638
  }
29639
+ var DIRECTIVE_SCAN_WINDOW = 2048;
29325
29640
  var META_KEY = "_autonomousContinue";
29326
29641
  function setAutonomousContinue(ctx) {
29327
29642
  ctx.meta[META_KEY] = true;
@@ -29404,21 +29719,22 @@ function createAgentResponseHandler(a) {
29404
29719
  });
29405
29720
  await a.ctx.session.flush();
29406
29721
  if (a.ctx.signal.aborted) {
29407
- let finalText2 = "";
29722
+ const parts2 = [];
29408
29723
  for (const block of res.content) {
29409
- if (isTextBlock(block)) finalText2 += block.text;
29724
+ if (isTextBlock(block)) parts2.push(block.text);
29410
29725
  }
29411
- return { finalText: finalText2, aborted: true, done: false };
29726
+ return { finalText: parts2.join(""), aborted: true, done: false };
29412
29727
  }
29413
- let finalText = "";
29728
+ const parts = [];
29414
29729
  const streamed = a.ctx.provider.capabilities.streaming;
29415
29730
  for (const block of res.content) {
29416
29731
  if (isTextBlock(block)) {
29417
29732
  const rendered = await a.pipelines.assistantOutput.run(block);
29418
- finalText += rendered.text;
29733
+ parts.push(rendered.text);
29419
29734
  if (!streamed) a.renderer?.write(rendered);
29420
29735
  }
29421
29736
  }
29737
+ const finalText = parts.join("");
29422
29738
  let directive = "none";
29423
29739
  if (finalText) {
29424
29740
  directive = parseContinueDirective(finalText);
@@ -30436,7 +30752,16 @@ function signalAbortReason(signal) {
30436
30752
  function createAgentLoopHandler(a, handlers) {
30437
30753
  const checkMailbox = attachMailboxChecker(a);
30438
30754
  async function compactContextIfNeeded() {
30755
+ const msgCount = a.ctx.messages.length;
30756
+ if (_lastCompactionMsgCount === msgCount && _lastCompactionWasNoop && _maxContext > 0) {
30757
+ return;
30758
+ }
30439
30759
  await a.pipelines.contextWindow.run(a.ctx);
30760
+ _lastCompactionMsgCount = msgCount;
30761
+ const stashed = a.ctx.lastRequestTokens;
30762
+ const tokens = typeof stashed === "number" && stashed > 0 ? stashed : 0;
30763
+ const load = _maxContext > 0 ? tokens / _maxContext : 0;
30764
+ _lastCompactionWasNoop = tokens > 0 && load < 0.5;
30440
30765
  }
30441
30766
  const calibrationKey = (model = a.ctx.model) => `${a.ctx.provider?.id ?? "unknown"}/${model}`;
30442
30767
  function emitContextPct() {
@@ -30447,22 +30772,42 @@ function createAgentLoopHandler(a, handlers) {
30447
30772
  }
30448
30773
  _lastEmittedMsgCount = msgCount;
30449
30774
  _lastEmittedToolCount = toolCount;
30775
+ if (msgCount !== _lastPreFlightMsgCount) {
30776
+ a.ctx.lastRequestTokens = estimateRequestTokens(
30777
+ a.ctx.messages,
30778
+ a.ctx.systemPrompt,
30779
+ a.ctx.tools ?? []
30780
+ ).total;
30781
+ _lastPreFlightMsgCount = msgCount;
30782
+ a.ctx.meta["lastRequestTokensAt"] = { msgCount, toolCount };
30783
+ }
30450
30784
  if (!_maxContext) {
30451
30785
  const metaLimit = a.ctx.meta?.["effectiveMaxContext"];
30452
30786
  const providerMax = a.ctx.provider.capabilities.maxContext;
30453
30787
  _maxContext = typeof metaLimit === "number" && metaLimit > 0 ? metaLimit : typeof providerMax === "number" && providerMax > 0 ? providerMax : 2e5;
30454
30788
  }
30455
- const { total } = estimateRequestTokensCalibrated(
30456
- a.ctx.messages,
30457
- a.ctx.systemPrompt,
30458
- a.ctx.tools ?? [],
30459
- calibrationKey()
30460
- );
30789
+ let total;
30790
+ const stashed = a.ctx.lastRequestTokens;
30791
+ if (typeof stashed === "number" && stashed > 0) {
30792
+ const cal = getCalibrationState(calibrationKey());
30793
+ total = cal.calibrated ? Math.round(stashed * Math.min(1.5, Math.max(0.5, cal.ratio))) : stashed;
30794
+ } else {
30795
+ const est = estimateRequestTokensCalibrated(
30796
+ a.ctx.messages,
30797
+ a.ctx.systemPrompt,
30798
+ a.ctx.tools ?? [],
30799
+ calibrationKey()
30800
+ );
30801
+ total = est.total;
30802
+ }
30461
30803
  a.events.emit("ctx.pct", { load: total / _maxContext, tokens: total, maxContext: _maxContext });
30462
30804
  }
30463
30805
  let _maxContext = 0;
30464
30806
  let _lastEmittedMsgCount = -1;
30465
30807
  let _lastEmittedToolCount = -1;
30808
+ let _lastPreFlightMsgCount = -1;
30809
+ let _lastCompactionMsgCount = -1;
30810
+ let _lastCompactionWasNoop = false;
30466
30811
  function foldBlockIntoConversation(block) {
30467
30812
  const messages = a.ctx.messages;
30468
30813
  const last = messages[messages.length - 1];
@@ -30580,6 +30925,12 @@ function createAgentLoopHandler(a, handlers) {
30580
30925
  });
30581
30926
  const req = await handlers.response.buildAndRunRequestPipeline(opts);
30582
30927
  const preFlight = estimateRequestTokens(req.messages, req.system, req.tools ?? []);
30928
+ a.ctx.lastRequestTokens = preFlight.total;
30929
+ _lastPreFlightMsgCount = req.messages.length;
30930
+ a.ctx.meta["lastRequestTokensAt"] = {
30931
+ msgCount: req.messages.length,
30932
+ toolCount: (req.tools ?? []).length
30933
+ };
30583
30934
  await a.ctx.session.append({
30584
30935
  type: "llm_request",
30585
30936
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -31275,6 +31626,10 @@ function flagsToConfigPatch(flags) {
31275
31626
  skills: false
31276
31627
  };
31277
31628
  }
31629
+ if (flags["token-saving-mode"]) {
31630
+ patch.features ??= {};
31631
+ patch.features.tokenSavingMode = true;
31632
+ }
31278
31633
  return patch;
31279
31634
  }
31280
31635
  async function writeProjectMeta(paths, projectRoot) {
@@ -31576,14 +31931,15 @@ Never silently skip a failure \u2014 always report it, even when you choose not
31576
31931
  ## After-task suggestions
31577
31932
 
31578
31933
  After completing a significant task, end your response with 2\u20134 suggested next
31579
- actions under a \`\u{1F4A1} Next steps\` heading. Use this format so the user can
31934
+ actions in a \`<next_steps>\` block. Use this exact format so the user can
31580
31935
  select them with \`/next 1\`, \`/next 2\`, or \`/next 1 2 3\`:
31581
31936
 
31582
31937
  \`\`\`
31583
- \u{1F4A1} Next steps
31938
+ <next_steps>
31584
31939
  1. First suggestion \u2014 imperative, specific, actionable
31585
31940
  2. Second suggestion
31586
31941
  3. Third suggestion
31942
+ </next_steps>
31587
31943
  \`\`\`
31588
31944
 
31589
31945
  Rules:
@@ -31621,6 +31977,10 @@ var DefaultSystemPromptBuilder = class {
31621
31977
  skillBodyCache;
31622
31978
  /** Tools from last build — used for memory relevance scoring. */
31623
31979
  _lastBuildTools;
31980
+ /** Cached rendered online agents string, keyed by array reference. */
31981
+ _lastOnlineAgents;
31982
+ /** Cached full buildToolUsage output — keyed by tools array + online agents refs. */
31983
+ _toolsUsageCache;
31624
31984
  async build(ctx) {
31625
31985
  this._lastBuildTools = ctx.tools;
31626
31986
  if (this.opts.skillLoader && !this.skillCache) {
@@ -31756,6 +32116,9 @@ var DefaultSystemPromptBuilder = class {
31756
32116
  }
31757
32117
  buildToolUsage(tools, ctx) {
31758
32118
  if (tools.length === 0) return "## Tool usage\n\nNo tools registered.";
32119
+ if (this._toolsUsageCache?.toolsRef === tools && this._toolsUsageCache?.agentsRef === ctx.onlineAgents) {
32120
+ return this._toolsUsageCache.text;
32121
+ }
31759
32122
  const byCat = /* @__PURE__ */ new Map();
31760
32123
  const uncategorized = [];
31761
32124
  for (const t2 of tools) {
@@ -31776,7 +32139,7 @@ var DefaultSystemPromptBuilder = class {
31776
32139
  ### ${cat}`);
31777
32140
  for (const t2 of catTools) {
31778
32141
  const hint = t2.usageHint ?? t2.description;
31779
- const desc = hint.length > 80 ? `${hint.slice(0, 77)}...` : hint.trim();
32142
+ const desc = this.opts.tokenSavingMode ? hint.length > 60 ? hint.slice(0, hint.indexOf(".", 20) + 1 || 60) + (hint.length > 60 ? "\u2026" : "") : hint.trim() : hint.length > 80 ? `${hint.slice(0, 77)}...` : hint.trim();
31780
32143
  lines.push(`- **${t2.name}** \u2014 ${desc}`);
31781
32144
  }
31782
32145
  }
@@ -31789,7 +32152,8 @@ var DefaultSystemPromptBuilder = class {
31789
32152
  ${hint.trim()}`);
31790
32153
  }
31791
32154
  }
31792
- lines.push(`
32155
+ if (!this.opts.tokenSavingMode) {
32156
+ lines.push(`
31793
32157
  ## Common patterns
31794
32158
 
31795
32159
  - **Inspect before edit:** \`read\`/\`glob\`/\`grep\` \u2192 locate target \u2192 \`edit\`
@@ -31799,6 +32163,7 @@ ${hint.trim()}`);
31799
32163
  - **Batch ops:** Use \`replace\` with glob patterns for multi-file surgical changes
31800
32164
 
31801
32165
  When unsure about a file's current state, read it first rather than assuming.`);
32166
+ }
31802
32167
  const hasDelegate = tools.some((t2) => t2.name === "delegate");
31803
32168
  if (hasDelegate) {
31804
32169
  const delegateTool = tools.find((t2) => t2.name === "delegate");
@@ -31807,7 +32172,12 @@ When unsure about a file's current state, read it first rather than assuming.`);
31807
32172
  return Array.isArray(role) ? role.filter((r) => typeof r === "string") : [];
31808
32173
  })();
31809
32174
  const roleList = enumValues.length > 0 ? enumValues.join(", ") : "(no roster configured)";
31810
- lines.push(`
32175
+ if (this.opts.tokenSavingMode) {
32176
+ lines.push(`## Delegation
32177
+
32178
+ Use \`delegate\` to hand work to a subagent (roles: ${roleList}).`);
32179
+ } else {
32180
+ lines.push(`
31811
32181
  ## Delegation
31812
32182
 
31813
32183
  You have a \`delegate\` tool that hands a discrete piece of work to a
@@ -31870,21 +32240,20 @@ it's called \u2014 you do not need to call any setup tool. For fine-grained
31870
32240
  control over a long-running fleet (spawn N workers, hand them tasks
31871
32241
  one by one, roll up results), use \`spawn_subagent\` + \`assign_task\` +
31872
32242
  \`await_tasks\` directly; \`delegate\` is the one-call shortcut.`);
32243
+ }
31873
32244
  }
31874
32245
  const hasMailbox = tools.some(
31875
32246
  (t2) => t2.name === "mailbox" || t2.name === "mail_send" || t2.name === "mail_inbox"
31876
32247
  );
31877
32248
  if (hasMailbox) {
31878
- let onlineAgentsInfo = "";
31879
- if (ctx.onlineAgents && ctx.onlineAgents.length > 0) {
31880
- const totalCount = ctx.onlineAgents.length;
31881
- const agentList = ctx.onlineAgents.map((a) => `- **${a.name}** (${a.source ?? "unknown"}${a.sessionId ? `, session: ${a.sessionId.slice(0, 8)}` : ""})`).join("\n");
31882
- onlineAgentsInfo = `
32249
+ const onlineAgentsInfo = this.renderOnlineAgents(ctx.onlineAgents);
32250
+ if (this.opts.tokenSavingMode) {
32251
+ lines.push(`
32252
+ ## Inter-agent mailbox${onlineAgentsInfo}
31883
32253
 
31884
- **Currently online (${totalCount} agent${totalCount !== 1 ? "s" : ""}):**
31885
- ${agentList}`;
31886
- }
31887
- lines.push(`
32254
+ Use \`mail_inbox\` for new messages, \`mail_send\` to communicate with other agents.`);
32255
+ } else {
32256
+ lines.push(`
31888
32257
  ## Inter-agent mailbox${onlineAgentsInfo}
31889
32258
 
31890
32259
  You share a persistent project mailbox with every other agent working on
@@ -31943,9 +32312,52 @@ inline, the rest as a summary. To catch up explicitly:
31943
32312
 
31944
32313
  - \`mailbox action=ack messageId=<id> completed=true outcome="What you did"\`
31945
32314
  - Messages you \`check\` are auto-marked as read; use \`ack\` to mark complete.`);
32315
+ }
32316
+ }
32317
+ const hasMcpControl = tools.some((t2) => t2.name === "mcp_control");
32318
+ const hasMcpUse = tools.some((t2) => t2.name === "mcp_use");
32319
+ if (hasMcpControl && this.opts.tokenSavingMode) {
32320
+ if (hasMcpUse) {
32321
+ lines.push(`
32322
+ ## MCP tools (lazy-loaded)
32323
+
32324
+ MCP server tools are NOT registered by default in token-saving mode to keep
32325
+ the prompt compact. Each server's process is running in the background; only
32326
+ tool registration is deferred.
32327
+
32328
+ **Preferred approach** \u2014 one-shot meta-tool:
32329
+ \`mcp_use({ server: "<name>", tool: "<bare-tool>", input: { ... } })\`
32330
+ This activates the server, calls the tool, returns the result, and
32331
+ deactivates \u2014 all in one call. No need to track activate/deactivate state.
32332
+
32333
+ **Manual approach** (for exploration):
32334
+ 1. \`mcp_control({ action: "list" })\` \u2014 see which servers are connected
32335
+ 2. \`mcp_control({ action: "activate", server: "<name>" })\` \u2014 register tools
32336
+ 3. Use the tools normally
32337
+ 4. \`mcp_control({ action: "deactivate", server: "<name>" })\` \u2014 clean up
32338
+
32339
+ Activation/deactivation is ephemeral (no config writes) and does NOT affect
32340
+ the server connection \u2014 only tool visibility changes.`);
32341
+ } else {
32342
+ lines.push(`
32343
+ ## MCP tools (lazy-loaded)
32344
+
32345
+ MCP server tools are NOT registered by default in token-saving mode to keep
32346
+ the prompt compact. Each server's process is running in the background; only
32347
+ tool registration is deferred.
32348
+
32349
+ When you need a specific MCP server's tools:
32350
+ 1. \`mcp_control({ action: "list" })\` \u2014 see which servers are connected
32351
+ 2. \`mcp_control({ action: "activate", server: "<name>" })\` \u2014 register its tools
32352
+ 3. Use the tools as needed
32353
+ 4. \`mcp_control({ action: "deactivate", server: "<name>" })\` \u2014 unregister when done
32354
+
32355
+ Activation/deactivation is ephemeral (no config writes) and does NOT affect
32356
+ the server connection \u2014 only tool visibility changes.`);
32357
+ }
31946
32358
  }
31947
32359
  const hasContextManager = tools.some((t2) => t2.name === "context_manager");
31948
- if (hasContextManager) {
32360
+ if (hasContextManager && !this.opts.tokenSavingMode) {
31949
32361
  const maxCtx = this.opts.modelCapabilities?.maxContextTokens ?? 128e3;
31950
32362
  const threshold = maxCtx <= 32e3 ? "50" : "70";
31951
32363
  lines.push(`
@@ -31962,7 +32374,32 @@ use the context_manager tool proactively \u2014 do NOT wait to be told:
31962
32374
  **Never** stuff redundant information into a tool result. If you summarize a file, do not paste its full content \u2014
31963
32375
  summarize it, and let the tool result hold only the summary.`);
31964
32376
  }
31965
- return lines.join("\n");
32377
+ const text = lines.join("\n");
32378
+ this._toolsUsageCache = { toolsRef: tools, agentsRef: ctx.onlineAgents, text };
32379
+ return text;
32380
+ }
32381
+ /**
32382
+ * Render the online agents list, cached by array reference. The agents
32383
+ * list changes at join/leave pace (seconds to minutes), not every prompt
32384
+ * build turn (hundreds of ms). Reference equality avoids re-stringifying
32385
+ * the same array on every iteration while still being correct when the
32386
+ * caller passes a fresh array.
32387
+ */
32388
+ renderOnlineAgents(agents) {
32389
+ if (!agents || agents.length === 0) return "";
32390
+ if (this._lastOnlineAgents?.ref === agents) {
32391
+ return this._lastOnlineAgents.text;
32392
+ }
32393
+ const totalCount = agents.length;
32394
+ const agentList = agents.map(
32395
+ (a) => `- **${a.name}** (${a.source ?? "unknown"}${a.sessionId ? `, session: ${a.sessionId.slice(0, 8)}` : ""})`
32396
+ ).join("\n");
32397
+ const text = `
32398
+
32399
+ **Currently online (${totalCount} agent${totalCount !== 1 ? "s" : ""}):**
32400
+ ${agentList}`;
32401
+ this._lastOnlineAgents = { ref: agents, text };
32402
+ return text;
31966
32403
  }
31967
32404
  async buildEnvironment(ctx) {
31968
32405
  const cached = this.envCacheByRoot.get(ctx.projectRoot);
@@ -32005,7 +32442,7 @@ summarize it, and let the tool result hold only the summary.`);
32005
32442
  "## Skills in scope for this session",
32006
32443
  this.skillCache,
32007
32444
  "",
32008
- "Full skill instructions are injected in the Active Skills block below."
32445
+ this.opts.tokenSavingMode ? "Compact skill instructions are injected in the Active Skills block below (Overview + Rules only)." : "Full skill instructions are injected in the Active Skills block below."
32009
32446
  );
32010
32447
  }
32011
32448
  const text = lines.join("\n");
@@ -32044,41 +32481,83 @@ ${mem}`);
32044
32481
  } catch {
32045
32482
  }
32046
32483
  }
32047
- if (this.opts.skillLoader && this.skillBodyCache === void 0) {
32048
- try {
32049
- const skills = await this.opts.skillLoader.list();
32050
- if (skills.length > 0) {
32051
- const bodies = [];
32052
- for (const s of skills) {
32053
- try {
32054
- const raw = await this.opts.skillLoader.readBody(s.name);
32055
- const body = stripFrontmatter(raw);
32056
- if (body.trim()) {
32057
- bodies.push(`## Skill: ${s.name}
32484
+ if (this.opts.skillLoader) {
32485
+ if (this.opts.tokenSavingMode) {
32486
+ if (this.skillBodyCache === void 0) {
32487
+ await this.buildCompactSkillBodies();
32488
+ }
32489
+ } else {
32490
+ if (this.skillBodyCache === void 0) {
32491
+ await this.buildFullSkillBodies();
32492
+ }
32493
+ }
32494
+ }
32495
+ if (this.skillBodyCache) {
32496
+ parts.push(`# Active Skills
32497
+
32498
+ ${this.skillBodyCache}`);
32499
+ }
32500
+ return parts.join("\n\n");
32501
+ }
32502
+ /** Build full skill bodies (token-saving OFF). */
32503
+ async buildFullSkillBodies() {
32504
+ try {
32505
+ const skills = await this.opts.skillLoader.list();
32506
+ if (skills.length > 0) {
32507
+ const bodies = [];
32508
+ for (const s of skills) {
32509
+ try {
32510
+ const raw = await this.opts.skillLoader.readBody(s.name);
32511
+ const body = stripFrontmatter2(raw);
32512
+ if (body.trim()) {
32513
+ bodies.push(`## Skill: ${s.name}
32058
32514
 
32059
32515
  ${body.trim()}`);
32060
- }
32061
- } catch {
32062
32516
  }
32517
+ } catch {
32063
32518
  }
32064
- if (bodies.length > 0) {
32065
- this.skillBodyCache = bodies.join("\n\n---\n\n");
32066
- } else {
32067
- this.skillBodyCache = "";
32068
- }
32069
- } else {
32070
- this.skillBodyCache = "";
32071
32519
  }
32072
- } catch {
32520
+ this.skillBodyCache = bodies.length > 0 ? bodies.join("\n\n---\n\n") : "";
32521
+ } else {
32073
32522
  this.skillBodyCache = "";
32074
32523
  }
32524
+ } catch {
32525
+ this.skillBodyCache = "";
32075
32526
  }
32076
- if (this.skillBodyCache) {
32077
- parts.push(`# Active Skills
32527
+ }
32528
+ /**
32529
+ * Build compact skill bodies for token-saving mode.
32530
+ * Uses `readSaveBody` from the skill loader which tries `SKILL.save.md`
32531
+ * first, then falls back to auto-compaction.
32532
+ */
32533
+ async buildCompactSkillBodies() {
32534
+ if (!this.opts.skillLoader) {
32535
+ this.skillBodyCache = "";
32536
+ return;
32537
+ }
32538
+ try {
32539
+ const skills = await this.opts.skillLoader.list();
32540
+ if (skills.length > 0) {
32541
+ const bodies = [];
32542
+ for (const s of skills) {
32543
+ try {
32544
+ const saveBody = await this.opts.skillLoader.readSaveBody(s.name);
32545
+ const clean = stripFrontmatter2(saveBody);
32546
+ if (clean.trim()) {
32547
+ bodies.push(`## Skill: ${s.name}
32078
32548
 
32079
- ${this.skillBodyCache}`);
32549
+ ${clean.trim()}`);
32550
+ }
32551
+ } catch {
32552
+ }
32553
+ }
32554
+ this.skillBodyCache = bodies.length > 0 ? bodies.join("\n\n---\n\n") : "";
32555
+ } else {
32556
+ this.skillBodyCache = "";
32557
+ }
32558
+ } catch {
32559
+ this.skillBodyCache = "";
32080
32560
  }
32081
- return parts.join("\n\n");
32082
32561
  }
32083
32562
  async buildMode() {
32084
32563
  if (this.opts.modePrompt) return this.opts.modePrompt;
@@ -32168,7 +32647,7 @@ ${this.skillBodyCache}`);
32168
32647
  return langs.size === 0 ? "unknown" : Array.from(langs).join(", ");
32169
32648
  }
32170
32649
  };
32171
- function stripFrontmatter(raw) {
32650
+ function stripFrontmatter2(raw) {
32172
32651
  if (!raw.startsWith("---")) return raw;
32173
32652
  const end = raw.indexOf("\n---", 4);
32174
32653
  if (end === -1) return raw;
@@ -32188,6 +32667,11 @@ function compactTrigger(trigger) {
32188
32667
  // src/registry/tool-registry.ts
32189
32668
  var ToolRegistry = class _ToolRegistry {
32190
32669
  tools = /* @__PURE__ */ new Map();
32670
+ /** Monotonic version bumped on every registry mutation. */
32671
+ _version = 0;
32672
+ /** Cached `list()` result, frozen after build. Invalidated on _version change. */
32673
+ _listSnapshot;
32674
+ _listSnapshotVersion = -1;
32191
32675
  /** Pre-compute tool definition token estimate once at registration time. */
32192
32676
  _stampDefTokens(tool) {
32193
32677
  if (tool._estDefTokens === void 0) {
@@ -32213,6 +32697,7 @@ var ToolRegistry = class _ToolRegistry {
32213
32697
  }
32214
32698
  this._stampDefTokens(tool);
32215
32699
  this.tools.set(tool.name, { tool, owner });
32700
+ this._version++;
32216
32701
  }
32217
32702
  /**
32218
32703
  * Attempt to register a tool. Returns true if successful, false if a tool
@@ -32226,6 +32711,7 @@ var ToolRegistry = class _ToolRegistry {
32226
32711
  }
32227
32712
  this._stampDefTokens(tool);
32228
32713
  this.tools.set(tool.name, { tool, owner });
32714
+ this._version++;
32229
32715
  return true;
32230
32716
  }
32231
32717
  /**
@@ -32297,6 +32783,7 @@ var ToolRegistry = class _ToolRegistry {
32297
32783
  wrapped._estDefTokens = void 0;
32298
32784
  this._stampDefTokens(wrapped);
32299
32785
  this.tools.set(name, { tool: wrapped, owner: `${entry.owner}+${owner}` });
32786
+ this._version++;
32300
32787
  }
32301
32788
  get(name) {
32302
32789
  return this.tools.get(name)?.tool;
@@ -32305,7 +32792,13 @@ var ToolRegistry = class _ToolRegistry {
32305
32792
  return this.tools.get(name)?.owner;
32306
32793
  }
32307
32794
  list() {
32308
- return Array.from(this.tools.values()).map((e) => e.tool);
32795
+ if (this._listSnapshot && this._version === this._listSnapshotVersion) {
32796
+ return this._listSnapshot;
32797
+ }
32798
+ const arr = Array.from(this.tools.values()).map((e) => e.tool);
32799
+ this._listSnapshot = arr;
32800
+ this._listSnapshotVersion = this._version;
32801
+ return arr;
32309
32802
  }
32310
32803
  /**
32311
32804
  * Group tools by their `category` field. Tools without a category
@@ -32553,14 +33046,19 @@ var DefaultPluginAPI = class {
32553
33046
  this.pipelines = readonlyPipelines;
32554
33047
  const tr = init.toolRegistry;
32555
33048
  const isOfficial = init.official === true;
33049
+ const capabilities = init.capabilities;
32556
33050
  const assertCanMutateTool = (name, op) => {
32557
33051
  if (isOfficial) return;
32558
33052
  const currentOwner = tr.ownerOf(name);
32559
33053
  if (currentOwner === void 0) return;
32560
33054
  const ownedSolelyByMe = currentOwner.split("+").every((seg) => seg === owner);
32561
- if (!ownedSolelyByMe) {
33055
+ if (ownedSolelyByMe) return;
33056
+ const toolCaps = tr.get(name)?.capabilities ?? [];
33057
+ const pluginMutateCaps = capabilities?.toolMutateCapabilities ?? [];
33058
+ const hasRequiredCap = toolCaps.some((c) => pluginMutateCaps.includes(c));
33059
+ if (!hasRequiredCap) {
32562
33060
  throw new Error(
32563
- `Plugin "${owner}" may not ${op} tool "${name}" \u2014 it is owned by "${currentOwner}". Only official (first-party) plugins may modify tools they do not own.`
33061
+ `Plugin "${owner}" may not ${op} tool "${name}" \u2014 it is owned by "${currentOwner}". Tool capabilities: [${toolCaps.join(", ") || "none"}]. Plugin toolMutateCapabilities: [${pluginMutateCaps.join(", ") || "none"}]. Missing required capability to mutate this tool.`
32564
33062
  );
32565
33063
  }
32566
33064
  };
@@ -37747,6 +38245,6 @@ function createChimeraPlugin() {
37747
38245
  };
37748
38246
  }
37749
38247
 
37750
- export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, ALL_SYNC_CATEGORIES, AUDIT_LOG_AGENT, Agent, AgentError, AgentStatusTracker, AnnotationsStore, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutoPhasePlanner, AutoPhaseRunner, AutonomousRunner, BUG_HUNTER_AGENT, BrainDecisionQueue, BrainMonitor, BudgetExceededError, CHIMERA_REVIEW_PROMPT, CONTEXT_WINDOW_MODES, CORE_RECONSTRUCT_EVENTS, CheckpointManager, CloudSync, CollaborationBus, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SESSION_LOGGING_CONFIG, DEFAULT_SESSION_PRUNE_DAYS, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DEPENDENCY_FILE_PATTERNS, DefaultAttachmentStore, DefaultBrainArbiter, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMailbox, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultPromptStore, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, ENHANCER_SYSTEM_PROMPT, ERROR_CODES, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FORBIDDEN_PROTO_KEYS, FileMemoryBackend, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, FsError, GitignoreUpdater, GlobalMailbox, GraphMemoryBackend, HookRegistry, HookRunner, HumanEscalatingBrainArbiter, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MATRIX_PHASE_KEYS, MAX_JOURNAL_ENTRIES, MAX_PROGRESS_HISTORY, MEMORY_TYPE_LABELS, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, ObservableBrainArbiter, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, PhaseGraphBuilder, PhaseOrchestrator, PhaseStore, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReplayLogStore, ReplayProviderRunner, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, STANDARD_AUDIT_EVENTS, ScopedEventBus, SddError, SddParallelRun, SddTaskDecomposer, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SessionMemoryConsolidator, SessionRecovery, SessionRegistry, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, StreamHangError, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolAuditLog, ToolError, ToolExecutor, ToolRegistry, WorktreeManager, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, assertNever, assertSafePath, atomicWrite, attachAutoExtend, attachDepWatcherBridge, attachMailboxChecker, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, bootConfig, braveSearchServer, buildBtwBlock, buildChildEnv, buildGoalPreamble, buildLosslessDigest, buildMailboxBlock, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildQueuedMessagesBlock, buildRecoveryStrategies, buildSmartDigest, classifyFamily, clearPlan, collabInjectMiddleware, collabPauseMiddleware, color, compactLog, compileGlob, compileUserRegex, completePartialObject, composeDirectorPrompt, composeSubagentPrompt, computeMessageTokens, computeTaskItemProgress, computeTaskProgress, consumeBtwNotes, consumeQueuedMessagesUpdate, context7Server, contextManagerTool, createAutoExecutor, createAutoPhaseFromTaskGraph, createAutonomyBrain, createChimeraPlugin, createContextManagerTool, createDefaultPipelines, createDelegateTool, createGitPlugin, createMailboxChecker, createMcpControlTool, createMessage, createObservabilityPlugin, createPlanPlugin, createPromptsPlugin, createSecurityPlugin, createSecuritySlashCommand, createSessionEventBridge, createSkillsPlugin, createStrategyCompactor, createSyncPlugin, createTieredBrainArbiter, createToolOutputSerializer, decryptConfigSecrets, deepMerge, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, detectEcosystem as detectPackageEcosystem, dispatchAgent, downloadGitHubTarball, eliseOldToolResults, emptyGoal, emptyPlan, emptyTaskFile, encryptConfigSecrets, enhanceUserPrompt, ensureDir, estimateMessageTokens, estimateMessages, estimateRequestTokens, estimateRequestTokensCalibrated, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, expandGlob, expectDefined, extractRunEnv, extractText, filesystemServer, findCriticalPath, findPreserveStart, flagsToConfigPatch, formatContextWindowModeList, formatDecisionSummary, formatGoal, formatHumanPrompt, formatPlan, formatPlanTemplates, formatTaskList, formatTaskProgress, formatTodosList, getAgentDefinition, getCalibrationState, getContextWindowMode, getFileHistory, getFilesByAgent, getFullLog, getFullPackageLog, getLastAuthor, getManifestPackages, getPackageAuthor, getPackagesByAgent, getPlanTemplate, getSessionRegistry, getTemplate, getTermSize, githubServer, goalFilePath, googleMapsServer, hasSessionRegistry, hasTextContent, hashRequest, hookMatcherMatches, injectPendingMailboxMessages, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isInteractive, isPluginError, isPrimitiveArray, isSddError, isSecretField, isSessionError, isStdinTTY, isStdoutTTY, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isValidMatrixKey, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTasks, loadTodosCheckpoint, loadUserModes, mailboxSessionTag, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAutonomyPromptContributor, makeAwaitTasksTool, makeCollabDebugTool, makeContinueToNextIterationTool, makeDependencyWatcherConfig, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeMailInboxTool, makeMailSendTool, makeMailboxTool, makeRollUpTool, makeSpawnTool, makeTerminateTool, matchAny, matchGlob, matrixKeyKind, mergeCustomModelDefs, mergeModelsPayload, migratePlaintextSecrets, miniMaxVisionServer, mutatePlan, mutateTasks, noOpLogger, noOpVault, normalizeRecipient, normalizeToLf, normalizedEqual, onResize, parseContinueDirective, parseEntries, parseProgressFromText, parseSkillRef, peekQueuedMessages, pendingBtwCount, phaseForRole, projectHash, projectSlug, recentTextTurns, recordActualUsage, recordFileAction, recordPackageAction, recordProgress, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resetCalibration, resolveAuditLevel, resolveChimeraConfig, resolveContextWindowPolicy, resolveMailboxIdentity, resolveModelMatrix, resolveProjectDir, resolveSessionLoggingConfig, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, runProviderWithRetry, runShellHook, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTasks, saveTodosCheckpoint, scoreAgents, scoreMessage, securitySlashCommand, sentinelServer, setBtwNote, setOutputLineGuard, setPlanItemStatus, setProgress, setQueuedMessagesSnapshot, setRawMode, shouldEnhance, slackServer, sleep, stableStringify, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, startPackageOutdatedWatcher, startTechStackConsumer, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, truncate, unifiedDiff, unloadPlugins, updatePackageOutdatedStatus, validateAgainstSchema, wireMetricsToEvents, withFileLock, wrapAsState, writeErr, writeOut, wstackGlobalRoot, zaiVisionServer };
38248
+ export { ACP_AGENTS, AGENTS_BY_PHASE, AGENT_CATALOG, AISpecBuilder, ALL_AGENT_DEFINITIONS, ALL_FLEET_AGENTS, ALL_SYNC_CATEGORIES, AUDIT_LOG_AGENT, Agent, AgentError, AgentStatusTracker, AnnotationsStore, AutoApprovePermissionPolicy, AutoCompactionMiddleware, AutoExecutor, AutoPhasePlanner, AutoPhaseRunner, AutonomousRunner, BUG_HUNTER_AGENT, BrainDecisionQueue, BrainMonitor, BudgetExceededError, CHIMERA_REVIEW_PROMPT, CONTEXT_WINDOW_MODES, CORE_RECONSTRUCT_EVENTS, CheckpointManager, CloudSync, CollaborationBus, ConfigError, ConfigMigrationError, Container, Context, ConversationState, DEFAULT_AUTONOMY_CONFIG, DEFAULT_CONFIG_MIGRATIONS, DEFAULT_CONTEXT_CONFIG, DEFAULT_CONTEXT_WINDOW_MODE_ID, DEFAULT_DIRECTOR_PREAMBLE, DEFAULT_DISPATCH_ROLE, DEFAULT_MAX_ITERATIONS, DEFAULT_MODES, DEFAULT_RECOVERY_STRATEGIES, DEFAULT_SESSION_LOGGING_CONFIG, DEFAULT_SESSION_PRUNE_DAYS, DEFAULT_SPEC_TEMPLATE, DEFAULT_SUBAGENT_BASELINE, DEFAULT_TOOLS_CONFIG, DEPENDENCY_FILE_PATTERNS, DefaultAttachmentStore, DefaultBrainArbiter, DefaultConfigLoader, DefaultConfigStore, DefaultErrorHandler, DefaultHealthRegistry, DefaultLogger, DefaultMailbox, DefaultMemoryStore, DefaultModeStore, DefaultModelsRegistry, DefaultMultiAgentCoordinator, DefaultPathResolver, DefaultPermissionPolicy, DefaultPluginAPI, DefaultPromptStore, DefaultProviderRunner, DefaultRetryPolicy, DefaultSecretScrubber, DefaultSecretVault, DefaultSessionReader, DefaultSessionRewinder, DefaultSessionStore, DefaultSkillLoader, DefaultSystemPromptBuilder, DefaultTaskStore, DefaultTokenCounter, Director, DirectorStateCheckpoint, DoneConditionChecker, ENHANCER_SYSTEM_PROMPT, ERROR_CODES, EternalAutonomyEngine, EventBus, ExtensionRegistry, FLEET_ROSTER, FLEET_ROSTER_BUDGETS, FLEET_ROSTER_WITHACP, FORBIDDEN_PROTO_KEYS, FileMemoryBackend, FleetBus, FleetCostCapError, FleetManager, FleetSpawnBudgetError, FleetUsageAggregator, FsError, GitignoreUpdater, GlobalMailbox, GraphMemoryBackend, HookRegistry, HookRunner, HumanEscalatingBrainArbiter, HybridCompactor, InMemoryAgentBridge, InMemoryBridgeTransport, InMemoryMetricsSink, InputBuilder, IntelligentCompactor, KERNEL_API_VERSION, LAYER_1_IDENTITY, LLMSelector, MATRIX_PHASE_KEYS, MAX_JOURNAL_ENTRIES, MAX_PROGRESS_HISTORY, MEMORY_TYPE_LABELS, NULL_FLEET_BUS, NoopMetricsSink, NoopTracer, OTelTracer, ObservableBrainArbiter, PROMETHEUS_CONTENT_TYPE, ParallelEternalEngine, PhaseGraphBuilder, PhaseOrchestrator, PhaseStore, Pipeline, PluginError, ProviderError, ProviderRegistry, QueueStore, REFACTOR_PLANNER_AGENT, RecoveryLock, ReplayLogStore, ReplayProviderRunner, ReportGenerator, RunController, SECURITY_SCANNER_AGENT, SPEC_TEMPLATES, STANDARD_AUDIT_EVENTS, ScopedEventBus, SddError, SddParallelRun, SddTaskDecomposer, SecurityScanner, SecurityScannerOrchestrator, SelectiveCompactor, SessionAnalyzer, SessionError, SessionMemoryConsolidator, SessionRecovery, SessionRegistry, SkillGenerator, SkillInstaller, SkillManifestStore, SlashCommandRegistry, SpecDrivenDev, SpecParser, SpecStore, SpecVersioning, StreamHangError, SubagentBudget, TOKENS, TaskFlow, TaskGenerator, TaskGraphStore, TaskTracker, TechStackDetector, ToolAuditLog, ToolError, ToolExecutor, ToolRegistry, WorktreeManager, WrongStackError, addPlanItem, allServers, analyzeCriticalPath, appendJournal, applyRosterBudget, asBlocks, asText, assertNever, assertSafePath, atomicWrite, attachAutoExtend, attachDepWatcherBridge, attachMailboxChecker, attachPlanCheckpoint, attachTodosCheckpoint, awsServer, blockServer, bootConfig, braveSearchServer, buildBtwBlock, buildChildEnv, buildGoalPreamble, buildLosslessDigest, buildMailboxBlock, buildOtlpMetricsRequest, buildOtlpTracesRequest, buildQueuedMessagesBlock, buildRecoveryStrategies, buildSmartDigest, classifyFamily, clearPlan, collabInjectMiddleware, collabPauseMiddleware, color, compactLog, compileGlob, compileUserRegex, completePartialObject, composeDirectorPrompt, composeSubagentPrompt, computeMessageTokens, computeTaskItemProgress, computeTaskProgress, consumeBtwNotes, consumeQueuedMessagesUpdate, context7Server, contextManagerTool, createAutoExecutor, createAutoPhaseFromTaskGraph, createAutonomyBrain, createChimeraPlugin, createContextManagerTool, createDefaultPipelines, createDelegateTool, createGitPlugin, createMailboxChecker, createMcpControlTool, createMcpUseTool, createMessage, createObservabilityPlugin, createPlanPlugin, createPromptsPlugin, createSecurityPlugin, createSecuritySlashCommand, createSessionEventBridge, createSkillsPlugin, createStrategyCompactor, createSyncPlugin, createTieredBrainArbiter, createToolOutputSerializer, decryptConfigSecrets, deepMerge, defaultGitignoreUpdater, defaultOrchestrator, defaultReportGenerator, defaultSecurityScanner, defaultSkillGenerator, defaultTechStackDetector, deriveTodosFromPlanItem, detectNewlineStyle, detectEcosystem as detectPackageEcosystem, dispatchAgent, downloadGitHubTarball, eliseOldToolResults, emptyGoal, emptyPlan, emptyTaskFile, encryptConfigSecrets, enhanceUserPrompt, ensureDir, estimateMessageTokens, estimateMessages, estimateRequestTokens, estimateRequestTokensCalibrated, estimateTextTokens, estimateToolDefTokens, estimateToolInputTokens, estimateToolResultTokens, everArtServer, expandGlob, expectDefined, extractRunEnv, extractText, filesystemServer, findCriticalPath, findPreserveStart, flagsToConfigPatch, formatContextWindowModeList, formatDecisionSummary, formatGoal, formatHumanPrompt, formatPlan, formatPlanTemplates, formatTaskList, formatTaskProgress, formatTodosList, getAgentDefinition, getCalibrationState, getContextWindowMode, getFileHistory, getFilesByAgent, getFullLog, getFullPackageLog, getLastAuthor, getManifestPackages, getPackageAuthor, getPackagesByAgent, getPlanTemplate, getSessionRegistry, getTemplate, getTermSize, githubServer, goalFilePath, googleMapsServer, hasSessionRegistry, hasTextContent, hashRequest, hookMatcherMatches, injectPendingMailboxMessages, isAgentError, isConfigError, isContextWindowModeId, isFsError, isImageBlock, isInteractive, isPluginError, isPrimitiveArray, isSddError, isSecretField, isSessionError, isStdinTTY, isStdoutTTY, isTextBlock, isThinkingBlock, isToolError, isToolResultBlock, isToolUseBlock, isValidMatrixKey, isWrongStackError, listContextWindowModes, listPlanTemplates, listTemplates, loadDirectorState, loadGoal, loadPlan, loadPlugins, loadProjectModes, loadTasks, loadTodosCheckpoint, loadUserModes, mailboxSessionTag, makeAgentSubagentRunner, makeAskTool, makeAssignTool, makeAutonomyPromptContributor, makeAwaitTasksTool, makeCollabDebugTool, makeContinueToNextIterationTool, makeDependencyWatcherConfig, makeDirectorSessionFactory, makeFleetEmitTool, makeFleetHealthTool, makeFleetSessionTool, makeFleetStatusTool, makeFleetUsageTool, makeLLMClassifier, makeMailInboxTool, makeMailSendTool, makeMailboxTool, makeRollUpTool, makeSpawnTool, makeTerminateTool, matchAny, matchGlob, matrixKeyKind, mergeCustomModelDefs, mergeModelsPayload, migratePlaintextSecrets, miniMaxVisionServer, mutatePlan, mutateTasks, noOpLogger, noOpVault, normalizeRecipient, normalizeToLf, normalizedEqual, onResize, parseContinueDirective, parseEntries, parseProgressFromText, parseSkillRef, peekQueuedMessages, pendingBtwCount, phaseForRole, projectHash, projectSlug, recentTextTurns, recordActualUsage, recordFileAction, recordPackageAction, recordProgress, removePlanItem, renderProgress, renderPrometheus, renderSpecAnalysis, renderTaskGraph, renderTaskList, repairToolUseAdjacency, resetCalibration, resolveAuditLevel, resolveChimeraConfig, resolveContextWindowPolicy, resolveMailboxIdentity, resolveModelMatrix, resolveProjectDir, resolveSessionLoggingConfig, resolveWstackPaths, rewriteConfigEncrypted, rosterSummaryFromConfigs, runConfigMigrations, runProviderWithRetry, runShellHook, safeParse, safeStringify, sanitizeJsonString, saveGoal, savePlan, saveTasks, saveTodosCheckpoint, scoreAgents, scoreMessage, securitySlashCommand, sentinelServer, setBtwNote, setOutputLineGuard, setPlanItemStatus, setProgress, setQueuedMessagesSnapshot, setRawMode, shouldEnhance, slackServer, sleep, stableStringify, startMetricsServer, startOtlpMetricsExporter, startOtlpTraceExporter, startPackageOutdatedWatcher, startTechStackConsumer, stripAnsi, summarizeUsage, templateToMarkdown, toStyle, toWrongStackError, topologicalSort, truncate, unifiedDiff, unloadPlugins, updatePackageOutdatedStatus, validateAgainstSchema, wireMetricsToEvents, withFileLock, wrapAsState, writeErr, writeOut, wstackGlobalRoot, zaiVisionServer };
37751
38249
  //# sourceMappingURL=index.js.map
37752
38250
  //# sourceMappingURL=index.js.map