zidane 6.2.10 → 6.2.12

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 (77) hide show
  1. package/dist/{acp-DuEMbOoQ.js → acp-C-auiVTk.js} +2 -2
  2. package/dist/{acp-DuEMbOoQ.js.map → acp-C-auiVTk.js.map} +1 -1
  3. package/dist/acp-cli.js +4 -4
  4. package/dist/acp.d.ts +1 -1
  5. package/dist/acp.js +1 -1
  6. package/dist/{agent-6iGNP46b.js → agent-DhfdXgL2.js} +81 -1
  7. package/dist/{agent-6iGNP46b.js.map → agent-DhfdXgL2.js.map} +1 -1
  8. package/dist/agent.d.ts +1 -1
  9. package/dist/agent.js +1 -1
  10. package/dist/{anthropic-BD-lwEKp.js → anthropic-uXfsormU.js} +87 -2
  11. package/dist/anthropic-uXfsormU.js.map +1 -0
  12. package/dist/{auth-BH6G59RL.js → auth-TZg3MVi2.js} +2 -2
  13. package/dist/{auth-BH6G59RL.js.map → auth-TZg3MVi2.js.map} +1 -1
  14. package/dist/chat/pure.d.ts +3 -3
  15. package/dist/chat.d.ts +43 -4
  16. package/dist/chat.d.ts.map +1 -1
  17. package/dist/chat.js +3 -3
  18. package/dist/contexts/daytona.d.ts +1 -1
  19. package/dist/contexts/e2b.d.ts +1 -1
  20. package/dist/eval.d.ts +1 -1
  21. package/dist/extensions.d.ts +1 -1
  22. package/dist/extensions.js +1 -1
  23. package/dist/headless.d.ts +1 -1
  24. package/dist/headless.js +1 -1
  25. package/dist/{index-BFNt9GAs.d.ts → index-l0wehkWU.d.ts} +44 -6
  26. package/dist/index-l0wehkWU.d.ts.map +1 -0
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.js +4 -4
  29. package/dist/{login-B5nMPF8w.js → login-Clf-R27F.js} +2 -2
  30. package/dist/{login-B5nMPF8w.js.map → login-Clf-R27F.js.map} +1 -1
  31. package/dist/mcp.d.ts +1 -1
  32. package/dist/output/stream-json.d.ts +1 -1
  33. package/dist/output/terminal.d.ts +1 -1
  34. package/dist/presets.d.ts +1 -1
  35. package/dist/presets.js +1 -1
  36. package/dist/providers/anthropic.d.ts +1 -1
  37. package/dist/providers/anthropic.js +1 -1
  38. package/dist/providers/arcee.d.ts +1 -1
  39. package/dist/providers/baseten.d.ts +1 -1
  40. package/dist/providers/cerebras.d.ts +1 -1
  41. package/dist/providers/local.d.ts +1 -1
  42. package/dist/providers/openai-compat.d.ts +1 -1
  43. package/dist/providers/openai.d.ts +1 -1
  44. package/dist/providers/openrouter.d.ts +1 -1
  45. package/dist/providers/xai.d.ts +1 -1
  46. package/dist/providers.d.ts +2 -2
  47. package/dist/providers.js +1 -1
  48. package/dist/restate.d.ts +1 -1
  49. package/dist/session/sqlite.d.ts +1 -1
  50. package/dist/session.d.ts +1 -1
  51. package/dist/{skills-CDpejYOf.js → skills-DKWqoaYH.js} +4 -3
  52. package/dist/skills-DKWqoaYH.js.map +1 -0
  53. package/dist/skills.d.ts +1 -1
  54. package/dist/skills.js +1 -1
  55. package/dist/{tool-formatters-B_zQsYfa.d.ts → tool-formatters-BSwVkSX2.d.ts} +2 -2
  56. package/dist/{tool-formatters-B_zQsYfa.d.ts.map → tool-formatters-BSwVkSX2.d.ts.map} +1 -1
  57. package/dist/tools/fetch-url.d.ts +1 -1
  58. package/dist/tools/web-search.d.ts +1 -1
  59. package/dist/tools.d.ts +1 -1
  60. package/dist/tools.js +1 -1
  61. package/dist/{transcript-anchors-BUigMBQt.js → transcript-anchors-BzcuKnq8.js} +108 -37
  62. package/dist/transcript-anchors-BzcuKnq8.js.map +1 -0
  63. package/dist/{transcript-anchors-C1Zqb8uS.d.ts → transcript-anchors-DKjXpQ0h.d.ts} +3 -42
  64. package/dist/transcript-anchors-DKjXpQ0h.d.ts.map +1 -0
  65. package/dist/tui.d.ts +3 -3
  66. package/dist/tui.d.ts.map +1 -1
  67. package/dist/tui.js +199 -150
  68. package/dist/tui.js.map +1 -1
  69. package/dist/{turn-operations-DVA52KMG.d.ts → turn-operations-CjkgQKmR.d.ts} +3 -3
  70. package/dist/{turn-operations-DVA52KMG.d.ts.map → turn-operations-CjkgQKmR.d.ts.map} +1 -1
  71. package/dist/types.d.ts +1 -1
  72. package/package.json +1 -1
  73. package/dist/anthropic-BD-lwEKp.js.map +0 -1
  74. package/dist/index-BFNt9GAs.d.ts.map +0 -1
  75. package/dist/skills-CDpejYOf.js.map +0 -1
  76. package/dist/transcript-anchors-BUigMBQt.js.map +0 -1
  77. package/dist/transcript-anchors-C1Zqb8uS.d.ts.map +0 -1
