zidane 4.1.4 → 4.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +3 -3
  2. package/dist/{agent-BoV5Twdl.d.ts → agent-BAoqUvwA.d.ts} +27 -1
  3. package/dist/{agent-BoV5Twdl.d.ts.map → agent-BAoqUvwA.d.ts.map} +1 -1
  4. package/dist/{index-28otmfLX.d.ts → index-B8-yNSsk.d.ts} +2 -2
  5. package/dist/index-B8-yNSsk.d.ts.map +1 -0
  6. package/dist/{index-DPsd0qwm.d.ts → index-CqpNqjDy.d.ts} +2 -2
  7. package/dist/{index-DPsd0qwm.d.ts.map → index-CqpNqjDy.d.ts.map} +1 -1
  8. package/dist/index.d.ts +3 -3
  9. package/dist/index.js +4 -4
  10. package/dist/mcp.d.ts +1 -1
  11. package/dist/{presets-Cs7_CsMk.js → presets-BzkJDW1K.js} +3 -3
  12. package/dist/presets-BzkJDW1K.js.map +1 -0
  13. package/dist/presets.d.ts +1 -1
  14. package/dist/presets.js +1 -1
  15. package/dist/{providers-CX-R-Oy-.js → providers-CCDvIXGJ.js} +26 -5
  16. package/dist/providers-CCDvIXGJ.js.map +1 -0
  17. package/dist/providers.d.ts +1 -1
  18. package/dist/providers.js +1 -1
  19. package/dist/session/sqlite.d.ts +1 -1
  20. package/dist/session.d.ts +1 -1
  21. package/dist/skills.d.ts +2 -2
  22. package/dist/{stats-DoKUtF5T.js → stats-BT9l57RS.js} +34 -2
  23. package/dist/stats-BT9l57RS.js.map +1 -0
  24. package/dist/{tools-DpeWKzP1.js → tools-C8kDot0H.js} +73 -23
  25. package/dist/tools-C8kDot0H.js.map +1 -0
  26. package/dist/tools.d.ts +2 -2
  27. package/dist/tools.js +1 -1
  28. package/dist/tui.d.ts +423 -80
  29. package/dist/tui.d.ts.map +1 -1
  30. package/dist/tui.js +1604 -250
  31. package/dist/tui.js.map +1 -1
  32. package/dist/types.d.ts +2 -2
  33. package/dist/types.js +1 -1
  34. package/package.json +1 -1
  35. package/dist/index-28otmfLX.d.ts.map +0 -1
  36. package/dist/presets-Cs7_CsMk.js.map +0 -1
  37. package/dist/providers-CX-R-Oy-.js.map +0 -1
  38. package/dist/stats-DoKUtF5T.js.map +0 -1
  39. package/dist/tools-DpeWKzP1.js.map +0 -1
