zidane 6.2.11 → 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 (75) 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 +4 -4
  16. package/dist/chat.js +3 -3
  17. package/dist/contexts/daytona.d.ts +1 -1
  18. package/dist/contexts/e2b.d.ts +1 -1
  19. package/dist/eval.d.ts +1 -1
  20. package/dist/extensions.d.ts +1 -1
  21. package/dist/extensions.js +1 -1
  22. package/dist/headless.d.ts +1 -1
  23. package/dist/headless.js +1 -1
  24. package/dist/{index-BFNt9GAs.d.ts → index-l0wehkWU.d.ts} +44 -6
  25. package/dist/index-l0wehkWU.d.ts.map +1 -0
  26. package/dist/index.d.ts +2 -2
  27. package/dist/index.js +4 -4
  28. package/dist/{login-B5nMPF8w.js → login-Clf-R27F.js} +2 -2
  29. package/dist/{login-B5nMPF8w.js.map → login-Clf-R27F.js.map} +1 -1
  30. package/dist/mcp.d.ts +1 -1
  31. package/dist/output/stream-json.d.ts +1 -1
  32. package/dist/output/terminal.d.ts +1 -1
  33. package/dist/presets.d.ts +1 -1
  34. package/dist/presets.js +1 -1
  35. package/dist/providers/anthropic.d.ts +1 -1
  36. package/dist/providers/anthropic.js +1 -1
  37. package/dist/providers/arcee.d.ts +1 -1
  38. package/dist/providers/baseten.d.ts +1 -1
  39. package/dist/providers/cerebras.d.ts +1 -1
  40. package/dist/providers/local.d.ts +1 -1
  41. package/dist/providers/openai-compat.d.ts +1 -1
  42. package/dist/providers/openai.d.ts +1 -1
  43. package/dist/providers/openrouter.d.ts +1 -1
  44. package/dist/providers/xai.d.ts +1 -1
  45. package/dist/providers.d.ts +2 -2
  46. package/dist/providers.js +1 -1
  47. package/dist/restate.d.ts +1 -1
  48. package/dist/session/sqlite.d.ts +1 -1
  49. package/dist/session.d.ts +1 -1
  50. package/dist/{skills-CDpejYOf.js → skills-DKWqoaYH.js} +4 -3
  51. package/dist/skills-DKWqoaYH.js.map +1 -0
  52. package/dist/skills.d.ts +1 -1
  53. package/dist/skills.js +1 -1
  54. package/dist/{tool-formatters-B_zQsYfa.d.ts → tool-formatters-BSwVkSX2.d.ts} +2 -2
  55. package/dist/{tool-formatters-B_zQsYfa.d.ts.map → tool-formatters-BSwVkSX2.d.ts.map} +1 -1
  56. package/dist/tools/fetch-url.d.ts +1 -1
  57. package/dist/tools/web-search.d.ts +1 -1
  58. package/dist/tools.d.ts +1 -1
  59. package/dist/tools.js +1 -1
  60. package/dist/{transcript-anchors-B_kUHJ16.js → transcript-anchors-BzcuKnq8.js} +106 -34
  61. package/dist/transcript-anchors-BzcuKnq8.js.map +1 -0
  62. package/dist/{transcript-anchors-2wafjV-s.d.ts → transcript-anchors-DKjXpQ0h.d.ts} +2 -2
  63. package/dist/{transcript-anchors-2wafjV-s.d.ts.map → transcript-anchors-DKjXpQ0h.d.ts.map} +1 -1
  64. package/dist/tui.d.ts +3 -3
  65. package/dist/tui.d.ts.map +1 -1
  66. package/dist/tui.js +199 -115
  67. package/dist/tui.js.map +1 -1
  68. package/dist/{turn-operations-DVA52KMG.d.ts → turn-operations-CjkgQKmR.d.ts} +3 -3
  69. package/dist/{turn-operations-DVA52KMG.d.ts.map → turn-operations-CjkgQKmR.d.ts.map} +1 -1
  70. package/dist/types.d.ts +1 -1
  71. package/package.json +1 -1
  72. package/dist/anthropic-BD-lwEKp.js.map +0 -1
  73. package/dist/index-BFNt9GAs.d.ts.map +0 -1
  74. package/dist/skills-CDpejYOf.js.map +0 -1
  75. package/dist/transcript-anchors-B_kUHJ16.js.map +0 -1
package/dist/tui.js CHANGED
@@ -1,5 +1,5 @@
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-B_kUHJ16.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
@@ -4670,7 +4742,7 @@ function DiscoveryShell({ children }) {
4670
4742
  const dispatchAuth = useMcpAuthDispatch();
4671
4743
  const dispatchAuthRef = useRef(dispatchAuth);
4672
4744
  dispatchAuthRef.current = dispatchAuth;
4673
- const [projectDir] = useState(() => findGitRoot(process.cwd()) ?? process.cwd());
4745
+ const { projectDir } = useProjectLocation();
4674
4746
  const dataDir = config.paths.userDir;
4675
4747
  const mcpCredentialStore = useMemo(() => createFileMcpCredentialStore(dataDir), [dataDir]);
4676
4748
  const [skillsCatalog, setSkillsCatalog] = useState([]);
@@ -12670,11 +12742,13 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
12670
12742
  })).catch((err) => {
12671
12743
  if (err instanceof SkillInstallError && err.code === "multiple-candidates" && err.candidates && err.candidates.length > 0) {
12672
12744
  setSkillOp(null);
12673
- 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 }));
12674
12747
  setSkillImportAll({
12675
12748
  source: req.source,
12676
12749
  scope: req.choice,
12677
- items
12750
+ items,
12751
+ fullCatalog
12678
12752
  });