package/dist/tui.js CHANGED
@@ -1,5 +1,5 @@
1
- import { $ as useMcpAuthDispatch, $n as buildBuildSystem, $t as providerKeySetChanged, A as runOAuthLogin, B as refreshMcpToolsCatalog, Ct as SETTINGS_CATEGORIES, D as formatPathForCwd, Dt as SettingsProvider, En as accentColor, Et as SETTINGS_TOGGLES, F as mcpsDiscoveryPaths, Gt as ConfigProvider, H as subscribeMcpToolsCache, Hn as useActiveTodos, Ht as DiscoveryProvider, J as parentServerName, Jt as resolveStoragePaths, K as buildVisibleMcpRows, Kt as useConfig, M as buildMcpServers, Mn as TODO_STATUS_GLYPHS, Mt as resolveChipColor, Nt as resolveTheme, O as fetchOAuthRedirect, Ot as clampFps, P as discoverProjectMcps, Q as McpAuthProvider, Qt as filterChainFallbacks, R as loadMcpToolsCache, St as DEFAULT_SETTINGS, T as suggestSafelistEntries, Tt as SETTINGS_INPUTS, Ut as useDiscovery, Vt as createDiscoverySlot, W as useMcpToolToggleMap, Wt as useDiscoveryOptional, Xt as chainPositionOf, Y as createFileMcpCredentialStore, Yt as buildRunModel, Zt as chainsEqual, _ as useSafeModeQueue, _n as chatAutoCompactBehavior, _t as truncateTrailing, a as useSurfaces, ar as compactSummaryEvent, at as PRESENT_PLAN_TOOL, b as getSafelist, br as updateToolEventOutcomes, bt as listProjectFiles, c as useStreamBuffer, cn as useUpdateCheck, cr as eventsFromTurns, d as discoverProjectSkills, dr as loadState, en as restoreChainFallbacks, er as buildPlanSystem, et as useMcpAuthState, fr as marginTopFor, ft as useInteractionsActions, g as useSafeModeActions, gr as sumRunCosts, gt as hintsLength, h as SafeModeProvider, hr as stripSpawnTokensLine, ht as clipHintsToWidth, i as useSelectStyle, in as tryOpenBrowser, it as InteractionsProvider, j as supportsOAuth, k as oauthUsesManualCodePaste, kt as useSettings, l as buildSkillsConfig, lr as lastContextSizeFromTurns, lt as makeRequestInteraction, m as writeSessionExport, mr as serverToolResultSummary, mt as EMPTY_HINTS, n as ThemeProvider, nn as toggleChainEntry, nr as chatReferenceTokensForPrompt, on as bootTick, ot as buildResumedToolResultsTurn, pt as useInteractionsQueue, q as indexOfServerRow, qt as resolveConfig, r as useColors, rn as useCompletion, rr as createChatTurnsReadTool, rt as ASK_USER_TOOL, s as useTheme, sn as buildUpdateHint, sr as deriveSessionTitle, st as createInteractionTools, t as computeTurnAnchors, tr as envSection, tt as getMcpAuthStatus, u as defaultSkillScanPaths, ur as listSessionMeta, ut as pendingInteractionsFromTurns, vn as discoverAgentsMd, vr as toolCallPreview, vt as buildHints, wt as SETTINGS_CHOICES, x as isOnSafelist, xr as usageByModel, xt as useEnabledToggleSet, y as addToSafelist, yr as toolResultText, z as mcpToolsCachePath } from "./transcript-anchors-BUigMBQt.js";
2
- import { $ as composeExtensionPreset, B as ExtensionInstallError, Bt as ensureKeybindingsFile, Et as createModelSearchTool, H as installExtensionFromSpec, Ht as groupBindings, J as createExtensionHud, K as removeInstalledExtension, P as summaryToTurn, St as tailTruncate, Ut as keybindingsPath, Vt as formatBindingForDisplay, Wt as matchesBinding, X as discoverAndBuildExtensionRegistry, Y as registerExtensionHostModules, Yt as resolveExtensionKeybindings, _ as buildPostCompactAttachments, c as applyCompactSummaryCutoff, dn as sanitizeExtensionConfigActionPatch, en as inlineLoadedExtension, et as disposeExtensionRegistry, f as cleanupPersistedSession, g as resolveTasksDir, h as resolvePersistDir, hn as effectiveContextWindow, ht as isSpawnTool, it as createExtensionHostRuntimeBridge, lt as basic_default, m as resolveMcpWarningsDir, mn as OUTPUT_RESERVE_TOKENS, nn as parseExtensionScanPathEnv, on as coerceExtensionConfigInput, q as updateInstalledExtension, rn as scanExtensionDirectories, rt as partitionExtensionCatalog, t as createAgent, tt as filterExtensionRegistry, un as resolveExtensionConfigValue, wt as looksBinary, x as compactConversation, y as selectFilesFromSession, z as createExtensionPromptBridge, zt as KEYBINDING_KEY_COL_WIDTH } from "./agent-6iGNP46b.js";
1
+ import { $ as useMcpAuthState, $n as buildPlanSystem, $t as restoreChainFallbacks, A as runOAuthLogin, Bt as createDiscoverySlot, Ct as SETTINGS_CHOICES, D as formatPathForCwd, Dt as clampFps, Et as SettingsProvider, G as buildVisibleMcpRows, Gt as useConfig, Ht as useDiscovery, J as createFileMcpCredentialStore, Jt as buildRunModel, K as indexOfServerRow, Kt as resolveConfig, L as loadMcpToolsCache, M as buildMcpServers, Mt as resolveTheme, O as fetchOAuthRedirect, Ot as useSettings, P as discoverProjectMcps, Q as useMcpAuthDispatch, Qn as buildBuildSystem, Qt as providerKeySetChanged, R as mcpToolsCachePath, St as SETTINGS_CATEGORIES, T as suggestSafelistEntries, Tn as accentColor, Tt as SETTINGS_TOGGLES, U as useMcpToolToggleMap, Ut as useDiscoveryOptional, V as subscribeMcpToolsCache, Vn as useActiveTodos, Vt as DiscoveryProvider, Wt as ConfigProvider, Xt as chainsEqual, Yt as chainPositionOf, Z as McpAuthProvider, Zt as filterChainFallbacks, _ as useSafeModeQueue, _n as discoverAgentsMd, _r as toolCallPreview, _t as buildHints, a as useSurfaces, an as bootTick, at as buildResumedToolResultsTurn, b as getSafelist, br as usageByModel, bt as useEnabledToggleSet, c as useStreamBuffer, cr as lastContextSizeFromTurns, ct as makeRequestInteraction, d as discoverProjectSkills, dr as marginTopFor, dt as useInteractionsActions, er as envSection, et as getMcpAuthStatus, ft as useInteractionsQueue, g as useSafeModeActions, gn as chatAutoCompactBehavior, gt as truncateTrailing, h as SafeModeProvider, hr as sumRunCosts, ht as hintsLength, i as useSelectStyle, ir as compactSummaryEvent, it as PRESENT_PLAN_TOOL, j as supportsOAuth, jn as TODO_STATUS_GLYPHS, jt as resolveChipColor, k as oauthUsesManualCodePaste, l as buildSkillsConfig, lr as listSessionMeta, lt as pendingInteractionsFromTurns, m as writeSessionExport, mr as stripSpawnTokensLine, mt as clipHintsToWidth, n as ThemeProvider, nn as useCompletion, nr as createChatTurnsReadTool, nt as ASK_USER_TOOL, on as buildUpdateHint, or as deriveSessionTitle, ot as createInteractionTools, pr as serverToolResultSummary, pt as EMPTY_HINTS, q as parentServerName, qt as resolveStoragePaths, r as useColors, rn as tryOpenBrowser, rt as InteractionsProvider, s as useTheme, sn as useUpdateCheck, sr as eventsFromTurns, t as computeTurnAnchors, tn as toggleChainEntry, tr as chatReferenceTokensForPrompt, u as defaultSkillScanPaths, ur as loadState, vr as toolResultText, wt as SETTINGS_INPUTS, x as isOnSafelist, xt as DEFAULT_SETTINGS, y as addToSafelist, yr as updateToolEventOutcomes, yt as listProjectFiles, z as refreshMcpToolsCatalog } from "./transcript-anchors-BzcuKnq8.js";
2
+ import { $ as composeExtensionPreset, B as ExtensionInstallError, Bt as ensureKeybindingsFile, Et as createModelSearchTool, H as installExtensionFromSpec, Ht as groupBindings, J as createExtensionHud, K as removeInstalledExtension, P as summaryToTurn, St as tailTruncate, Ut as keybindingsPath, Vt as formatBindingForDisplay, Wt as matchesBinding, X as discoverAndBuildExtensionRegistry, Y as registerExtensionHostModules, Yt as resolveExtensionKeybindings, _ as buildPostCompactAttachments, c as applyCompactSummaryCutoff, dn as sanitizeExtensionConfigActionPatch, en as inlineLoadedExtension, et as disposeExtensionRegistry, f as cleanupPersistedSession, g as resolveTasksDir, h as resolvePersistDir, hn as effectiveContextWindow, ht as isSpawnTool, it as createExtensionHostRuntimeBridge, lt as basic_default, m as resolveMcpWarningsDir, mn as OUTPUT_RESERVE_TOKENS, nn as parseExtensionScanPathEnv, on as coerceExtensionConfigInput, q as updateInstalledExtension, rn as scanExtensionDirectories, rt as partitionExtensionCatalog, t as createAgent, tt as filterExtensionRegistry, un as resolveExtensionConfigValue, wt as looksBinary, x as compactConversation, y as selectFilesFromSession, z as createExtensionPromptBridge, zt as KEYBINDING_KEY_COL_WIDTH } from "./agent-DhfdXgL2.js";
3
3
  import { a as formatDuration, c as previewLine, i as fmtTokens, l as shortId, n as compactPath, o as formatTaskStatus, r as fmtCost, s as formatTaskSummary, t as ageString } from "./format-BF745pLL.js";
