zidane 6.2.6 → 6.2.10

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 (103) hide show
  1. package/dist/{acp-CYJvnqPa.js → acp-DuEMbOoQ.js} +4 -4
  2. package/dist/{acp-CYJvnqPa.js.map → acp-DuEMbOoQ.js.map} +1 -1
  3. package/dist/acp-cli.js +6 -6
  4. package/dist/acp.d.ts +1 -1
  5. package/dist/acp.js +1 -1
  6. package/dist/{agent-D11SxCvA.js → agent-6iGNP46b.js} +5 -5
  7. package/dist/{agent-D11SxCvA.js.map → agent-6iGNP46b.js.map} +1 -1
  8. package/dist/agent.d.ts +1 -1
  9. package/dist/agent.js +1 -1
  10. package/dist/{anthropic-DdlSgT6K.js → anthropic-BD-lwEKp.js} +3 -3
  11. package/dist/{anthropic-DdlSgT6K.js.map → anthropic-BD-lwEKp.js.map} +1 -1
  12. package/dist/{auth-Ys_7TmRj.js → auth-BH6G59RL.js} +8 -6
  13. package/dist/auth-BH6G59RL.js.map +1 -0
  14. package/dist/chat/pure.d.ts +3 -3
  15. package/dist/chat.d.ts +14 -44
  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/eval.js +1 -1
  22. package/dist/extensions.d.ts +1 -1
  23. package/dist/extensions.js +1 -1
  24. package/dist/headless.d.ts +1 -1
  25. package/dist/headless.js +3 -3
  26. package/dist/{index-CNyYEOy0.d.ts → index-BFNt9GAs.d.ts} +59 -7
  27. package/dist/index-BFNt9GAs.d.ts.map +1 -0
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +9 -9
  30. package/dist/{login-Bp_tRj_e.js → login-B5nMPF8w.js} +3 -3
  31. package/dist/{login-Bp_tRj_e.js.map → login-B5nMPF8w.js.map} +1 -1
  32. package/dist/{mcp-CkHUripi.js → mcp-BCaN_Gyg.js} +140 -29
  33. package/dist/mcp-BCaN_Gyg.js.map +1 -0
  34. package/dist/mcp.d.ts +1 -1
  35. package/dist/mcp.js +1 -1
  36. package/dist/{messages-Ce4yRjd3.js → messages-BDpXLFoe.js} +2 -2
  37. package/dist/{messages-Ce4yRjd3.js.map → messages-BDpXLFoe.js.map} +1 -1
  38. package/dist/{openai-compat-TA7aihJ-.js → openai-compat-J_JZ7qsw.js} +7 -1
  39. package/dist/openai-compat-J_JZ7qsw.js.map +1 -0
  40. package/dist/output/stream-json.d.ts +1 -1
  41. package/dist/output/terminal.d.ts +1 -1
  42. package/dist/presets.d.ts +1 -1
  43. package/dist/presets.js +1 -1
  44. package/dist/providers/anthropic.d.ts +1 -1
  45. package/dist/providers/anthropic.js +1 -1
  46. package/dist/providers/arcee.d.ts +1 -1
  47. package/dist/providers/arcee.js +1 -1
  48. package/dist/providers/baseten.d.ts +1 -1
  49. package/dist/providers/baseten.js +1 -1
  50. package/dist/providers/cerebras.d.ts +1 -1
  51. package/dist/providers/cerebras.js +1 -1
  52. package/dist/providers/local.d.ts +1 -1
  53. package/dist/providers/local.js +1 -1
  54. package/dist/providers/openai-compat.d.ts +1 -1
  55. package/dist/providers/openai-compat.js +1 -1
  56. package/dist/providers/openai.d.ts +1 -1
  57. package/dist/providers/openai.js +79 -34
  58. package/dist/providers/openai.js.map +1 -1
  59. package/dist/providers/openrouter.d.ts +1 -1
  60. package/dist/providers/openrouter.js +1 -1
  61. package/dist/providers/xai.d.ts +1 -1
  62. package/dist/providers/xai.js +1 -1
  63. package/dist/{providers-Dln69sQ_.js → providers-CclOzGxc.js} +3 -3
  64. package/dist/{providers-Dln69sQ_.js.map → providers-CclOzGxc.js.map} +1 -1
  65. package/dist/providers.d.ts +1 -1
  66. package/dist/providers.js +4 -4
  67. package/dist/restate.d.ts +1 -1
  68. package/dist/session/sqlite.d.ts +1 -1
  69. package/dist/{session-D7JSEMME.js → session-CIXE-Bzp.js} +2 -2
  70. package/dist/{session-D7JSEMME.js.map → session-CIXE-Bzp.js.map} +1 -1
  71. package/dist/session.d.ts +1 -1
  72. package/dist/session.js +2 -2
  73. package/dist/{skills-BlmY7QhV.js → skills-CDpejYOf.js} +168 -44
  74. package/dist/skills-CDpejYOf.js.map +1 -0
  75. package/dist/skills.d.ts +2 -2
  76. package/dist/skills.js +1 -1
  77. package/dist/{tool-formatters-B7oWiy5m.d.ts → tool-formatters-B_zQsYfa.d.ts} +2 -2
  78. package/dist/{tool-formatters-B7oWiy5m.d.ts.map → tool-formatters-B_zQsYfa.d.ts.map} +1 -1
  79. package/dist/tools/fetch-url.d.ts +1 -1
  80. package/dist/tools/web-search.d.ts +1 -1
  81. package/dist/tools.d.ts +1 -1
  82. package/dist/tools.js +1 -1
  83. package/dist/{transcript-anchors-cc4gsU-j.js → transcript-anchors-BUigMBQt.js} +227 -11
  84. package/dist/transcript-anchors-BUigMBQt.js.map +1 -0
  85. package/dist/{transcript-anchors-BUZ915pM.d.ts → transcript-anchors-C1Zqb8uS.d.ts} +49 -3
  86. package/dist/transcript-anchors-C1Zqb8uS.d.ts.map +1 -0
  87. package/dist/tui.d.ts +12 -7
  88. package/dist/tui.d.ts.map +1 -1
  89. package/dist/tui.js +391 -70
  90. package/dist/tui.js.map +1 -1
  91. package/dist/{turn-operations-2Ou_DkbC.d.ts → turn-operations-DVA52KMG.d.ts} +3 -3
  92. package/dist/{turn-operations-2Ou_DkbC.d.ts.map → turn-operations-DVA52KMG.d.ts.map} +1 -1
  93. package/dist/types.d.ts +1 -1
  94. package/dist/{xai-kGdhWmds.js → xai-D-wALLuZ.js} +2 -2
  95. package/dist/{xai-kGdhWmds.js.map → xai-D-wALLuZ.js.map} +1 -1
  96. package/package.json +2 -2
  97. package/dist/auth-Ys_7TmRj.js.map +0 -1
  98. package/dist/index-CNyYEOy0.d.ts.map +0 -1
  99. package/dist/mcp-CkHUripi.js.map +0 -1
  100. package/dist/openai-compat-TA7aihJ-.js.map +0 -1
  101. package/dist/skills-BlmY7QhV.js.map +0 -1
  102. package/dist/transcript-anchors-BUZ915pM.d.ts.map +0 -1
  103. package/dist/transcript-anchors-cc4gsU-j.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-cc4gsU-j.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-D11SxCvA.js";
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";
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";
@@ -7,16 +7,16 @@ import { l as errorMessage } from "./errors-DJUxZg9b.js";
7
7
  import { M as findGitRoot, j as projectUserPaths } from "./resolve-HtxmBWs9.js";