12679
12753
  return;
12680
12754
  }
@@ -13551,7 +13625,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
13551
13625
  onConfirm: (selected) => {
13552
13626
  const req = skillImportAll;
13553
13627
  setSkillImportAll(null);
13554
- runSkillInstall(selected.length === req.items.length ? {
13628
+ runSkillInstall(req.fullCatalog && selected.length === req.items.length ? {
13555
13629
  source: req.source,
13556
13630
  all: true,
13557
13631
  choice: req.scope
@@ -15991,7 +16065,8 @@ function App({ config }) {
15991
16065
  */
15992
16066
  function ThemedShell() {
15993
16067
  const { settings } = useSettings();
15994
- const [extensionRegistry, setExtensionRegistry] = useState(useConfig().extensions);
16068
+ const config = useConfig();
16069
+ const [extensionRegistry, setExtensionRegistry] = useState(config.extensions);
15995
16070
  useEffect(() => () => {
15996
16071
  disposeExtensionRegistry(extensionRegistry);
15997
16072
  }, [extensionRegistry]);
@@ -16008,7 +16083,10 @@ function ThemedShell() {
16008
16083
  registry: renderersRegistry,
16009
16084
  children: /* @__PURE__ */ jsx$1(ThemeProvider, {
16010
16085
  theme,
16011
- 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
+ }) }) }) }) }) })
16012
16090
  })
16013
16091
  })
16014
16092
  });
@@ -16184,16 +16262,9 @@ function AppShell() {
16184
16262
  useEffect(() => {
16185
16263
  smoothStreamingRef.current = settings.smoothStreaming;
16186
16264
  }, [settings.smoothStreaming]);
16187
- const initialCwd = launch?.cwd ?? process.cwd();
16188
- const [projectDir, setProjectDir] = useState(() => findGitRoot(initialCwd) ?? initialCwd);
16189
- const [cwd, setCwdRaw] = useState(() => initialCwd);
16265
+ const { cwd, projectDir, setCwd } = useProjectLocation();
16190
16266
  const cwdRef = useRef(cwd);
16191
16267
  cwdRef.current = cwd;
16192
- const setCwd = useCallback((next) => {
16193
- process.chdir(next);
16194
- setCwdRaw(next);
16195
- setProjectDir(findGitRoot(next) ?? next);
16196
- }, []);
16197
16268
  const safelistRef = useRef(null);
16198
16269
  const readSafelist = useCallback(() => {
16199
16270
  if (safelistRef.current === null) safelistRef.current = getSafelist(dataDir, projectDir);
@@ -17578,19 +17649,26 @@ function AppShell() {
17578
17649
  });
17579
17650
  const spawnStartedAt = /* @__PURE__ */ new Map();
17580
17651
  agent.hooks.hook("spawn:before", ({ id, task, depth, model }) => {
17581
- spawnStartedAt.set(id, Date.now());
17652
+ const startedAt = Date.now();
17582
17653
  const taskPreview = previewLine(task, 80);
17654
+ spawnStartedAt.set(id, {
17655
+ startedAt,
17656
+ task: taskPreview,
17657
+ ...model ? { model } : {}
17658
+ });
17583
17659
  stream.appendImmediate({
17584
17660
  kind: "spawn-start",
17585
17661
  text: taskPreview,
17586
17662
  childId: id,
17587
17663
  depth: depth ?? 1,
17664
+ spawn: { startedAt },
17588
17665
  ...model ? { model } : {}
17589
17666
  });
17590
17667
  });
17591
17668
  agent.hooks.hook("spawn:complete", ({ id, depth, status, stats }) => {
17592
17669
  const tag = status === "aborted" ? "aborted" : status === "error" ? "error" : "done";
17593
- const startedAt = spawnStartedAt.get(id);
17670
+ const started = spawnStartedAt.get(id);
17671
+ const startedAt = started?.startedAt;
17594
17672
  spawnStartedAt.delete(id);
17595
17673
  const elapsed = startedAt !== void 0 ? ` · ${formatDuration(Date.now() - startedAt)}` : "";
17596
17674
  const cost = flattenTurns(stats).reduce((sum, turn) => sum + (turn.cost ?? 0), 0);
@@ -17599,7 +17677,13 @@ function AppShell() {
17599
17677
  kind: "spawn-end",
17600
17678
  text: segments ? `${tag}${segments} · ${formatTokenUsage(stats)}` : `${tag} ${formatTokenUsage(stats)}`,
17601
17679
  childId: id,
17602
- 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 } : {}
17603
17687
  });
17604
17688
  });
17605
17689
  agent.hooks.hook("spawn:error", ({ id, depth, error }) => {