4
4
  import { n as appendCapped } from "./output-cap-kBUHBlnq.js";
5
5
  import { i as killProcessGroup, n as SUPPORTS_PROCESS_GROUPS, r as createProcessContext } from "./contexts-A4ep-iJs.js";
@@ -14,9 +14,9 @@ import { o as withTimeout } from "./timeout-BDetbuN6.js";
14
14
  import { n as connectMcpServers, u as McpOAuthProvider } from "./mcp-BCaN_Gyg.js";
15
15
  import { a as generateStructuredData, c as shouldAutoGenerateTitle, f as commandBlockToEvent, g as parseCommandInvocation, h as executeCommand, n as patchInlineGhost, p as commandBlocksToContent, r as resolveInlineSuggestion, s as generateSessionTitle, t as createPathAutocompleteProvider } from "./inline-autocomplete-BAwBcZtD.js";
16
16
  import { s as resolveCompletionSubmit } from "./completion-core-BRo86R_L.js";
17
- import { i as installSkillFromSpec, r as SkillInstallError } from "./skills-CDpejYOf.js";
18
- import { i as ZIDANE_EXTENSION_SKILL_NAME, l as withZidaneExtensionSkill, o as extensionDirForCwd, r as EXTENSION_EDIT_METADATA_KEY, s as extensionScaffold, t as loginMcpServer } from "./login-B5nMPF8w.js";
19
- import { C as restoreModelOptions, S as piIdOf, _ as modelOptionsFor, m as getContextWindow, p as enabledModelOptions, s as setProviderCredential, t as detectAuth, v as modelSupportsReasoning } from "./auth-BH6G59RL.js";
17
+ import { i as installSkillFromSpec, r as SkillInstallError } from "./skills-DKWqoaYH.js";
18
+ import { i as ZIDANE_EXTENSION_SKILL_NAME, l as withZidaneExtensionSkill, o as extensionDirForCwd, r as EXTENSION_EDIT_METADATA_KEY, s as extensionScaffold, t as loginMcpServer } from "./login-Clf-R27F.js";
19
+ import { C as restoreModelOptions, S as piIdOf, _ as modelOptionsFor, m as getContextWindow, p as enabledModelOptions, s as setProviderCredential, t as detectAuth, v as modelSupportsReasoning } from "./auth-TZg3MVi2.js";
20
20
  import { createDockerContext } from "./contexts/docker.js";
21
21
  import { createTuiStore } from "./session/sqlite.js";