8
8
  import { a as createRingBufferSink, i as createLoggingHooks, l as logFileTimestamp, n as createFileSink, o as fanoutSink, r as createLogger, s as formatLogLine, t as consoleSink } from "./logger-DBX9uYOw.js";
9
9
  import { i as sniffImageMediaType } from "./media-sniff-Bn76JxAu.js";
10
- import { r as formatTokenUsage, t as effectiveInputFromTurn } from "./stats-DAKBEKjc.js";
10
+ import { n as flattenTurns, r as formatTokenUsage, t as effectiveInputFromTurn } from "./stats-DAKBEKjc.js";
11
11
  import { replaceDynamicSection } from "./prompt.js";
12
- import { a as getExtensionSessionState, i as demoteStaleRunningStatus, o as loadSession, s as setExtensionSessionState, t as createSession } from "./session-D7JSEMME.js";
12
+ import { a as getExtensionSessionState, i as demoteStaleRunningStatus, o as loadSession, s as setExtensionSessionState, t as createSession } from "./session-CIXE-Bzp.js";
13
13
  import { o as withTimeout } from "./timeout-BDetbuN6.js";
14
- import { n as connectMcpServers, u as McpOAuthProvider } from "./mcp-CkHUripi.js";
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-BlmY7QhV.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-Bp_tRj_e.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-Ys_7TmRj.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";
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";
@@ -1971,6 +1971,23 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false }) {
1971
1971
  scrollbox.scrollBy(direction, key.shift ? "content" : "viewport");
1972
1972
  }, [modal]));
1973
1973
  const anchors = useMemo(() => computeTurnAnchors(items), [items]);
1974
+ const liveByItem = useMemo(() => {
1975
+ const map = /* @__PURE__ */ new Map();
1976
+ const open = openSpawns(events);
1977
+ for (let i = items.length - 1; i >= 0 && open.size > 0; i--) {
1978
+ const item = items[i];
1979
+ 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
+ here.push({
1982
+ id,
1983
+ activity: spawnActivity(childEvents)
1984
+ });
1985
+ open.delete(id);
1986
+ }
1987
+ if (here.length > 0) map.set(i, here.reverse());
1988
+ }
1989
+ return map;
1990
+ }, [items, events]);
1974
1991
  useEffect(() => {
1975
1992
  if (!selectedTurnId) return;
1976
1993
  const scrollbox = scrollboxRef.current;
@@ -2011,20 +2028,29 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false }) {
2011
2028
  }
2012
2029
  },
2013
2030
  children: [items.map((item, i) => {
2014
- if (item.kind === "event") return /* @__PURE__ */ jsx$1(EventLine, {
2015
- event: item.event,
2016
- previous: item.previous,
2017
- selected: isTurnHighlighted(item.event, selectedTurnId, ownership),
2018
- anchorId: anchors.ids[i][0],
2019
- settleCodeEpoch: codeSettle.current.targets.has(item.event) ? codeSettle.current.epoch : 0
2020
- }, i);
2031
+ if (item.kind === "event") {
2032
+ const live = liveByItem.get(i);
2033
+ const line = /* @__PURE__ */ jsx$1(EventLine, {
2034
+ event: item.event,
2035
+ previous: item.previous,
2036
+ selected: isTurnHighlighted(item.event, selectedTurnId, ownership),
2037
+ 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);
2045
+ }
2021
2046
  return /* @__PURE__ */ jsx$1(SubagentBlock, {
2022
2047
  events: item.events,
2023
2048
  previous: item.previous,
2024
2049
  selectedTurnId,
2025
2050
  anchorIds: anchors.ids[i],
2026
2051
  codeSettleTargets: codeSettle.current.targets,
2027
- codeSettleEpoch: codeSettle.current.epoch
2052
+ codeSettleEpoch: codeSettle.current.epoch,
2053
+ live: liveByItem.get(i)
2028
2054
  }, i);
2029
2055
  }), showThrobber && /* @__PURE__ */ jsx$1("box", {
2030
2056
  style: { marginTop: items.length > 0 ? 1 : 0 },
@@ -2038,14 +2064,56 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false }) {
2038
2064
  });
2039
2065
  }