package/dist/skills.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { C as SkillsConfig, S as SkillSource, a as ActivationVia, b as SkillDiagnostic, c as SkillActivationState, l as SkillActivationStateOptions, o as ActiveSkill, s as DeactivationReason, u as createSkillActivationState, x as SkillResource, y as SkillConfig } from "./agent-BoV5Twdl.js";
2
- import { S as installAllowedToolsGate, _ as inferSource, a as SkillValidationResult, b as buildCatalog, c as parseAllowedToolPattern, d as validateSkillName, f as resolveSkills, g as getDefaultScanPaths, h as discoverSkills, i as SkillValidationIssue, l as validateResourcePath, m as SourcedScanPath, n as writeSkillToDisk, o as isToolAllowedByUnion, p as interpolateShellCommands, r as writeSkillsToDisk, s as matchesAllowedTool, t as defineSkill, u as validateSkillForWrite, v as parseFrontmatter, x as IMPLICITLY_ALLOWED_SKILL_TOOLS, y as parseSkillFile } from "./index-DPsd0qwm.js";
1
+ import { C as SkillsConfig, S as SkillSource, a as ActivationVia, b as SkillDiagnostic, c as SkillActivationState, l as SkillActivationStateOptions, o as ActiveSkill, s as DeactivationReason, u as createSkillActivationState, x as SkillResource, y as SkillConfig } from "./agent-BAoqUvwA.js";
2
+ import { S as installAllowedToolsGate, _ as inferSource, a as SkillValidationResult, b as buildCatalog, c as parseAllowedToolPattern, d as validateSkillName, f as resolveSkills, g as getDefaultScanPaths, h as discoverSkills, i as SkillValidationIssue, l as validateResourcePath, m as SourcedScanPath, n as writeSkillToDisk, o as isToolAllowedByUnion, p as interpolateShellCommands, r as writeSkillsToDisk, s as matchesAllowedTool, t as defineSkill, u as validateSkillForWrite, v as parseFrontmatter, x as IMPLICITLY_ALLOWED_SKILL_TOOLS, y as parseSkillFile } from "./index-CqpNqjDy.js";
3
3
  export { ActivationVia, ActiveSkill, DeactivationReason, IMPLICITLY_ALLOWED_SKILL_TOOLS, SkillActivationState, SkillActivationStateOptions, SkillConfig, SkillDiagnostic, SkillResource, SkillSource, SkillValidationIssue, SkillValidationResult, SkillsConfig, SourcedScanPath, buildCatalog, createSkillActivationState, defineSkill, discoverSkills, getDefaultScanPaths, inferSource, installAllowedToolsGate, interpolateShellCommands, isToolAllowedByUnion, matchesAllowedTool, parseAllowedToolPattern, parseFrontmatter, parseSkillFile, resolveSkills, validateResourcePath, validateSkillForWrite, validateSkillName, writeSkillToDisk, writeSkillsToDisk };
@@ -1,4 +1,36 @@
1
1
  //#region src/stats.ts