22
22
  import { $ as buildEditOutcomesAnnotation, A as blendHsl, B as turnSelectionOwnership, C as stripHtmlCommentsOutsideCode, E as uniqueSkillNamesFromReferences, F as isTurnHighlighted, H as buildContextualDiff, I as isUserBashEvent, J as filetypeFromPath, L as isVisible, M as BASH_CALL_ID_PREFIX, N as EDIT_TOOL_NAMES, O as createFilesCompletionProvider, P as isEditErrorResult, R as promptHistoryFromEvents, S as splitMarkdownCodeBlocks, T as createSkillsCompletionProvider, U as buildUnifiedDiff, W as clipDiffForRender, Y as previewEditPayload, Z as summarizeEditPayload, _ as filterModelCatalog, a as TOOL_DISPLAY, at as stripEditOutcomesAnnotation, b as chunkMarkdownForRender, d as finalizeStreamingMarkdown, f as finalizeStreamingMarkdownForOwner, g as buildModelCatalog, h as splitPromptSegments, i as turnAsText, it as rewriteMultiEditHeader, j as buildLinearRamp, lt as createChatsCompletionProvider, m as turnContextSize, n as deleteTurnSafely, nt as parseEditOutcomesFromResult, o as displayNameFor, ot as summarizeOutcomes, q as extractEditPayload, r as truncateTurnsAt, rt as resolveApprovalForPayload, s as formatToolCall, tt as mergeApprovalAndBodyOutcomes, u as capTranscriptEvents, v as indexOfEntry, x as normalizeMarkdownCodeFences, z as selectableTurnIds } from "./turn-operations-CXjRaltC.js";
@@ -1505,7 +1505,7 @@ const BASH_RESULT_MAX_LINES = 10;
1505
1505
  * same-turn events read as one continuous highlighted block instead of a
1506
1506
  * striped list.
1507
1507
  */