2040
2066
  /**
2041
- * Walk the visible-event list once and group consecutive child events
2042
- * (`depth > 0`) into runs so we can wrap each run in a single bordered
2043
- * subagent box.
2044
- *
2045
- * When `hideSubagentOutput` is on, `isVisible` already filters most child
2046
- * events out; the surviving `spawn-start` / `spawn-end` markers render as
2047
- * plain entries (no boxing) there's nothing meaningful to box.
2067
+ * Children with a `spawn-start` but no terminal marker yet, mapped to the
2068
+ * events they've produced since. Computed against the FULL event list a
2069
+ * parent-depth row (e.g. a background-task banner) can split one child's
2070
+ * 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.
2075
+ */
2076
+ function openSpawns(events) {
2077
+ const open = /* @__PURE__ */ new Map();
2078
+ for (const event of events) {
2079
+ if (!event.childId || (event.depth ?? 0) === 0) continue;
2080
+ if (event.kind === "spawn-start") {
2081
+ open.set(event.childId, []);
2082
+ continue;
2083
+ }
2084
+ if (event.kind === "spawn-end" || event.kind === "error") {
2085
+ open.delete(event.childId);
2086
+ continue;
2087
+ }
2088
+ open.get(event.childId)?.push(event);
2089
+ }
2090
+ return open;
2091
+ }
2092
+ /**
2093
+ * One-word-ish description of what a running child is doing right now,
2094
+ * derived from its trailing events: `text` while prose streams, `thinking`
2095
+ * during reasoning, the tool name for a single in-flight call, and
2096
+ * `tool call ×N` over an uninterrupted burst of calls.
2048
2097
  */
2098
+ function spawnActivity(events) {
2099
+ const last = events[events.length - 1];
2100
+ if (!last) return "starting";
2101
+ switch (last.kind) {
2102
+ case "markdown": return "text";
2103
+ case "thinking": return "thinking";
2104
+ case "tool":
2105
+ case "tool-result": {
2106
+ let calls = 0;
2107
+ for (let i = events.length - 1; i >= 0; i--) {
2108
+ const kind = events[i].kind;
2109
+ if (kind === "tool") calls += 1;
2110
+ else if (kind !== "tool-result") break;
2111
+ }
2112
+ return calls > 1 ? `tool call ×${calls}` : last.tool ?? "tool call";
2113
+ }
2114
+ default: return "working";
2115
+ }
2116
+ }
2049
2117
  function partitionTranscript(events, settings) {
2050
2118
  const visible = events.filter((e) => isVisible(e, settings));
2051
2119
  if (visible.length === 0) return [];
@@ -2093,7 +2161,7 @@ function partitionTranscript(events, settings) {
2093
2161
  * indented twice. Grandchildren (depth ≥ 2) still indent further, so
2094
2162
  * nested subagents remain visually distinct.
2095
2163
  */
2096
- function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds, codeSettleTargets, codeSettleEpoch = 0 }) {
2164
+ function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds, codeSettleTargets, codeSettleEpoch = 0, live }) {
2097
2165
  const COLOR = useColors();
2098
2166
  const childIds = useMemo(() => {
2099
2167
  const set = /* @__PURE__ */ new Set();
@@ -2103,7 +2171,7 @@ function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds, cod
2103
2171
  const title = childIds.length === 0 ? " subagent " : childIds.length === 1 ? ` ${childIds[0]} ` : ` subagents · ${childIds.join(", ")} `;
2104
2172
  const marginTop = previous ? 1 : 0;
2105
2173
  const hideChildLabel = childIds.length === 1;
2106
- return /* @__PURE__ */ jsx$1("box", {
2174
+ return /* @__PURE__ */ jsxs("box", {
2107
2175
  title,
2108
2176
  style: {
2109
2177
  border: true,
@@ -2117,7 +2185,7 @@ function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds, cod
2117
2185
  flexShrink: 0,
2118
2186
  alignSelf: "stretch"
2119
2187
  },
2120
- children: events.map((evt, i) => /* @__PURE__ */ jsx$1(EventLine, {
2188
+ children: [events.map((evt, i) => /* @__PURE__ */ jsx$1(EventLine, {
2121
2189
  event: evt,
2122
2190
  previous: events[i - 1],
2123
2191
  depthOffset: 1,
@@ -2125,7 +2193,31 @@ function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds, cod
2125
2193
  anchorId: anchorIds?.[i],
2126
2194
  hideChildLabel,
2127
2195
  settleCodeEpoch: codeSettleTargets?.has(evt) ? codeSettleEpoch : 0
2128
- }, i))
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))]
2203
+ });
2204
+ }
2205
+ /** Spinner + current-activity line for a still-running subagent. */
2206
+ function LiveSpawnRow({ spawn, showLabel }) {
2207
+ const COLOR = useColors();
2208
+ return /* @__PURE__ */ jsxs("text", {
2209
+ fg: COLOR.dim,
2210
+ 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", {
2216
+ fg: COLOR.mute,
2217
+ children: " ·"
2218
+ })] }),
2219
+ ` ${spawn.activity}`
2220
+ ]
2129
2221
  });
2130
2222
  }