2
+ function normalize(stats) {
3
+ return {
4
+ input: stats.totalIn ?? 0,
5
+ output: stats.totalOut ?? 0,
6
+ cacheRead: stats.totalCacheRead ?? 0,
7
+ cacheCreation: stats.totalCacheCreation ?? 0
8
+ };
9
+ }
10
+ /**
11
+ * Render a one-line token summary suitable for spawn-end markers, child
12
+ * tool-result text, and any other per-run "what did this cost?" surface.
13
+ *
14
+ * `in 52413 (cache 50000) / 4075 out`
15
+ *
16
+ * The `in` total includes cached reads and cache-creation tokens (see
17
+ * {@link effectiveInputTokens}); the `(cache N)` parenthetical breaks out
18
+ * the cached portion so the user can tell at a glance how much was reused
19
+ * vs new. The parenthetical is omitted when its value is zero, so
20
+ * non-caching providers and brand-new runs read simply as `in N / M out`.
21
+ *
22
+ * Output-side caching is not a concept any current provider exposes —
23
+ * Anthropic's `cacheRead` / `cacheCreation` are both input-billed. If a
24
+ * future provider ships an output cache, extend `TokenUsageLike` with
25
+ * output-cache fields and add a parallel `(cache N)` slot on the `out`
26
+ * side here; today the right side is always plain `${N} out`.
27
+ */
28
+ function formatTokenUsage(stats) {
29
+ const { input, output, cacheRead, cacheCreation } = normalize(stats);
30
+ const inputTotal = input + cacheRead + cacheCreation;
31
+ const inputCache = cacheRead + cacheCreation;
32
+ return `${inputCache > 0 ? `in ${inputTotal} (cache ${inputCache})` : `in ${inputTotal}`} / ${output} out`;
33
+ }
2
34
  /**
3
35
  * Depth-first walk over the stats tree, returning every `TurnUsage` entry
4
36
  * — parent loop first, then each child subtree in completion order.
@@ -53,6 +85,6 @@ function statsByModel(stats) {
53
85
  return out;
54
86
  }
55
87
  //#endregion
56
- export { statsByModel as n, flattenTurns as t };
88
+ export { formatTokenUsage as n, statsByModel as r, flattenTurns as t };
57
89
 
58
- //# sourceMappingURL=stats-DoKUtF5T.js.map
90
+ //# sourceMappingURL=stats-BT9l57RS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-BT9l57RS.js","names":[],"sources":["../src/stats.ts"],"sourcesContent":["/**\n * Pure derivations over `AgentStats`.\n *\n * Both helpers are tree-shakeable — import only what you need. They never\n * touch agent state, never do I/O, and always operate on the recursive\n * `AgentStats` tree returned by `agent.run()`.\n */\n\nimport type { AgentStats, TurnUsage } from './types'\n\n/**\n * Per-model usage rollup produced by {@link statsByModel}.\n *\n * `turns` counts the number of `TurnUsage` entries attributed to the model\n * across the whole tree (parent loop + every recursively-spawned child).\n * Cache and cost numbers are summed from the same set of turns.\n */\nexport interface ModelUsage {\n input: number\n output: number\n cost: number\n cacheRead: number\n cacheCreation: number\n turns: number\n}\n\n/**\n * Common shape for token-usage helpers. Mirrors `AgentStats`'s cumulative\n * fields. Callers working with `TurnUsage` / `SessionRun.totalUsage`\n * (`input` / `output` / `cacheRead` / `cacheCreation`) map their fields in\n * at the call site — we don't accept both shapes here because\n * `AgentStats.output` is a structured-output payload (`Record<string,\n * unknown>`), not a token count, so the field name `output` is ambiguous.\n */\nexport interface TokenUsageLike {\n totalIn?: number\n totalOut?: number\n totalCacheRead?: number\n totalCacheCreation?: number\n}\n\nfunction normalize(stats: TokenUsageLike): {\n input: number\n output: number\n cacheRead: number\n cacheCreation: number\n} {\n return {\n input: stats.totalIn ?? 0,\n output: stats.totalOut ?? 0,\n cacheRead: stats.totalCacheRead ?? 0,\n cacheCreation: stats.totalCacheCreation ?? 0,\n }\n}\n\n/**\n * Sum of `input + cacheRead + cacheCreation` — i.e. the number of tokens the\n * model actually saw, regardless of how they were billed.\n *\n * With provider prompt caching (Anthropic, OpenRouter→Anthropic, Gemini),\n * `AgentStats.totalIn` only counts **new uncached** tokens per turn; the\n * bulk of an N-turn run's context lives in `totalCacheRead`, plus a smaller\n * `totalCacheCreation` chunk for whichever turns added new breakpoints.\n * Showing only `totalIn` in a per-run summary makes long subagent runs look\n * suspiciously cheap (e.g. \"13 in\" for 8 turns over a large repo).\n *\n * `TurnUsage` / `SessionRun.totalUsage` callers map their fields to the\n * `total*` names at the call site (see {@link TokenUsageLike}).\n */\nexport function effectiveInputTokens(stats: TokenUsageLike): number {\n const { input, cacheRead, cacheCreation } = normalize(stats)\n return input + cacheRead + cacheCreation\n}\n\n/**\n * Render a one-line token summary suitable for spawn-end markers, child\n * tool-result text, and any other per-run \"what did this cost?\" surface.\n *\n * `in 52413 (cache 50000) / 4075 out`\n *\n * The `in` total includes cached reads and cache-creation tokens (see\n * {@link effectiveInputTokens}); the `(cache N)` parenthetical breaks out\n * the cached portion so the user can tell at a glance how much was reused\n * vs new. The parenthetical is omitted when its value is zero, so\n * non-caching providers and brand-new runs read simply as `in N / M out`.\n *\n * Output-side caching is not a concept any current provider exposes —\n * Anthropic's `cacheRead` / `cacheCreation` are both input-billed. If a\n * future provider ships an output cache, extend `TokenUsageLike` with\n * output-cache fields and add a parallel `(cache N)` slot on the `out`\n * side here; today the right side is always plain `${N} out`.\n */\nexport function formatTokenUsage(stats: TokenUsageLike): string {\n const { input, output, cacheRead, cacheCreation } = normalize(stats)\n const inputTotal = input + cacheRead + cacheCreation\n const inputCache = cacheRead + cacheCreation\n const inPart = inputCache > 0\n ? `in ${inputTotal} (cache ${inputCache})`\n : `in ${inputTotal}`\n return `${inPart} / ${output} out`\n}\n\n/**\n * Depth-first walk over the stats tree, returning every `TurnUsage` entry\n * — parent loop first, then each child subtree in completion order.\n *\n * Closes the cache-token aggregation gap: `TurnUsage.cacheRead` /\n * `cacheCreation` live only on per-turn entries, and the top-level\n * `AgentStats` deliberately doesn't carry cumulative forms (one source of\n * truth, no risk of drift). Anything that needs a tree-wide sum walks\n * through this.\n */\nexport function flattenTurns(stats: AgentStats): TurnUsage[] {\n const out: TurnUsage[] = []\n collectTurns(stats, out)\n return out\n}\n\nfunction collectTurns(stats: AgentStats, out: TurnUsage[]): void {\n if (stats.turnUsage)\n out.push(...stats.turnUsage)\n if (stats.children) {\n for (const child of stats.children)\n collectTurns(child.stats, out)\n }\n}\n\n/**\n * Group cumulative usage by `TurnUsage.modelId`. Each entry sums the input,\n * output, cache, cost, and turn-count across every turn the tree attributed\n * to that model — naturally handling cross-model runs (vision-fallback,\n * model-shifted subagents, mixed-provider workflows).\n *\n * Turns missing `modelId` (mock providers, providers that don't echo a model\n * id) are bucketed under the literal string `'(unknown)'`.\n */\nexport function statsByModel(stats: AgentStats): Map<string, ModelUsage> {\n const out = new Map<string, ModelUsage>()\n for (const turn of flattenTurns(stats)) {\n const key = turn.modelId ?? '(unknown)'\n let entry = out.get(key)\n if (!entry) {\n entry = { input: 0, output: 0, cost: 0, cacheRead: 0, cacheCreation: 0, turns: 0 }\n out.set(key, entry)\n }\n entry.input += turn.input\n entry.output += turn.output\n entry.cost += turn.cost ?? 0\n entry.cacheRead += turn.cacheRead ?? 0\n entry.cacheCreation += turn.cacheCreation ?? 0\n entry.turns += 1\n }\n return out\n}\n"],"mappings":";AAyCA,SAAS,UAAU,OAKjB;CACA,OAAO;EACL,OAAO,MAAM,WAAW;EACxB,QAAQ,MAAM,YAAY;EAC1B,WAAW,MAAM,kBAAkB;EACnC,eAAe,MAAM,sBAAsB;EAC5C;;;;;;;;;;;;;;;;;;;;AAwCH,SAAgB,iBAAiB,OAA+B;CAC9D,MAAM,EAAE,OAAO,QAAQ,WAAW,kBAAkB,UAAU,MAAM;CACpE,MAAM,aAAa,QAAQ,YAAY;CACvC,MAAM,aAAa,YAAY;CAI/B,OAAO,GAHQ,aAAa,IACxB,MAAM,WAAW,UAAU,WAAW,KACtC,MAAM,aACO,KAAK,OAAO;;;;;;;;;;;;AAa/B,SAAgB,aAAa,OAAgC;CAC3D,MAAM,MAAmB,EAAE;CAC3B,aAAa,OAAO,IAAI;CACxB,OAAO;;AAGT,SAAS,aAAa,OAAmB,KAAwB;CAC/D,IAAI,MAAM,WACR,IAAI,KAAK,GAAG,MAAM,UAAU;CAC9B,IAAI,MAAM,UACR,KAAK,MAAM,SAAS,MAAM,UACxB,aAAa,MAAM,OAAO,IAAI;;;;;;;;;;;AAapC,SAAgB,aAAa,OAA4C;CACvE,MAAM,sBAAM,IAAI,KAAyB;CACzC,KAAK,MAAM,QAAQ,aAAa,MAAM,EAAE;EACtC,MAAM,MAAM,KAAK,WAAW;EAC5B,IAAI,QAAQ,IAAI,IAAI,IAAI;EACxB,IAAI,CAAC,OAAO;GACV,QAAQ;IAAE,OAAO;IAAG,QAAQ;IAAG,MAAM;IAAG,WAAW;IAAG,eAAe;IAAG,OAAO;IAAG;GAClF,IAAI,IAAI,KAAK,MAAM;;EAErB,MAAM,SAAS,KAAK;EACpB,MAAM,UAAU,KAAK;EACrB,MAAM,QAAQ,KAAK,QAAQ;EAC3B,MAAM,aAAa,KAAK,aAAa;EACrC,MAAM,iBAAiB,KAAK,iBAAiB;EAC7C,MAAM,SAAS;;CAEjB,OAAO"}
@@ -3,7 +3,7 @@ import { r as AgentProviderError, s as toTypedError, t as AgentAbortedError } fr
3
3
  import { t as toolOutputByteLength } from "./types-Bx_F8jet.js";