1508
- const EventLine = memo(({ event, previous, depthOffset = 0, selected = false, anchorId, hideChildLabel = false, settleCodeEpoch = 0 }) => {
1508
+ const EventLine = memo(({ event, previous, depthOffset = 0, selected = false, anchorId, hideChildLabel = false, settleCodeEpoch = 0, liveSpawn }) => {
1509
1509
  const SURFACE = useSurfaces();
1510
1510
  const gap = marginTopFor(event, previous);
1511
1511
  return /* @__PURE__ */ jsx$1("box", {
@@ -1524,7 +1524,8 @@ const EventLine = memo(({ event, previous, depthOffset = 0, selected = false, an
1524
1524
  depthOffset,
1525
1525
  hideChildLabel,
1526
1526
  selected,
1527
- settleCodeEpoch
1527
+ settleCodeEpoch,
1528
+ liveSpawn
1528
1529
  })
1529
1530
  });
1530
1531
  });
@@ -1977,10 +1978,12 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false }) {
1977
1978
  for (let i = items.length - 1; i >= 0 && open.size > 0; i--) {
1978
1979
  const item = items[i];
1979
1980
  const here = [];
1980
- for (const [id, childEvents] of open) if (item.kind === "child-run" ? item.events.some((e) => e.childId === id) : item.event.kind === "spawn-start" && item.event.childId === id) {
1981
+ for (const [id, child] of open) if (item.kind === "child-run" ? item.events.some((e) => e.childId === id) : item.event.kind === "spawn-start" && item.event.childId === id) {
1981
1982
  here.push({
1982
1983
  id,
1983
- activity: spawnActivity(childEvents)
1984
+ activity: spawnActivity(child.events),
1985
+ startedAt: child.start.spawn?.startedAt ?? Date.now(),
1986
+ turns: observedSpawnTurns(child.events)
1984
1987
  });
1985
1988
  open.delete(id);
1986
1989
  }
@@ -2030,18 +2033,14 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false }) {
2030
2033
  children: [items.map((item, i) => {
2031
2034
  if (item.kind === "event") {
2032
2035
  const live = liveByItem.get(i);
2033
- const line = /* @__PURE__ */ jsx$1(EventLine, {
2036
+ return /* @__PURE__ */ jsx$1(EventLine, {
2034
2037
  event: item.event,
2035
2038
  previous: item.previous,
2036
2039
  selected: isTurnHighlighted(item.event, selectedTurnId, ownership),
2037
2040
  anchorId: anchors.ids[i][0],
2038
- settleCodeEpoch: codeSettle.current.targets.has(item.event) ? codeSettle.current.epoch : 0
2039
- }, live ? void 0 : i);
2040
- if (!live) return line;
2041
- return /* @__PURE__ */ jsxs("box", { children: [line, live.map((spawn) => /* @__PURE__ */ jsx$1(LiveSpawnRow, {
2042
- spawn,
2043
- showLabel: true
2044
- }, spawn.id))] }, i);
2041
+ settleCodeEpoch: codeSettle.current.targets.has(item.event) ? codeSettle.current.epoch : 0,
2042
+ liveSpawn: live?.[0]
2043
+ }, i);
2045
2044
  }
2046
2045
  return /* @__PURE__ */ jsx$1(SubagentBlock, {
2047
2046
  events: item.events,
@@ -2068,27 +2067,37 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false }) {
2068
2067
  * events they've produced since. Computed against the FULL event list — a
2069
2068
  * parent-depth row (e.g. a background-task banner) can split one child's
2070
2069
  * events across two boxes, and only a global scan knows whether the child
2071
- * actually finished. `spawn:error` emits a child-tagged `error` event and
2072
- * never a `spawn-end`, so that closes the child too. Live-only signal:
2073
- * replayed sessions always synthesize a `spawn-end` per child run, so
2074
- * nothing stays open after a reload.
2070
+ * actually finished. `spawn:complete` fires for EVERY terminal state
2071
+ * (success/abort/timeout/error \u2014 see spawn.ts), so a `spawn-end` marker is
2072
+ * the normal close; a child-tagged `error` event (`spawn:error`, e.g. a
2073
+ * destroy failure surfaced after completion) also closes, covering
2074
+ * whichever order the two arrive in. Live-only signal: replayed sessions
2075
+ * always synthesize a `spawn-end` per child run, so nothing stays open
2076
+ * after a reload.
2075
2077
  */
2076
2078
  function openSpawns(events) {
2077
2079
  const open = /* @__PURE__ */ new Map();
2078
2080
  for (const event of events) {
2079
2081
  if (!event.childId || (event.depth ?? 0) === 0) continue;
2080
2082
  if (event.kind === "spawn-start") {
2081
- open.set(event.childId, []);
2083
+ open.set(event.childId, {
2084
+ start: event,
2085
+ events: []
2086
+ });
2082
2087
  continue;
2083
2088
  }
2084
2089
  if (event.kind === "spawn-end" || event.kind === "error") {
2085
2090
  open.delete(event.childId);
2086
2091
  continue;
2087
2092
  }
2088
- open.get(event.childId)?.push(event);
2093
+ open.get(event.childId)?.events.push(event);
2089
2094
  }
2090
2095
  return open;
2091
2096
  }
2097
+ /** Distinct child-loop turns observed in the streamed event tail. */
2098
+ function observedSpawnTurns(events) {
2099
+ return new Set(events.flatMap((event) => event.turnId ? [event.turnId] : [])).size;
2100
+ }
2092
2101
  /**
2093
2102
  * One-word-ish description of what a running child is doing right now,
2094
2103
  * derived from its trailing events: `text` while prose streams, `thinking`
@@ -2114,8 +2123,30 @@ function spawnActivity(events) {
2114
2123
  default: return "working";
2115
2124
  }
2116
2125
  }
2126
+ /**
2127
+ * Pair lifecycle markers from the end so reused labels (`child-1` in a
2128
+ * later top-level run) don't make an old terminal hide a new active start.
2129
+ * Exported for the layout invariant test; renderers otherwise use it only
2130
+ * through {@link partitionTranscript}.
2131
+ */
2132
+ function collapseCompletedSpawnStarts(events) {
2133
+ const keep = Array.from({ length: events.length }).fill(true);
2134
+ const terminalByChild = /* @__PURE__ */ new Map();
2135
+ for (let i = events.length - 1; i >= 0; i--) {
2136
+ const event = events[i];
2137
+ if (event.kind === "spawn-end" && event.childId) terminalByChild.set(event.childId, (terminalByChild.get(event.childId) ?? 0) + 1);
2138
+ else if (event.kind === "spawn-start" && event.childId) {
2139
+ const terminals = terminalByChild.get(event.childId) ?? 0;
2140
+ if (terminals > 0) {
2141
+ keep[i] = false;
2142
+ terminalByChild.set(event.childId, terminals - 1);
2143
+ }
2144
+ }
2145
+ }
2146
+ return events.filter((_, i) => keep[i]);
2147
+ }
2117
2148
  function partitionTranscript(events, settings) {
2118
- const visible = events.filter((e) => isVisible(e, settings));
2149
+ const visible = collapseCompletedSpawnStarts(events).filter((e) => isVisible(e, settings));
2119
2150
  if (visible.length === 0) return [];
2120
2151
  if (settings.hideSubagentOutput) return visible.map((event, i) => ({
2121
2152
  kind: "event",
@@ -2171,7 +2202,7 @@ function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds, cod
2171
2202
  const title = childIds.length === 0 ? " subagent " : childIds.length === 1 ? ` ${childIds[0]} ` : ` subagents · ${childIds.join(", ")} `;
2172
2203
  const marginTop = previous ? 1 : 0;
2173
2204
  const hideChildLabel = childIds.length === 1;
2174
- return /* @__PURE__ */ jsxs("box", {
2205
+ return /* @__PURE__ */ jsx$1("box", {
2175
2206
  title,
2176
2207
  style: {
2177
2208
  border: true,
@@ -2185,38 +2216,81 @@ function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds, cod
2185
2216
  flexShrink: 0,
2186
2217
  alignSelf: "stretch"
2187
2218
  },
2188
- children: [events.map((evt, i) => /* @__PURE__ */ jsx$1(EventLine, {
2219
+ children: events.map((evt, i) => /* @__PURE__ */ jsx$1(EventLine, {
2189
2220
  event: evt,
2190
2221
  previous: events[i - 1],
2191
2222
  depthOffset: 1,
2192
2223
  selected: selectedTurnId !== null && evt.turnId === selectedTurnId,
2193
2224
  anchorId: anchorIds?.[i],
2194
2225
  hideChildLabel,
2195
- settleCodeEpoch: codeSettleTargets?.has(evt) ? codeSettleEpoch : 0
2196
- }, i)), live?.map((spawn) => /* @__PURE__ */ jsx$1("box", {
2197
- style: { marginTop: events.length > 0 ? 1 : 0 },
2198
- children: /* @__PURE__ */ jsx$1(LiveSpawnRow, {
2199
- spawn,
2200
- showLabel: !hideChildLabel
2201
- })
2202
- }, spawn.id))]
2226
+ settleCodeEpoch: codeSettleTargets?.has(evt) ? codeSettleEpoch : 0,
2227
+ liveSpawn: evt.kind === "spawn-start" ? live?.find((spawn) => spawn.id === evt.childId) : void 0
2228
+ }, i))
2203
2229
  });
2204
2230
  }
2205
- /** Spinner + current-activity line for a still-running subagent. */
2206
- function LiveSpawnRow({ spawn, showLabel }) {
2231
+ /**
2232
+ * Stable one-row subagent lifecycle layout. Identity/model/task stay in
2233
+ * the left lane for the whole run; only the right tail changes:
2234
+ * active `2 turns · 14s · ⠋ tool call`, done `4 turns`.
2235
+ */
2236
+ function SpawnLifecycleMarker({ row, dim, event, hideChildLabel, live }) {
2207
2237
  const COLOR = useColors();
2208
- return /* @__PURE__ */ jsxs("text", {
2209
- fg: COLOR.dim,
2238
+ const frame = useSpinnerFrame();
2239
+ const terminal = event.kind === "spawn-end";
2240
+ const failed = terminal && (event.text.startsWith("error") || event.text.startsWith("aborted"));
2241
+ const turns = terminal ? event.spawn?.turns : live?.turns;
2242
+ const turnLabel = `${turns ?? 0} turn${turns === 1 ? "" : "s"}`;
2243
+ const elapsed = live ? formatDuration(Math.max(0, Date.now() - live.startedAt)) : null;
2244
+ return /* @__PURE__ */ jsxs("box", {
2245
+ style: {
2246
+ ...row,
2247
+ flexDirection: "row",
2248
+ alignItems: "center"
2249
+ },
2210
2250
  children: [
2211
- /* @__PURE__ */ jsx$1(StatusSpinner, { color: COLOR.warn }),
2212
- showLabel && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx$1("span", {
2213
- fg: COLOR.brand,
2214
- children: ` ${spawn.id}`
2215
- }), /* @__PURE__ */ jsx$1("span", {
2251
+ /* @__PURE__ */ jsxs("text", {
2252
+ fg: dim,
2253
+ wrapMode: "none",
2254
+ style: { flexShrink: 1 },
2255
+ children: [
2256
+ /* @__PURE__ */ jsx$1("span", {
2257
+ fg: failed ? COLOR.error : COLOR.accent,
2258
+ children: terminal ? failed ? "✗ " : "🌳 " : "🌱 "
2259
+ }),
2260
+ !hideChildLabel && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx$1("span", {
2261
+ fg: COLOR.brand,
2262
+ children: event.childId ?? "child"
2263
+ }), /* @__PURE__ */ jsx$1("span", {
2264
+ fg: COLOR.mute,
2265
+ children: " · "
2266
+ })] }),
2267
+ event.model !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx$1("span", {
2268
+ fg: COLOR.model,
2269
+ children: event.model
2270
+ }), /* @__PURE__ */ jsx$1("span", {
2271
+ fg: COLOR.mute,
2272
+ children: " · "
2273
+ })] }),
2274
+ /* @__PURE__ */ jsx$1("span", {
2275
+ fg: COLOR.dim,
2276
+ children: terminal ? event.spawn?.task ?? event.text : event.text
2277
+ })
2278
+ ]
2279
+ }),
2280
+ /* @__PURE__ */ jsx$1("box", { style: { flexGrow: 1 } }),
2281
+ /* @__PURE__ */ jsxs("text", {
2216
2282
  fg: COLOR.mute,
2217
- children: " ·"
2218
- })] }),
2219
- ` ${spawn.activity}`
2283
+ wrapMode: "none",
2284
+ style: { flexShrink: 0 },
2285
+ children: [/* @__PURE__ */ jsx$1("span", { children: turnLabel }), live && /* @__PURE__ */ jsxs(Fragment, { children: [
2286
+ /* @__PURE__ */ jsx$1("span", { children: ` · ${elapsed} · ` }),
2287
+ /* @__PURE__ */ jsx$1("span", {
2288
+ fg: COLOR.warn,
2289
+ children: frame
2290
+ }),
2291
+ /* @__PURE__ */ jsx$1("span", { children: ` ${live.activity}` })
2292
+ ] })]
2293
+ })
2220
2294
  ]
2221
2295
  });
2222
2296
  }
@@ -2259,7 +2333,7 @@ function rowStyle(paddingLeft) {
2259
2333
  alignSelf: "stretch"
2260
2334
  };
2261
2335
  }
2262
- function EventLineImpl({ event, previous, depthOffset = 0, hideChildLabel = false, selected = false, settleCodeEpoch = 0 }) {
2336
+ function EventLineImpl({ event, previous, depthOffset = 0, hideChildLabel = false, selected = false, settleCodeEpoch = 0, liveSpawn }) {
2263
2337
  const COLOR = useColors();
2264
2338
  const { settings } = useSettings();
2265
2339
  const cleanText = stripTerminalControlChars(event.text);
@@ -2382,58 +2456,18 @@ function EventLineImpl({ event, previous, depthOffset = 0, hideChildLabel = fals
2382
2456
  settleCodeEpoch
2383
2457
  })
2384
2458
  });
2385
- case "spawn-start": return /* @__PURE__ */ jsx$1("box", {
2386
- style: row,
2387
- children: /* @__PURE__ */ jsxs("text", {
2388
- fg: COLOR.dim,
2389
- children: [
2390
- /* @__PURE__ */ jsx$1("span", {
2391
- fg: COLOR.accent,
2392
- children: "🌱 "
2393
- }),
2394
- !hideChildLabel && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx$1("span", {
2395
- fg: COLOR.brand,
2396
- children: event.childId ?? "child"
2397
- }), /* @__PURE__ */ jsx$1("span", {
2398
- fg: COLOR.mute,
2399
- children: " · "
2400
- })] }),
2401
- event.model !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx$1("span", {
2402
- fg: COLOR.model,
2403
- children: event.model
2404
- }), /* @__PURE__ */ jsx$1("span", {
2405
- fg: COLOR.mute,
2406
- children: " · "
2407
- })] }),
2408
- /* @__PURE__ */ jsx$1("span", {
2409
- fg: COLOR.dim,
2410
- children: safeText
2411
- })
2412
- ]
2413
- })
2459
+ case "spawn-start": return /* @__PURE__ */ jsx$1(SpawnLifecycleMarker, {
2460
+ row,
2461
+ dim: COLOR.dim,
2462
+ event,
2463
+ hideChildLabel,
2464
+ live: liveSpawn
2414
2465
  });
2415
- case "spawn-end": return /* @__PURE__ */ jsx$1("box", {
2416
- style: row,
2417
- children: /* @__PURE__ */ jsxs("text", {
2418
- fg: COLOR.dim,
2419
- children: [
2420
- /* @__PURE__ */ jsx$1("span", {
2421
- fg: COLOR.accent,
2422
- children: "🌳 "
2423
- }),
2424
- !hideChildLabel && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx$1("span", {
2425
- fg: COLOR.brand,
2426
- children: event.childId ?? "child"
2427
- }), /* @__PURE__ */ jsx$1("span", {
2428
- fg: COLOR.mute,
2429
- children: " · "
2430
- })] }),
2431
- /* @__PURE__ */ jsx$1("span", {
2432
- fg: COLOR.mute,
2433
- children: safeText
2434
- })
2435
- ]
2436
- })
2466
+ case "spawn-end": return /* @__PURE__ */ jsx$1(SpawnLifecycleMarker, {
2467
+ row,
2468
+ dim: COLOR.dim,
2469
+ event,
2470
+ hideChildLabel
2437
2471
  });