2131
2223
  function EmptyState() {
@@ -4568,11 +4660,14 @@ function CwdPickerModal({ currentCwd, onPick }) {
4568
4660
  const FILES_REFRESH_THROTTLE_MS = 3e3;
4569
4661
  const SKILLS_REFRESH_THROTTLE_MS = 3e4;
4570
4662
  const MCP_TOOLS_CACHE_POLL_MS = 4e3;
4663
+ const MCPS_CONFIG_POLL_MS = 3e3;
4571
4664
  function debugLog$1(...args) {
4572
4665
  if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/tui] ${args.map(errorMessage).join(" ")}\n`);
4573
4666
  }
4574
4667
  function DiscoveryShell({ children }) {
4575
4668
  const config = useConfig();
4669
+ const { settings } = useSettings();
4670
+ const foreignAgents = settings.importForeignConfigs === true;
4576
4671
  const dispatchAuth = useMcpAuthDispatch();
4577
4672
  const dispatchAuthRef = useRef(dispatchAuth);
4578
4673
  dispatchAuthRef.current = dispatchAuth;
@@ -4586,6 +4681,8 @@ function DiscoveryShell({ children }) {
4586
4681
  const [mcpToolsByServer, setMcpToolsByServer] = useState(() => readToolsByServer(dataDir));
4587
4682
  const filesSlotRef = useRef(null);
4588
4683
  const skillsSlotRef = useRef(null);
4684
+ /** Last-published MCP discovery result — see the value-compare in `refreshMcps`. */
4685
+ const mcpsFingerprintRef = useRef(null);
4589
4686
  useEffect(() => {
4590
4687
  filesSlotRef.current?.abort();
4591
4688
  skillsSlotRef.current?.abort();
@@ -4608,7 +4705,8 @@ function DiscoveryShell({ children }) {
4608
4705
  throttleMs: SKILLS_REFRESH_THROTTLE_MS,
4609
4706
  walk: () => discoverProjectSkills({
4610
4707
  cwd: projectDir,
4611
- prefix: config.prefix
4708
+ prefix: config.prefix,
4709
+ foreignAgents
4612
4710
  }),
4613
4711
  onLoad: (items) => {
4614
4712
  if (skillsSlotRef.current === skillsSlot) setSkillsCatalog(items);
@@ -4623,7 +4721,12 @@ function DiscoveryShell({ children }) {
4623
4721
  try {
4624
4722
  const { servers, errors } = discoverProjectMcps({
4625
4723
  cwd: projectDir,
4626
- prefix: config.prefix
4724
+ prefix: config.prefix,
4725
+ foreignAgents
4726
+ });
4727
+ mcpsFingerprintRef.current = JSON.stringify({
4728
+ servers,
4729
+ errors
4627
4730
  });
4628
4731
  setMcpsCatalog(servers);
4629
4732
  setMcpsErrors(errors);
@@ -4650,7 +4753,8 @@ function DiscoveryShell({ children }) {
4650
4753
  }, [
4651
4754
  projectDir,
4652
4755
  config.prefix,
4653
- mcpCredentialStore
4756
+ mcpCredentialStore,
4757
+ foreignAgents
4654
4758
  ]);
4655
4759
  const ensureFiles = useCallback(() => filesSlotRef.current?.ensure() ?? Promise.resolve([]), []);
4656
4760
  const ensureSkills = useCallback(() => skillsSlotRef.current?.ensure() ?? Promise.resolve([]), []);
@@ -4660,8 +4764,15 @@ function DiscoveryShell({ children }) {
4660
4764
  try {
4661
4765
  const { servers, errors } = discoverProjectMcps({
4662
4766
  cwd: projectDir,
4663
- prefix: config.prefix
4767
+ prefix: config.prefix,
4768
+ foreignAgents
4664
4769
  });
4770
+ const fingerprint = JSON.stringify({
4771
+ servers,
4772
+ errors
4773
+ });
4774
+ if (fingerprint === mcpsFingerprintRef.current) return Promise.resolve();
4775
+ mcpsFingerprintRef.current = fingerprint;
4665
4776
  setMcpsCatalog(servers);
4666
4777
  setMcpsErrors(errors);
4667
4778
  for (const entry of servers) {
@@ -4683,7 +4794,27 @@ function DiscoveryShell({ children }) {
4683
4794
  }, [
4684
4795
  projectDir,
4685
4796
  config.prefix,
4686
- mcpCredentialStore
4797
+ mcpCredentialStore,
4798
+ foreignAgents
4799
+ ]);
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
4687
4818
  ]);
4688
4819
  useEffect(() => {
4689
4820
  let lastSignature = cacheFileSignature(dataDir);
@@ -4742,6 +4873,21 @@ function cacheFileSignature(dataDir) {
4742
4873
  const stat = statSync(mcpToolsCachePath(dataDir), { throwIfNoEntry: false });
4743
4874
  return stat ? `${stat.mtimeMs}:${stat.size}` : null;
4744
4875
  }
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
+ }
4745
4891
  function readToolsByServer(dataDir) {
4746
4892
  const cache = loadMcpToolsCache({ dataDir });
4747
4893
  const out = {};
@@ -4963,7 +5109,7 @@ const BASE_LEVELS$1 = [
4963
5109
  },
4964
5110
  {
4965
5111
  id: "minimal",
4966
- description: "tiny reasoning budget (gpt-5 family)"
5112
+ description: "tiny reasoning budget"
4967
5113
  },
4968
5114
  {
4969
5115
  id: "low",
@@ -4979,16 +5125,16 @@ const BASE_LEVELS$1 = [
4979
5125
  },
4980
5126
  {
4981
5127
  id: "xhigh",
4982
- description: "very deep reasoning (Anthropic)"
5128
+ description: "very deep reasoning"
4983
5129
  },
4984
5130
  {
4985
5131
  id: "max",
4986
- description: "maximum reasoning effort (Anthropic)"
5132
+ description: "maximum reasoning effort"
4987
5133
  }
4988
5134
  ];
4989
5135
  const ADAPTIVE_LEVEL$1 = {
4990
5136
  id: "adaptive",
4991
- description: "model decides per-turn (Anthropic)"
5137
+ description: "model decides per-turn"
4992
5138
  };
4993
5139
  function ModelOptionsPickerModal({ supportsReasoning, supportsAdaptive, currentEffort, options, enabled, onPickEffort, onToggleOption }) {
4994
5140
  const COLOR = useColors();
@@ -11452,13 +11598,17 @@ function filterLogRecords(records, minLevel) {
11452
11598
  }
11453
11599
  //#endregion
11454
11600
  //#region src/tui/settings-form-dialog.tsx
11455
- function FormDialog({ title, error, hint, children }) {
11601
+ /** Shared dialog width pickers use it to size their own ellipsed rows. */
11602
+ function formDialogWidth(termWidth) {
11603
+ return Math.min(96, Math.max(48, termWidth - 8));
11604
+ }
11605
+ function FormDialog({ title, error, hint, contentRows, children }) {
11456
11606
  const COLOR = useColors();
11457
11607
  const SURFACE = useSurfaces();
11458
11608
  const { width: termWidth, height: termHeight } = useTerminalDimensions();
11459
- const width = Math.min(96, Math.max(48, termWidth - 8));
11609
+ const width = formDialogWidth(termWidth);
11460
11610
  const left = Math.max(0, Math.floor((termWidth - width) / 2));
11461
- const top = Math.max(1, Math.floor(termHeight / 2) - 7);
11611
+ const top = contentRows !== void 0 ? Math.max(1, Math.floor((termHeight - (contentRows + 4)) / 2)) : Math.max(1, Math.floor(termHeight / 2) - 7);
11462
11612
  return /* @__PURE__ */ jsxs("box", {
11463
11613
  title: ` ${title} `,
11464
11614
  style: {
@@ -11747,13 +11897,13 @@ function SkillInstallDialog({ active, onSubmit, onCancel }) {
11747
11897
  focused: row === "source",
11748
11898
  label: "source",
11749
11899
  inputRef: sourceRef,
11750
- placeholder: "owner/repo · skills.sh/owner/repo/skill · pkg@version"
11900
+ placeholder: "owner/repo · skills.sh URL · npx skills add … · pkg@version"
11751
11901
  }),
11752
11902
  /* @__PURE__ */ jsx$1(InputRow$1, {
11753
11903
  focused: row === "skill",
11754
11904
  label: "skill",
11755
11905
  inputRef: skillRef,
11756
- placeholder: "pick one from multi-skill repos (optional)"
11906
+ placeholder: "pick one from multi-skill repos (optional — empty offers import-all)"
11757
11907
  }),
11758
11908
  /* @__PURE__ */ jsx$1(CycleRow, {
11759
11909
  focused: row === "scope",
@@ -11765,6 +11915,130 @@ function SkillInstallDialog({ active, onSubmit, onCancel }) {
11765
11915
  ]
11766
11916
  });
11767
11917
  }
11918
+ /** Rows shown at once in the picker; longer lists scroll around the cursor. */
11919
+ const SKILL_PICKER_MAX_VISIBLE = 10;
11920
+ /**
11921
+ * Shown when a skill install hit a multi-skill source without a selector
11922
+ * (`multiple-candidates`): a checkbox picker over everything the repo
11923
+ * contains, all pre-selected. `space` toggles the row under the cursor,
11924
+ * `a` flips all/none, `enter` imports the checked subset, `esc` cancels
11925
+ * back to the idle Skills tab.
11926
+ */
11927
+ function SkillImportDialog({ active, source, items, onConfirm, onCancel }) {
11928
+ const COLOR = useColors();
11929
+ const { width: termWidth } = useTerminalDimensions();
11930
+ const [cursor, setCursor] = useState(0);
11931
+ const [checked, setChecked] = useState(() => new Set(items.map((_, i) => i)));
11932
+ const [error, setError] = useState(null);
11933
+ const count = items.length;
11934
+ useKeyboard((key) => {
11935
+ if (!active) return;
11936
+ if (key.name === "escape") {
11937
+ onCancel();
11938
+ return;
11939
+ }
11940
+ if (key.name === "up" || key.name === "tab" && key.shift) {
11941
+ setCursor((c) => (c + count - 1) % count);
11942
+ return;
11943
+ }
11944
+ if (key.name === "down" || key.name === "tab") {
11945
+ setCursor((c) => (c + 1) % count);
11946
+ return;
11947
+ }
11948
+ if (key.name === "space") {
11949
+ setError(null);
11950
+ setChecked((prev) => {
11951
+ const next = new Set(prev);
11952
+ if (next.has(cursor)) next.delete(cursor);
11953
+ else next.add(cursor);
11954
+ return next;
11955
+ });
11956
+ return;
11957
+ }
11958
+ if (key.name === "a") {
11959
+ setError(null);
11960
+ setChecked((prev) => prev.size === count ? /* @__PURE__ */ new Set() : new Set(items.map((_, i) => i)));
11961
+ return;
11962
+ }
11963
+ if (key.name === "return") {
11964
+ const selected = items.filter((_, i) => checked.has(i)).map((item) => item.rel);
11965
+ if (selected.length === 0) {
11966
+ setError("nothing selected — space toggles, a selects all");
11967
+ return;
11968
+ }
11969
+ onConfirm(selected);
11970
+ }
11971
+ });
11972
+ const start = Math.max(0, Math.min(cursor - Math.floor(SKILL_PICKER_MAX_VISIBLE / 2), count - SKILL_PICKER_MAX_VISIBLE));
11973
+ const visible = items.slice(start, start + SKILL_PICKER_MAX_VISIBLE);
11974
+ const innerWidth = formDialogWidth(termWidth) - 6;
11975
+ const hasOverflowUp = start > 0;
11976
+ const hasOverflowDown = start + SKILL_PICKER_MAX_VISIBLE < count;
11977
+ return /* @__PURE__ */ jsxs(FormDialog, {
11978
+ title: "import skills",
11979
+ error,
11980
+ contentRows: 1 + visible.length + (hasOverflowUp ? 1 : 0) + (hasOverflowDown ? 1 : 0),
11981
+ hint: " ↑↓ move · space toggle · a all/none · enter import · esc cancel",
11982
+ children: [
11983
+ /* @__PURE__ */ jsxs("text", {
11984
+ fg: COLOR.mute,
11985
+ children: [
11986
+ " ",
11987
+ /* @__PURE__ */ jsx$1("span", {
11988
+ fg: COLOR.warn,
11989
+ children: source
11990
+ }),
11991
+ ` — ${checked.size}/${count} selected`
11992
+ ]
11993
+ }),
11994
+ hasOverflowUp && /* @__PURE__ */ jsx$1("text", {
11995
+ fg: COLOR.mute,
11996
+ children: ` ↑ ${start} more`
11997
+ }),
11998
+ visible.map((item, vi) => {
11999
+ const i = start + vi;
12000
+ const focusedRow = i === cursor;
12001
+ const isChecked = checked.has(i);
12002
+ const label = clipEnd(item.description ? `${item.rel} — ${item.description}` : item.rel, Math.max(8, innerWidth - 8), item.rel.length);
12003
+ return /* @__PURE__ */ jsxs("text", {
12004
+ fg: COLOR.mute,
12005
+ children: [
12006
+ ` ${focusedRow ? "❯" : " "} [`,
12007
+ /* @__PURE__ */ jsx$1("span", {
12008
+ fg: isChecked ? COLOR.accent : COLOR.mute,
12009
+ children: isChecked ? "✓" : " "
12010
+ }),
12011
+ "] ",
12012
+ /* @__PURE__ */ jsx$1("span", {
12013
+ fg: focusedRow ? COLOR.warn : isChecked ? COLOR.accent : COLOR.mute,
12014
+ children: label.name
12015
+ }),
12016
+ label.rest && /* @__PURE__ */ jsx$1("span", {
12017
+ fg: COLOR.mute,
12018
+ children: label.rest
12019
+ })
12020
+ ]
12021
+ }, item.rel);
12022
+ }),
12023
+ hasOverflowDown && /* @__PURE__ */ jsx$1("text", {
12024
+ fg: COLOR.mute,
12025
+ children: ` ↓ ${count - start - SKILL_PICKER_MAX_VISIBLE} more`
12026
+ })
12027
+ ]
12028
+ });
12029
+ }
12030
+ /**
12031
+ * Clip `text` to `max` columns with a trailing ellipsis, split into the
12032
+ * name segment (first `nameLen` chars — colored per row state) and the
12033
+ * dim remainder so the description stays one ellipsed line.
12034
+ */
12035
+ function clipEnd(text, max, nameLen) {
12036
+ const clipped = text.length > max ? `${text.slice(0, Math.max(1, max - 1))}…` : text;
12037
+ return {
12038
+ name: clipped.slice(0, Math.min(nameLen, clipped.length)),
12039
+ rest: clipped.slice(Math.min(nameLen, clipped.length))
12040
+ };
12041
+ }
11768
12042
  const MCP_TRANSPORTS = [
11769
12043
  "stdio",
11770
12044
  "streamable-http",
@@ -12372,6 +12646,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
12372
12646
  const [removeArmed, setRemoveArmed] = useState(null);
12373
12647
  const [extInstallOpen, setExtInstallOpen] = useState(false);
12374
12648
  const [skillInstallOpen, setSkillInstallOpen] = useState(false);
12649
+ const [skillImportAll, setSkillImportAll] = useState(null);
12375
12650
  const [skillOp, setSkillOp] = useState(null);
12376
12651
  const [mcpAdd, setMcpAdd] = useState(false);
12377
12652
  const [mcpOp, setMcpOp] = useState(null);
@@ -12381,6 +12656,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
12381
12656
  const configEditActive = activeTab === "extensions" && configEdit !== null;
12382
12657
  const extInstallActive = activeTab === "extensions" && extInstallOpen;
12383
12658
  const skillInstallActive = activeTab === "skills" && skillInstallOpen;
12659
+ const skillImportAllActive = activeTab === "skills" && skillImportAll !== null;
12384
12660
  const mcpAddActive = activeTab === "mcps" && mcpAdd;
12385
12661
  useEffect(() => {
12386
12662
  if (activeTab !== "extensions" && configEdit) setConfigEdit(null);
@@ -12391,14 +12667,18 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
12391
12667
  useEffect(() => {
12392
12668
  if (activeTab !== "skills" && skillInstallOpen) setSkillInstallOpen(false);
12393
12669
  }, [activeTab, skillInstallOpen]);
12670
+ useEffect(() => {
12671
+ if (activeTab !== "skills" && skillImportAll) setSkillImportAll(null);
12672
+ }, [activeTab, skillImportAll]);
12394
12673
  useEffect(() => {
12395
12674
  if (activeTab !== "mcps" && mcpAdd) setMcpAdd(false);
12396
12675
  }, [activeTab, mcpAdd]);
12397
12676
  useEffect(() => {
12398
- if (!extInstallOpen && !skillInstallOpen && !mcpAdd) inputRef.current?.focus();
12677
+ if (!extInstallOpen && !skillInstallOpen && !skillImportAll && !mcpAdd) inputRef.current?.focus();
12399
12678
  }, [
12400
12679
  extInstallOpen,
12401
12680
  skillInstallOpen,
12681
+ skillImportAll,
12402
12682
  mcpAdd
12403
12683
  ]);
12404
12684
  /** Run a skill install off the dialog's payload, streaming progress into the op line. */
@@ -12412,6 +12692,8 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
12412
12692
  actions.onInstallSkill({
12413
12693
  source: req.source,
12414
12694
  ...req.skill !== void 0 ? { skill: req.skill } : {},
12695
+ ...req.all !== void 0 ? { all: req.all } : {},
12696
+ ...req.skills !== void 0 ? { skills: req.skills } : {},
12415
12697
  scope: req.choice,
12416
12698
  onProgress: (message) => setSkillOp({
12417
12699
  kind: "busy",
@@ -12420,10 +12702,22 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
12420
12702
  }).then((message) => setSkillOp({
12421
12703
  kind: "notice",
12422
12704
  text: message
12423
- })).catch((err) => setSkillOp({
12424
- kind: "error",
12425
- text: errorMessage(err)
12426
- }));
12705
+ })).catch((err) => {
12706
+ if (err instanceof SkillInstallError && err.code === "multiple-candidates" && err.candidates && err.candidates.length > 0) {
12707
+ setSkillOp(null);
12708
+ const items = err.details && err.details.length === err.candidates.length ? err.details : err.candidates.map((rel) => ({ rel }));
12709
+ setSkillImportAll({
12710
+ source: req.source,
12711
+ scope: req.choice,
12712
+ items
12713
+ });
12714
+ return;
12715
+ }
12716
+ setSkillOp({
12717
+ kind: "error",
12718
+ text: errorMessage(err)
12719
+ });
12720
+ });
12427
12721
  }, [actions]);
12428
12722
  /** Add-MCP submit: persist through the host, then surface the outcome. */
12429
12723
  const runAddMcp = useCallback((result) => {
@@ -12788,7 +13082,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
12788
13082
  if (key.name === "escape" && configEdit?.kind !== "model") setConfigEdit(null);
12789
13083
  return;
12790
13084
  }
12791
- if (extInstallActive || skillInstallActive) return;
13085
+ if (extInstallActive || skillInstallActive || skillImportAllActive) return;
12792
13086
  if (mcpAddActive) return;
12793
13087
  if (key.name === "escape" && oauthPasteActive && focusedMcp) {
12794
13088
  actions?.onCancelLoginMcp?.(focusedMcp.config.name);
@@ -13033,7 +13327,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
13033
13327
  horizontalMargin: 0,
13034
13328
  verticalMargin: 0,
13035
13329
  ...version ? { bottomTitle: `zidane v${version}` } : {},
13036
- disableEscape: configEditActive || !!editingInputKey || extInstallActive || skillInstallActive || mcpAddActive,
13330
+ disableEscape: configEditActive || !!editingInputKey || extInstallActive || skillInstallActive || skillImportAllActive || mcpAddActive,
13037
13331
  children: [
13038
13332
  /* @__PURE__ */ jsx$1("box", {
13039
13333
  style: { flexShrink: 0 },
@@ -13054,7 +13348,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
13054
13348
  },
13055
13349
  children: /* @__PURE__ */ jsx$1("input", {
13056
13350
  ref: inputRef,
13057
- focused: !oauthPasteActive && !configEditActive && !editingInputKey && !extInstallActive && !skillInstallActive && !mcpAddActive,
13351
+ focused: !oauthPasteActive && !configEditActive && !editingInputKey && !extInstallActive && !skillInstallActive && !skillImportAllActive && !mcpAddActive,
13058
13352
  placeholder: searchPlaceholder(activeTab),
13059
13353
  onInput: handleQueryChange,
13060
13354
  onSubmit: () => {},
@@ -13285,6 +13579,25 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
13285
13579
  },
13286
13580
  onCancel: () => setSkillInstallOpen(false)
13287
13581
  }),
13582
+ skillImportAllActive && skillImportAll && /* @__PURE__ */ jsx$1(SkillImportDialog, {
13583
+ active: skillImportAllActive,
13584
+ source: skillImportAll.source,
13585
+ items: skillImportAll.items,
13586
+ onConfirm: (selected) => {
13587
+ const req = skillImportAll;
13588
+ setSkillImportAll(null);
13589
+ runSkillInstall(selected.length === req.items.length ? {
13590
+ source: req.source,
13591
+ all: true,
13592
+ choice: req.scope
13593
+ } : {
13594
+ source: req.source,
13595
+ skills: selected,
13596
+ choice: req.scope
13597
+ });
13598
+ },
13599
+ onCancel: () => setSkillImportAll(null)
13600
+ }),
13288
13601
  mcpAddActive && /* @__PURE__ */ jsx$1(McpAddDialog, {
13289
13602
  active: mcpAddActive,
13290
13603
  existingNames: mcpsCatalog.map((s) => s.config.name),
@@ -15936,6 +16249,8 @@ function AppShell() {
15936
16249
  skillsCatalogRef.current = skillsCatalog;
15937
16250
  const enabledSkillsRef = useRef(settings.enabledSkills);
15938
16251
  enabledSkillsRef.current = settings.enabledSkills;
16252
+ const importForeignConfigsRef = useRef(settings.importForeignConfigs);
16253
+ importForeignConfigsRef.current = settings.importForeignConfigs;
15939
16254
  const mcpsCatalogRef = useRef(mcpsCatalog);
15940
16255
  mcpsCatalogRef.current = mcpsCatalog;
15941
16256
  const enabledMcpsRef = useRef(settings.enabledMcps);
@@ -16793,7 +17108,8 @@ function AppShell() {
16793
17108
  const profile = pickedAgentRef.current;
16794
17109
  const skillsScan = defaultSkillScanPaths({
16795
17110
  cwd: projectDir,
16796
- prefix: config.prefix
17111
+ prefix: config.prefix,
17112
+ foreignAgents: importForeignConfigsRef.current === true
16797
17113
  });
16798
17114
  const liveExtensionRegistry = filterExtensionRegistry(extensionRegistry, enabledExtensionsRef.current);
16799
17115
  const extensionSkillNames = liveExtensionRegistry.skills.map((s) => s.name);
@@ -17295,7 +17611,9 @@ function AppShell() {
17295
17611
  setLastInputTokens(ctx.effectiveTokens);
17296
17612
  lastInputTokensRef.current = ctx.effectiveTokens;
17297
17613
  });
17614
+ const spawnStartedAt = /* @__PURE__ */ new Map();
17298
17615
  agent.hooks.hook("spawn:before", ({ id, task, depth, model }) => {
17616
+ spawnStartedAt.set(id, Date.now());
17299
17617
  const taskPreview = previewLine(task, 80);
17300
17618
  stream.appendImmediate({
17301
17619
  kind: "spawn-start",
@@ -17307,9 +17625,14 @@ function AppShell() {
17307
17625
  });
17308
17626
  agent.hooks.hook("spawn:complete", ({ id, depth, status, stats }) => {
17309
17627
  const tag = status === "aborted" ? "aborted" : status === "error" ? "error" : "done";
17628
+ const startedAt = spawnStartedAt.get(id);
17629
+ spawnStartedAt.delete(id);
17630
+ const elapsed = startedAt !== void 0 ? ` · ${formatDuration(Date.now() - startedAt)}` : "";
17631
+ const cost = flattenTurns(stats).reduce((sum, turn) => sum + (turn.cost ?? 0), 0);
17632
+ const segments = `${elapsed}${cost > 0 ? ` · $${cost.toFixed(cost < .01 ? 4 : 2)}` : ""}`;
17310
17633
  stream.appendImmediate({
17311
17634
  kind: "spawn-end",
17312
- text: `${tag} ${formatTokenUsage(stats)}`,
17635
+ text: segments ? `${tag}${segments} · ${formatTokenUsage(stats)}` : `${tag} ${formatTokenUsage(stats)}`,
17313
17636
  childId: id,
17314
17637
  depth: depth ?? 1
17315
17638
  });
@@ -17904,22 +18227,20 @@ function AppShell() {
17904
18227
  * catalog refresh makes the new skill togglable immediately.
17905
18228
  */
17906
18229
  const onInstallSkill = useCallback(async (req) => {
17907
- let result;
17908
- try {
17909
- result = await installSkillFromSpec({
17910
- source: req.source,
17911
- scope: req.scope,
17912
- cwd: cwdRef.current,
17913
- prefix: config.prefix,
17914
- ...req.skill !== void 0 ? { skill: req.skill } : {},
17915
- ...req.onProgress !== void 0 ? { onProgress: req.onProgress } : {}
17916
- });
17917
- } catch (err) {
17918
- if (err instanceof SkillInstallError && err.code === "multiple-candidates") throw new Error(`${err.message} — re-run as “${req.source} <name>”.`);
17919
- throw err;
17920
- }
18230
+ const result = await installSkillFromSpec({
18231
+ source: req.source,
18232
+ scope: req.scope,
18233
+ cwd: cwdRef.current,
18234
+ prefix: config.prefix,
18235
+ ...req.skill !== void 0 ? { skill: req.skill } : {},
18236
+ ...req.all !== void 0 ? { all: req.all } : {},
18237
+ ...req.skills !== void 0 ? { skills: req.skills } : {},
18238
+ ...req.onProgress !== void 0 ? { onProgress: req.onProgress } : {}
18239
+ });
17921
18240
  await onRefreshSkills();
17922
- return result.engine === "skills-cli" ? `installed ${result.installed.join(", ")} via the skills.sh CLI` : `installed ${result.installed.join(", ")} (${req.scope}, ${result.provenance ?? "native"})`;
18241
+ const skippedNote = result.skipped?.length ? ` skipped existing: ${result.skipped.join(", ")}` : "";
18242
+ const failedNote = result.failed?.length ? ` — ⚠ invalid: ${result.failed.join(", ")}` : "";
18243
+ return result.engine === "skills-cli" ? `installed ${result.installed.join(", ")} via the skills.sh CLI` : `installed ${result.installed.join(", ")} (${req.scope}, ${result.provenance ?? "native"})${skippedNote}${failedNote}`;
17923
18244
  }, [config.prefix, onRefreshSkills]);
17924
18245
  /**
17925
18246
  * Persist a new MCP server (Settings → MCPs → ctrl+g form). Upserts
@@ -20498,7 +20819,7 @@ const BASE_LEVELS = [
20498
20819
  },
20499
20820
  {
20500
20821
  id: "minimal",
20501
- description: "tiny reasoning budget (gpt-5 family)"
20822
+ description: "tiny reasoning budget"
20502
20823
  },
20503
20824
  {
20504
20825
  id: "low",
@@ -20514,16 +20835,16 @@ const BASE_LEVELS = [
20514
20835
  },
20515
20836
  {
20516
20837
  id: "xhigh",
20517
- description: "very deep reasoning (Anthropic)"
20838
+ description: "very deep reasoning"
20518
20839
  },
20519
20840
  {
20520
20841
  id: "max",
20521
- description: "maximum reasoning effort (Anthropic)"
20842
+ description: "maximum reasoning effort"
20522
20843
  }
20523
20844
  ];
20524
20845
  const ADAPTIVE_LEVEL = {
20525
20846
  id: "adaptive",
20526
- description: "model decides per-turn (Anthropic)"
20847
+ description: "model decides per-turn"
20527
20848
  };
20528
20849
  function EffortPickerModal({ current, supportsAdaptive, onPick }) {
20529
20850
  const COLOR = useColors();