4
4
  import { t as connectMcpServers } from "./mcp-8wClKY-3.js";
5
5
  import { _ as validateResourcePath, b as createSkillActivationState, d as escapeXml, n as resolveSkills, p as installAllowedToolsGate, t as interpolateShellCommands, u as buildCatalog } from "./interpolate-CukJwP2G.js";
6
- import { t as flattenTurns } from "./stats-DoKUtF5T.js";
6
+ import { n as formatTokenUsage, t as flattenTurns } from "./stats-BT9l57RS.js";
7
7
  import { createHooks } from "hookable";
8
8
  import { stat } from "node:fs/promises";
9
9
  import { resolve } from "node:path";
@@ -1135,12 +1135,18 @@ async function emitToolResult(ctx, params) {
1135
1135
  }
1136
1136
  async function executeToolsSequential(ctx, toolCalls, turnId) {
1137
1137
  const results = [];
1138
- for (const call of toolCalls) {
1139
- if (ctx.signal.aborted) break;
1138
+ for (let i = 0; i < toolCalls.length; i++) {
1139
+ const call = toolCalls[i];
1140
+ if (ctx.signal.aborted) {
1141
+ for (let j = i; j < toolCalls.length; j++) results.push({
1142
+ id: toolCalls[j].id,
1143
+ content: "Aborted: run was cancelled"
1144
+ });
1145
+ return results;
1146
+ }
1140
1147
  if (ctx.steeringQueue.length > 0) {
1141
- const fromIdx = toolCalls.indexOf(call);
1142
- for (let i = fromIdx; i < toolCalls.length; i++) results.push({
1143
- id: toolCalls[i].id,
1148
+ for (let j = i; j < toolCalls.length; j++) results.push({
1149
+ id: toolCalls[j].id,
1144
1150
  content: "Skipped: steering message received"
1145
1151
  });
1146
1152
  return results;
@@ -1752,6 +1758,8 @@ const HOOK_EVENT_SET = new Set([
1752
1758
  "child:stream:text",
1753
1759
  "child:stream:thinking",
1754
1760
  "child:stream:end",
1761
+ "child:tool:gate",
1762
+ "child:mcp:tool:gate",
1755
1763
  "child:tool:before",
1756
1764
  "child:tool:after",
1757
1765
  "child:tool:error",
@@ -2093,8 +2101,12 @@ function createAgent({ provider, name: agentName, system: agentSystem, tools: ag
2093
2101
  }
2094
2102
  const formattedTools = buildFormattedTools();
2095
2103
  const turns = [];
2096
- const isResume = session && session.turns.length > 0 && (session.runs.length > 0 || !options.prompt);
2097
- if (isResume) turns.push(...session.turns);
2104
+ const isResume = session && session.turns.length > 0 && (session.runs.length > 0 || !options.prompt) && !options.parentRunId;
2105
+ if (isResume) {
2106
+ const childRunIds = new Set(session.runs.filter((r) => (r.depth ?? 0) > 0).map((r) => r.id));
2107
+ const resumed = childRunIds.size === 0 ? session.turns : session.turns.filter((t) => !t.runId || !childRunIds.has(t.runId));
2108
+ turns.push(...resumed);
2109
+ }
2098
2110
  const runTurnStart = turns.length;
2099
2111
  if (options.system) await hooks.callHook("system:before", { system: options.system });
2100
2112
  const promptParts = canonicalizePrompt(options.prompt);
@@ -3605,6 +3617,7 @@ const BUBBLED_EVENTS = [
3605
3617
  "tool:error",
3606
3618
  "turn:after"
3607
3619
  ];
3620
+ const BUBBLED_GATE_EVENTS = ["tool:gate", "mcp:tool:gate"];
3608
3621
  const CHILD_EVENT_NAME = {
3609
3622
  "stream:text": "child:stream:text",
3610
3623
  "stream:thinking": "child:stream:thinking",
@@ -3614,6 +3627,18 @@ const CHILD_EVENT_NAME = {
3614
3627
  "tool:error": "child:tool:error",
3615
3628
  "turn:after": "child:turn:after"
3616
3629
  };
3630
+ const CHILD_GATE_EVENT_NAME = {
3631
+ "tool:gate": "child:tool:gate",
3632
+ "mcp:tool:gate": "child:mcp:tool:gate"
3633
+ };
3634
+ const sessionChildCounters = /* @__PURE__ */ new WeakMap();
3635
+ function reserveChildLabel(session) {
3636
+ let counter = sessionChildCounters.get(session);
3637
+ if (counter === void 0) counter = session.runs.filter((r) => (r.depth ?? 0) > 0).length;
3638
+ counter += 1;
3639
+ sessionChildCounters.set(session, counter);
3640
+ return `child-${counter}`;
3641
+ }
3617
3642
  function extractText(message) {
3618
3643
  if (!message || typeof message !== "object") return "";
3619
3644
  const msg = message;
@@ -3656,15 +3681,21 @@ var SpawnTimeoutError = class extends Error {
3656
3681
  /**
3657
3682
  * Wire child's hooks to bubble into `parentHooks` as `child:*` events.
3658
3683
  *
3659
- * Two kinds of forwarding:
3684
+ * Three kinds of forwarding:
3660
3685
  *
3661
- * 1. **Originating events** (`stream:text`, `tool:before`, …) → rewrite to
3662
- * the matching `child:*` event, inject `{ childId, depth }` from this
3663
- * spawn, then fire on the parent's hook bus.
3664
- * 2. **Re-bubbled events** (`child:stream:text`, `child:tool:before`, …)
3665
- * from a grandchild already carry `childId` + `depth` pointing at the
3666
- * originating subagent. Forward them verbatim so the top-level listener
3667
- * sees the correct ancestry, not the immediate parent's.
3686
+ * 1. **Originating observational events** (`stream:text`, `tool:before`, …)
3687
+ * → rewrite to the matching `child:*` event, inject `{ childId, depth }`,
3688
+ * fire on the parent's hook bus as a **spread copy** (so parent listeners
3689
+ * can't accidentally mutate the child's ctx).
3690
+ * 2. **Originating gate events** (`tool:gate`, `mcp:tool:gate`) forward
3691
+ * the **same ctx reference**, augmented with `childId` / `depth`, so a
3692
+ * parent listener writing `ctx.block = true` lands on the gate the
3693
+ * child's loop is awaiting on. The bubble itself `await`s the parent's
3694
+ * callHook so any async approval (e.g. a TUI picker) completes before
3695
+ * the child's loop sees the decision.
3696
+ * 3. **Re-bubbled `child:*` events** from a grandchild already carry the
3697
+ * originating `childId` + `depth`. Forward verbatim so a top-level
3698
+ * listener sees true ancestry, not the immediate parent's.
3668
3699
  *
3669
3700
  * Returns a function that unregisters every listener registered here.
3670
3701
  * Called before `agent.run()` starts, torn down in a finally block — so
@@ -3684,12 +3715,30 @@ function bubbleHooks(childHooks, parentHooks, childId, depth) {
3684
3715
  });
3685
3716
  unregisters.push(unregister);
3686
3717
  }
3718
+ const tagOnCtx = (ctx) => {
3719
+ ctx.childId = childId;
3720
+ ctx.depth = depth;
3721
+ };
3722
+ for (const evt of BUBBLED_GATE_EVENTS) {
3723
+ const parentEvt = CHILD_GATE_EVENT_NAME[evt];
3724
+ const unregister = childHooks.hook(evt, async (ctx) => {
3725
+ tagOnCtx(ctx);
3726
+ await fire(parentEvt, ctx);
3727
+ });
3728
+ unregisters.push(unregister);
3729
+ }
3730
+ const chainHook = childHooks.hook;
3687
3731
  for (const evt of BUBBLED_EVENTS) {
3688
3732
  const parentEvt = CHILD_EVENT_NAME[evt];
3689
- const unregister = childHooks.hook(parentEvt, (ctx) => {
3733
+ unregisters.push(chainHook(parentEvt, (ctx) => {
3690
3734
  fire(parentEvt, ctx);
3691
- });
3692
- unregisters.push(unregister);
3735
+ }));
3736
+ }
3737
+ for (const evt of BUBBLED_GATE_EVENTS) {
3738
+ const parentEvt = CHILD_GATE_EVENT_NAME[evt];
3739
+ unregisters.push(chainHook(parentEvt, async (ctx) => {
3740
+ await fire(parentEvt, ctx);
3741
+ }));
3693
3742
  }
3694
3743
  return () => {
3695
3744
  for (const u of unregisters) u();
@@ -3751,7 +3800,7 @@ function createSpawnTool(options = {}) {
3751
3800
  if (childDepth > maxDepth) return `Cannot spawn: maxDepth=${maxDepth} reached (parent depth=${parentDepth}). Deepen the cap with createSpawnTool({ maxDepth }).`;
3752
3801
  if (localActiveCount >= maxConcurrent) return `Cannot spawn: ${localActiveCount}/${maxConcurrent} sub-agents already running. Wait for one to complete.`;
3753
3802
  if (ctx.signal.aborted) return `[sub-agent pre-aborted] Parent signal was already aborted — skipped "${task.slice(0, 80)}"`;
3754
- const id = `child-${++localCounter}`;
3803
+ const id = ctx.session ? reserveChildLabel(ctx.session) : `child-${++localCounter}`;
3755
3804
  localActiveCount++;
3756
3805
  const child = {
3757
3806
  id,
@@ -3798,14 +3847,15 @@ function createSpawnTool(options = {}) {
3798
3847
  try {
3799
3848
  finalStats = await raceWithTimeout(runPromise, options.timeoutMs);
3800
3849
  const treeTurns = flattenTurns(finalStats).length;
3850
+ const usage = formatTokenUsage(finalStats);
3801
3851
  if (ctx.signal.aborted) {
3802
3852
  childRunStatus = "aborted";
3803
- result = [`[sub-agent ${id}] Aborted after ${treeTurns} turns (${finalStats.elapsed}ms)`, `Tokens: ${finalStats.totalIn} in / ${finalStats.totalOut} out`].join("\n");
3853
+ result = [`[sub-agent ${id}] Aborted after ${treeTurns} turns (${finalStats.elapsed}ms)`, `Tokens: ${usage}`].join("\n");
3804
3854
  } else {
3805
3855
  const response = extractText(agent.turns.at(-1));
3806
3856
  result = [
3807
3857
  `[sub-agent ${id}] Completed in ${treeTurns} turns (${finalStats.elapsed}ms)`,
3808
- `Tokens: ${finalStats.totalIn} in / ${finalStats.totalOut} out`,
3858
+ `Tokens: ${usage}`,
3809
3859
  "",
3810
3860
  response || "(no text response)"
3811
3861
  ].join("\n");
@@ -3938,4 +3988,4 @@ const writeFile$1 = {
3938
3988
  //#endregion
3939
3989
  export { multiEdit as a, grep as c, createAgent as d, createToolSearchTool as f, validateToolArgs as g, createSkillsReadTool as h, readFile$1 as i, glob as l, createSkillsRunScriptTool as m, createSpawnTool as n, listFiles as o, createSkillsUseTool as p, shell as r, createInteractionTool as s, writeFile$1 as t, edit as u };
3940
3990
 
3941
- //# sourceMappingURL=tools-DpeWKzP1.js.map
3991
+ //# sourceMappingURL=tools-C8kDot0H.js.map