2438
2472
  case "compact-summary": return /* @__PURE__ */ jsx$1(CompactSummaryBlock, {
2439
2473
  event,
@@ -4651,6 +4685,44 @@ function CwdPickerModal({ currentCwd, onPick }) {
4651
4685
  });
4652
4686
  }
4653
4687
  //#endregion
4688
+ //#region src/tui/project-location-context.tsx
4689
+ const ProjectLocationContext = createContext(null);
4690
+ /** Resolve the project root used by BOTH discovery and agent activation. */
4691
+ function resolveProjectLocation(cwd) {
4692
+ return {
4693
+ cwd,
4694
+ projectDir: findGitRoot(cwd) ?? cwd
4695
+ };
4696
+ }
4697
+ /**
4698
+ * Single source of truth for the TUI's active cwd/project root. It must
4699
+ * sit ABOVE both `DiscoveryShell` and `AppShell`: discovery used to derive
4700
+ * a frozen root from `process.cwd()` while AppShell independently honored
4701
+ * `launch.cwd` and runtime project switches, causing `.agents` skills/MCPs
4702
+ * to be read from the wrong repository.
4703
+ */
4704
+ function ProjectLocationProvider({ initialCwd, children }) {
4705
+ const [location, setLocation] = useState(() => resolveProjectLocation(initialCwd));
4706
+ const setCwd = useCallback((next) => {
4707
+ process.chdir(next);
4708
+ setLocation(resolveProjectLocation(next));
4709
+ }, []);
4710
+ const value = useMemo(() => ({
4711
+ cwd: location.cwd,
4712
+ projectDir: location.projectDir,
4713
+ setCwd
4714
+ }), [location, setCwd]);
4715
+ return /* @__PURE__ */ jsx(ProjectLocationContext.Provider, {
4716
+ value,
4717
+ children
4718
+ });
4719
+ }
4720
+ function useProjectLocation() {
4721
+ const value = useContext(ProjectLocationContext);
4722
+ if (!value) throw new Error("useProjectLocation must be used inside ProjectLocationProvider");
4723
+ return value;
4724
+ }
4725
+ //#endregion
4654
4726
  //#region src/tui/discovery-shell.tsx
4655
4727
  /**
4656
4728
  * SWR throttles. `files` is short so a long-open `@` popover picks up
@@ -4660,7 +4732,6 @@ function CwdPickerModal({ currentCwd, onPick }) {
4660
4732
  const FILES_REFRESH_THROTTLE_MS = 3e3;
4661
4733
  const SKILLS_REFRESH_THROTTLE_MS = 3e4;
4662
4734
  const MCP_TOOLS_CACHE_POLL_MS = 4e3;
4663
- const MCPS_CONFIG_POLL_MS = 3e3;
4664
4735
  function debugLog$1(...args) {
4665
4736
  if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/tui] ${args.map(errorMessage).join(" ")}\n`);
4666
4737
  }
@@ -4671,7 +4742,7 @@ function DiscoveryShell({ children }) {
4671
4742
  const dispatchAuth = useMcpAuthDispatch();
4672
4743
  const dispatchAuthRef = useRef(dispatchAuth);
4673
4744
  dispatchAuthRef.current = dispatchAuth;
4674
- const [projectDir] = useState(() => findGitRoot(process.cwd()) ?? process.cwd());
4745
+ const { projectDir } = useProjectLocation();
4675
4746
  const dataDir = config.paths.userDir;
4676
4747
  const mcpCredentialStore = useMemo(() => createFileMcpCredentialStore(dataDir), [dataDir]);
4677
4748
  const [skillsCatalog, setSkillsCatalog] = useState([]);
@@ -4797,25 +4868,6 @@ function DiscoveryShell({ children }) {
4797
4868
  mcpCredentialStore,
4798
4869
  foreignAgents
4799
4870
  ]);
4800
- useEffect(() => {
4801
- let lastSignature = mcpsConfigSignature(projectDir, config.prefix, foreignAgents);
4802
- const id = setInterval(() => {
4803
- try {
4804
- const signature = mcpsConfigSignature(projectDir, config.prefix, foreignAgents);
4805
- if (signature === lastSignature) return;
4806
- lastSignature = signature;
4807
- refreshMcps();
4808
- } catch (err) {
4809
- debugLog$1("mcps config poll failed", err);
4810
- }
4811
- }, MCPS_CONFIG_POLL_MS);
4812
- return () => clearInterval(id);
4813
- }, [
4814
- projectDir,
4815
- config.prefix,
4816
- refreshMcps,
4817
- foreignAgents
4818
- ]);
4819
4871
  useEffect(() => {
4820
4872
  let lastSignature = cacheFileSignature(dataDir);
4821
4873
  const id = setInterval(() => {
@@ -4873,21 +4925,6 @@ function cacheFileSignature(dataDir) {
4873
4925
  const stat = statSync(mcpToolsCachePath(dataDir), { throwIfNoEntry: false });
4874
4926
  return stat ? `${stat.mtimeMs}:${stat.size}` : null;
4875
4927
  }
4876
- /**
4877
- * Change signature across every candidate `mcp(s).json` path (project +
4878
- * user, both filename variants). Missing files contribute their bare path
4879
- * so create/delete flips the signature just like an edit does.
4880
- */
4881
- function mcpsConfigSignature(projectDir, prefix, foreignAgents) {
4882
- return mcpsDiscoveryPaths({
4883
- cwd: projectDir,
4884
- prefix,
4885
- foreignAgents
4886
- }).map(({ path }) => {
4887
- const stat = statSync(path, { throwIfNoEntry: false });
4888
- return stat ? `${path}:${stat.mtimeMs}:${stat.size}` : path;
4889
- }).join("|");
4890
- }
4891
4928
  function readToolsByServer(dataDir) {
4892
4929
  const cache = loadMcpToolsCache({ dataDir });
4893
4930
  const out = {};
@@ -12705,11 +12742,13 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
12705
12742
  })).catch((err) => {
12706
12743
  if (err instanceof SkillInstallError && err.code === "multiple-candidates" && err.candidates && err.candidates.length > 0) {
12707
12744
  setSkillOp(null);
12708
- const items = err.details && err.details.length === err.candidates.length ? err.details : err.candidates.map((rel) => ({ rel }));
12745
+ const fullCatalog = err.details !== void 0 && err.details.length === err.candidates.length;
12746
+ const items = fullCatalog && err.details ? err.details : err.candidates.map((rel) => ({ rel }));
12709
12747
  setSkillImportAll({
12710
12748
  source: req.source,
12711
12749
  scope: req.choice,
12712
- items
12750
+ items,
12751
+ fullCatalog
12713
12752
  });
12714
12753
  return;
12715
12754
  }
@@ -13586,7 +13625,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
13586
13625
  onConfirm: (selected) => {
13587
13626
  const req = skillImportAll;
13588
13627
  setSkillImportAll(null);
13589
- runSkillInstall(selected.length === req.items.length ? {
13628
+ runSkillInstall(req.fullCatalog && selected.length === req.items.length ? {
13590
13629
  source: req.source,
13591
13630
  all: true,
13592
13631
  choice: req.scope
@@ -16026,7 +16065,8 @@ function App({ config }) {
16026
16065
  */
16027
16066
  function ThemedShell() {
16028
16067
  const { settings } = useSettings();
16029
- const [extensionRegistry, setExtensionRegistry] = useState(useConfig().extensions);
16068
+ const config = useConfig();
16069
+ const [extensionRegistry, setExtensionRegistry] = useState(config.extensions);
16030
16070
  useEffect(() => () => {
16031
16071
  disposeExtensionRegistry(extensionRegistry);
16032
16072
  }, [extensionRegistry]);
@@ -16043,7 +16083,10 @@ function ThemedShell() {
16043
16083
  registry: renderersRegistry,
16044
16084
  children: /* @__PURE__ */ jsx$1(ThemeProvider, {
16045
16085
  theme,
16046
- children: /* @__PURE__ */ jsx$1(MdStyleProvider, { children: /* @__PURE__ */ jsx$1(ChipStyleProvider, { children: /* @__PURE__ */ jsx$1(SafeModeProvider, { children: /* @__PURE__ */ jsx$1(InteractionsProvider, { children: /* @__PURE__ */ jsx$1(McpAuthProvider, { children: /* @__PURE__ */ jsx$1(DiscoveryShell, { children: /* @__PURE__ */ jsx$1(ModalRoot, { children: /* @__PURE__ */ jsx$1(AppShell, {}) }) }) }) }) }) }) })
16086
+ children: /* @__PURE__ */ jsx$1(MdStyleProvider, { children: /* @__PURE__ */ jsx$1(ChipStyleProvider, { children: /* @__PURE__ */ jsx$1(SafeModeProvider, { children: /* @__PURE__ */ jsx$1(InteractionsProvider, { children: /* @__PURE__ */ jsx$1(McpAuthProvider, { children: /* @__PURE__ */ jsx$1(ProjectLocationProvider, {
16087
+ initialCwd: config.launch?.cwd ?? process.cwd(),
16088
+ children: /* @__PURE__ */ jsx$1(DiscoveryShell, { children: /* @__PURE__ */ jsx$1(ModalRoot, { children: /* @__PURE__ */ jsx$1(AppShell, {}) }) })
16089
+ }) }) }) }) }) })
16047
16090
  })
16048
16091
  })
16049
16092
  });
@@ -16219,16 +16262,9 @@ function AppShell() {
16219
16262
  useEffect(() => {
16220
16263
  smoothStreamingRef.current = settings.smoothStreaming;
16221
16264
  }, [settings.smoothStreaming]);
16222
- const initialCwd = launch?.cwd ?? process.cwd();
16223
- const [projectDir, setProjectDir] = useState(() => findGitRoot(initialCwd) ?? initialCwd);
16224
- const [cwd, setCwdRaw] = useState(() => initialCwd);
16265
+ const { cwd, projectDir, setCwd } = useProjectLocation();
16225
16266
  const cwdRef = useRef(cwd);
16226
16267
  cwdRef.current = cwd;
16227
- const setCwd = useCallback((next) => {
16228
- process.chdir(next);
16229
- setCwdRaw(next);
16230
- setProjectDir(findGitRoot(next) ?? next);
16231
- }, []);
16232
16268
  const safelistRef = useRef(null);
16233
16269
  const readSafelist = useCallback(() => {
16234
16270
  if (safelistRef.current === null) safelistRef.current = getSafelist(dataDir, projectDir);
@@ -17613,19 +17649,26 @@ function AppShell() {
17613
17649
  });
17614
17650
  const spawnStartedAt = /* @__PURE__ */ new Map();
17615
17651
  agent.hooks.hook("spawn:before", ({ id, task, depth, model }) => {
17616
- spawnStartedAt.set(id, Date.now());
17652
+ const startedAt = Date.now();
17617
17653
  const taskPreview = previewLine(task, 80);
17654
+ spawnStartedAt.set(id, {
17655
+ startedAt,
17656
+ task: taskPreview,
17657
+ ...model ? { model } : {}
17658
+ });
17618
17659
  stream.appendImmediate({
17619
17660
  kind: "spawn-start",
17620
17661
  text: taskPreview,
17621
17662
  childId: id,
17622
17663
  depth: depth ?? 1,
17664
+ spawn: { startedAt },
17623
17665
  ...model ? { model } : {}
17624
17666
  });
17625
17667
  });
17626
17668
  agent.hooks.hook("spawn:complete", ({ id, depth, status, stats }) => {
17627
17669
  const tag = status === "aborted" ? "aborted" : status === "error" ? "error" : "done";
17628
- const startedAt = spawnStartedAt.get(id);
17670
+ const started = spawnStartedAt.get(id);
17671
+ const startedAt = started?.startedAt;
17629
17672
  spawnStartedAt.delete(id);
17630
17673
  const elapsed = startedAt !== void 0 ? ` · ${formatDuration(Date.now() - startedAt)}` : "";
17631
17674
  const cost = flattenTurns(stats).reduce((sum, turn) => sum + (turn.cost ?? 0), 0);
@@ -17634,7 +17677,13 @@ function AppShell() {
17634
17677
  kind: "spawn-end",
17635
17678
  text: segments ? `${tag}${segments} · ${formatTokenUsage(stats)}` : `${tag} ${formatTokenUsage(stats)}`,
17636
17679
  childId: id,
17637
- depth: depth ?? 1
17680
+ depth: depth ?? 1,
17681
+ spawn: {
17682
+ startedAt: startedAt ?? Date.now(),
17683
+ ...started?.task ? { task: started.task } : {},
17684
+ turns: stats.turns
17685
+ },
17686
+ ...started?.model ? { model: started.model } : {}
17638
17687
  });
17639
17688
  });
17640
17689
  agent.hooks.hook("spawn:error", ({ id, depth, error }) => {