zidane 6.2.23 → 6.2.26
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.
- package/dist/{acp-B7wH6LhE.js → acp-CNZqD1Fw.js} +5 -5
- package/dist/{acp-B7wH6LhE.js.map → acp-CNZqD1Fw.js.map} +1 -1
- package/dist/acp-cli.js +4 -4
- package/dist/acp.d.ts +1 -1
- package/dist/acp.js +1 -1
- package/dist/{agent-BSIMsEtD.js → agent--VPMZ0nT.js} +324 -39
- package/dist/agent--VPMZ0nT.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +2 -2
- package/dist/{auth-CpdQebUy.js → auth-DIT_DMwa.js} +2 -2
- package/dist/{auth-CpdQebUy.js.map → auth-DIT_DMwa.js.map} +1 -1
- package/dist/chat/pure.d.ts +3 -3
- package/dist/chat/pure.js +1 -1
- package/dist/chat.d.ts +4 -4
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +6 -6
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/daytona.d.ts.map +1 -1
- package/dist/contexts/daytona.js +9 -2
- package/dist/contexts/daytona.js.map +1 -1
- package/dist/contexts/docker.js +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/contexts/e2b.d.ts.map +1 -1
- package/dist/contexts/e2b.js +3 -4
- package/dist/contexts/e2b.js.map +1 -1
- package/dist/{contexts-A4ep-iJs.js → contexts-0rmrBhTK.js} +8 -5
- package/dist/contexts-0rmrBhTK.js.map +1 -0
- package/dist/contexts.js +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +2 -2
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/{output-cap-kBUHBlnq.js → glob-DluQFSw1.js} +2 -50
- package/dist/glob-DluQFSw1.js.map +1 -0
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +4 -4
- package/dist/history-search-worker.js +6 -1
- package/dist/history-search-worker.js.map +1 -1
- package/dist/{index-Bv9qhj4n.d.ts → index-AVZ6pYpi.d.ts} +254 -97
- package/dist/index-AVZ6pYpi.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -9
- package/dist/index.js.map +1 -1
- package/dist/{inline-autocomplete-BAwBcZtD.js → inline-autocomplete-CbcdZpfC.js} +2 -1
- package/dist/inline-autocomplete-CbcdZpfC.js.map +1 -0
- package/dist/{login-BkZ_d5sT.js → login-afiadwf0.js} +35 -19
- package/dist/login-afiadwf0.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/output-cap-DM1HrgIp.js +100 -0
- package/dist/output-cap-DM1HrgIp.js.map +1 -0
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/{resolve-x5mlFtLX.js → resolve-BPTA1RpX.js} +23 -3
- package/dist/resolve-BPTA1RpX.js.map +1 -0
- package/dist/restate.d.ts +1 -1
- package/dist/{run-summary-nD3IQ4ZQ.js → run-summary-BU_NgwUT.js} +17 -1
- package/dist/run-summary-BU_NgwUT.js.map +1 -0
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-Dbvz1ZUE.js → session-jLsc_kMH.js} +22 -3
- package/dist/session-jLsc_kMH.js.map +1 -0
- package/dist/session.d.ts +2 -2
- package/dist/session.js +2 -2
- package/dist/{skills-C1vGKbqv.js → skills-C7eIjWYm.js} +2 -2
- package/dist/{skills-C1vGKbqv.js.map → skills-C7eIjWYm.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +2 -2
- package/dist/{tool-formatters-D9P6Znip.d.ts → tool-formatters-Dual3Hdl.d.ts} +2 -2
- package/dist/{tool-formatters-D9P6Znip.d.ts.map → tool-formatters-Dual3Hdl.d.ts.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-Ci5888xS.d.ts → transcript-anchors-CG85bieG.d.ts} +2 -2
- package/dist/transcript-anchors-CG85bieG.d.ts.map +1 -0
- package/dist/{transcript-anchors-CqzIr74w.js → transcript-anchors-CnmxZ8QR.js} +96 -16
- package/dist/transcript-anchors-CnmxZ8QR.js.map +1 -0
- package/dist/tui.d.ts +55 -8
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +1845 -1145
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CokV32wf.js → turn-operations-4tnvKwfJ.js} +82 -14
- package/dist/turn-operations-4tnvKwfJ.js.map +1 -0
- package/dist/{turn-operations-C3y6A82G.d.ts → turn-operations-BUYaSCL3.d.ts} +3 -3
- package/dist/{turn-operations-C3y6A82G.d.ts.map → turn-operations-BUYaSCL3.d.ts.map} +1 -1
- package/dist/types-BIarq1qE.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +2 -1
- package/dist/agent-BSIMsEtD.js.map +0 -1
- package/dist/contexts-A4ep-iJs.js.map +0 -1
- package/dist/index-Bv9qhj4n.d.ts.map +0 -1
- package/dist/inline-autocomplete-BAwBcZtD.js.map +0 -1
- package/dist/login-BkZ_d5sT.js.map +0 -1
- package/dist/output-cap-kBUHBlnq.js.map +0 -1
- package/dist/resolve-x5mlFtLX.js.map +0 -1
- package/dist/run-summary-nD3IQ4ZQ.js.map +0 -1
- package/dist/session-Dbvz1ZUE.js.map +0 -1
- package/dist/transcript-anchors-Ci5888xS.d.ts.map +0 -1
- package/dist/transcript-anchors-CqzIr74w.js.map +0 -1
- package/dist/turn-operations-CokV32wf.js.map +0 -1
package/dist/tui.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { $ as McpAuthProvider, $t as filterChainFallbacks, A as runOAuthLogin, At as useSettings, B as mcpToolsCachePath, Ct as DEFAULT_SETTINGS, D as formatPathForCwd, Dn as accentColor, Dt as SETTINGS_TOGGLES, Et as SETTINGS_INPUTS, F as parseJsonTolerant, G as useMcpToolToggleMap, Gt as useDiscoveryOptional, Ht as createDiscoverySlot, I as parseMcpsFile, J as indexOfServerRow, Jt as resolveConfig, Kt as ConfigProvider, L as parseClaudeState, M as buildMcpServers, N as defaultMcpsConfigPaths, Nn as TODO_STATUS_GLYPHS, Nt as resolveChipColor, O as fetchOAuthRedirect, Ot as SettingsProvider, P as discoverProjectMcps, Pt as resolveTheme, Qt as chainsEqual, Sr as usageByModel, St as useEnabledToggleSet, T as suggestSafelistEntries, Tt as SETTINGS_CHOICES, U as subscribeMcpToolsCache, Un as useActiveTodos, Ut as DiscoveryProvider, V as refreshMcpToolsCatalog, Wt as useDiscovery, X as createFileMcpCredentialStore, Xt as buildRunModel, Y as parentServerName, Yt as resolveStoragePaths, Zt as chainPositionOf, _ as useSafeModeQueue, _r as sumRunCosts, _t as hintsLength, a as useSurfaces, an as tryOpenBrowser, at as InteractionsProvider, b as getSafelist, br as toolResultText, c as useStreamBuffer, cn as buildUpdateHint, cr as deriveSessionTitle, ct as createInteractionTools, d as discoverProjectSkills, dr as listSessionMeta, dt as pendingInteractionsFromTurns, en as providerKeySetChanged, er as buildBuildSystem, et as useMcpAuthDispatch, fr as loadState, g as useSafeModeActions, gr as stripSpawnTokensLine, gt as clipHintsToWidth, h as SafeModeProvider, hr as serverToolResultSummary, ht as EMPTY_HINTS, i as useSelectStyle, in as useCompletion, ir as createChatTurnsReadTool, it as ASK_USER_TOOL, j as supportsOAuth, k as oauthUsesManualCodePaste, kt as clampFps, l as buildSkillsConfig, ln as useUpdateCheck, lr as eventsFromTurns, m as writeSessionExport, mt as useInteractionsQueue, n as ThemeProvider, nr as envSection, nt as getMcpAuthStatus, or as compactSummaryEvent, ot as PRESENT_PLAN_TOOL, pr as marginTopFor, pt as useInteractionsActions, q as buildVisibleMcpRows, qt as useConfig, r as useColors, rn as toggleChainEntry, rr as chatReferenceTokensForPrompt, s as useTheme, sn as bootTick, st as buildResumedToolResultsTurn, t as computeTurnAnchors, tn as restoreChainFallbacks, tr as buildPlanSystem, tt as useMcpAuthState, u as defaultSkillScanPaths, ur as lastContextSizeFromTurns, ut as makeRequestInteraction, vn as chatAutoCompactBehavior, vt as truncateTrailing, wt as SETTINGS_CATEGORIES, x as isOnSafelist, xr as updateToolEventOutcomes, xt as listProjectFiles, y as addToSafelist, yn as discoverAgentsMd, yr as toolCallPreview, yt as buildHints, z as loadMcpToolsCache } from "./transcript-anchors-
|
|
2
|
-
import {
|
|
1
|
+
import { $ as McpAuthProvider, $t as filterChainFallbacks, A as runOAuthLogin, At as useSettings, B as mcpToolsCachePath, Bn as pruneTodosByRun, Ct as DEFAULT_SETTINGS, D as formatPathForCwd, Dn as accentColor, Dt as SETTINGS_TOGGLES, Et as SETTINGS_INPUTS, F as parseJsonTolerant, G as useMcpToolToggleMap, Gt as useDiscoveryOptional, Ht as createDiscoverySlot, I as parseMcpsFile, J as indexOfServerRow, Jt as resolveConfig, Kt as ConfigProvider, L as parseClaudeState, M as buildMcpServers, N as defaultMcpsConfigPaths, Nn as TODO_STATUS_GLYPHS, Nt as resolveChipColor, O as fetchOAuthRedirect, Ot as SettingsProvider, P as discoverProjectMcps, Pt as resolveTheme, Qt as chainsEqual, Sr as usageByModel, St as useEnabledToggleSet, T as suggestSafelistEntries, Tt as SETTINGS_CHOICES, U as subscribeMcpToolsCache, Un as useActiveTodos, Ut as DiscoveryProvider, V as refreshMcpToolsCatalog, Wt as useDiscovery, X as createFileMcpCredentialStore, Xt as buildRunModel, Y as parentServerName, Yt as resolveStoragePaths, Zt as chainPositionOf, _ as useSafeModeQueue, _r as sumRunCosts, _t as hintsLength, a as useSurfaces, an as tryOpenBrowser, at as InteractionsProvider, b as getSafelist, br as toolResultText, c as useStreamBuffer, cn as buildUpdateHint, cr as deriveSessionTitle, ct as createInteractionTools, d as discoverProjectSkills, dr as listSessionMeta, dt as pendingInteractionsFromTurns, en as providerKeySetChanged, er as buildBuildSystem, et as useMcpAuthDispatch, fr as loadState, g as useSafeModeActions, gr as stripSpawnTokensLine, gt as clipHintsToWidth, h as SafeModeProvider, hr as serverToolResultSummary, ht as EMPTY_HINTS, i as useSelectStyle, in as useCompletion, ir as createChatTurnsReadTool, it as ASK_USER_TOOL, j as supportsOAuth, k as oauthUsesManualCodePaste, kt as clampFps, l as buildSkillsConfig, ln as useUpdateCheck, lr as eventsFromTurns, m as writeSessionExport, mt as useInteractionsQueue, n as ThemeProvider, nr as envSection, nt as getMcpAuthStatus, or as compactSummaryEvent, ot as PRESENT_PLAN_TOOL, pr as marginTopFor, pt as useInteractionsActions, q as buildVisibleMcpRows, qt as useConfig, r as useColors, rn as toggleChainEntry, rr as chatReferenceTokensForPrompt, s as useTheme, sn as bootTick, st as buildResumedToolResultsTurn, t as computeTurnAnchors, tn as restoreChainFallbacks, tr as buildPlanSystem, tt as useMcpAuthState, u as defaultSkillScanPaths, ur as lastContextSizeFromTurns, ut as makeRequestInteraction, vn as chatAutoCompactBehavior, vt as truncateTrailing, wt as SETTINGS_CATEGORIES, x as isOnSafelist, xr as updateToolEventOutcomes, xt as listProjectFiles, y as addToSafelist, yn as discoverAgentsMd, yr as toolCallPreview, yt as buildHints, z as loadMcpToolsCache } from "./transcript-anchors-CnmxZ8QR.js";
|
|
2
|
+
import { B as createExtensionPromptBridge, Bt as KEYBINDING_KEY_COL_WIDTH, Ct as tailTruncate, Dt as createModelSearchTool, F as summaryToTurn, Gt as matchesBinding, Ht as formatBindingForDisplay, J as updateInstalledExtension, S as compactConversation, Tt as looksBinary, U as installExtensionFromSpec, Ut as groupBindings, V as ExtensionInstallError, Vt as ensureKeybindingsFile, Wt as keybindingsPath, X as registerExtensionHostModules, Xt as resolveExtensionKeybindings, Y as createExtensionHud, Z as discoverAndBuildExtensionRegistry, _ as resolveTasksDir, at as createExtensionHostRuntimeBridge, b as selectFilesFromSession, c as applyCompactSummaryCutoff, dn as resolveExtensionConfigValue, et as composeExtensionPreset, f as cleanupPersistedSession, fn as sanitizeExtensionConfigActionPatch, g as resolvePersistDir, gn as effectiveContextWindow, gt as isSpawnTool, h as resolveMcpWarningsDir, hn as OUTPUT_RESERVE_TOKENS, in as scanExtensionDirectories, it as partitionExtensionCatalog, m as rehomePersistedStubs, nt as filterExtensionRegistry, q as removeInstalledExtension, rn as parseExtensionScanPathEnv, sn as coerceExtensionConfigInput, t as createAgent, tn as inlineLoadedExtension, tt as disposeExtensionRegistry, ut as basic_default, v as buildPostCompactAttachments } from "./agent--VPMZ0nT.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
|
-
import { n as appendCapped } from "./output-cap-
|
|
5
|
-
import { i as killProcessGroup, n as SUPPORTS_PROCESS_GROUPS, r as createProcessContext } from "./contexts-
|
|
4
|
+
import { n as appendCapped } from "./output-cap-DM1HrgIp.js";
|
|
5
|
+
import { i as killProcessGroup, n as SUPPORTS_PROCESS_GROUPS, r as createProcessContext } from "./contexts-0rmrBhTK.js";
|
|
6
6
|
import { l as errorMessage } from "./errors-DJUxZg9b.js";
|
|
7
|
-
import { M as findGitRoot, j as projectUserPaths } from "./resolve-
|
|
7
|
+
import { M as findGitRoot, j as projectUserPaths } from "./resolve-BPTA1RpX.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
10
|
import { d as McpOAuthProvider, i as nonOwningMcpView, n as connectMcpServers, p as hasAuthorizationHeader } from "./mcp-H6bqyM94.js";
|
|
11
|
-
import { n as flattenTurns, r as formatTokenUsage, t as effectiveInputFromTurn } from "./stats-DAKBEKjc.js";
|
|
12
11
|
import { replaceDynamicSection } from "./prompt.js";
|
|
13
|
-
import { a as getExtensionSessionState,
|
|
12
|
+
import { a as getExtensionSessionState, c as setExtensionSessionState, i as demoteStaleRunningStatus, o as loadSession, t as createSession } from "./session-jLsc_kMH.js";
|
|
13
|
+
import { n as flattenTurns, r as formatTokenUsage, t as effectiveInputFromTurn } from "./stats-DAKBEKjc.js";
|
|
14
14
|
import { o as withTimeout } from "./timeout-BDetbuN6.js";
|
|
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-
|
|
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-CbcdZpfC.js";
|
|
16
16
|
import { s as resolveCompletionSubmit } from "./completion-core-BRo86R_L.js";
|
|
17
|
-
import { i as installSkillFromSpec, r as SkillInstallError } from "./skills-
|
|
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-
|
|
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-
|
|
17
|
+
import { i as installSkillFromSpec, r as SkillInstallError } from "./skills-C7eIjWYm.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-afiadwf0.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, w as renderDefaultCallbackPage } from "./auth-DIT_DMwa.js";
|
|
20
20
|
import { createDockerContext } from "./contexts/docker.js";
|
|
21
21
|
import { createTuiStore } from "./session/sqlite.js";
|
|
22
|
-
import { $ as extractEditPayload, B as isVisible, C as chunkMarkdownForRender, E as stripHtmlCommentsOutsideCode, F as BASH_CALL_ID_PREFIX, G as streamEventSearchText, H as promptHistoryFromEvents, I as EDIT_TOOL_NAMES, J as buildContextualDiff, K as turnSelectionOwnership, L as isEditErrorResult, N as blendHsl, O as createSkillsCompletionProvider, P as buildLinearRamp, R as isTurnHighlighted, T as splitMarkdownCodeBlocks, U as selectableTurnIds, V as isVisibleDuringSearch, W as selectionAfterTurnRemoval, X as clipDiffForRender, Y as buildUnifiedDiff, _ as turnContextSize, a as TOOL_DISPLAY, at as buildEditOutcomesAnnotation, b as filterModelCatalog, ct as parseEditOutcomesFromResult, d as finalizeStreamingMarkdown, dt as stripEditOutcomesAnnotation, et as filetypeFromPath, f as finalizeStreamingMarkdownForOwner, ft as summarizeOutcomes, g as revealEarlierTranscriptEvents, h as replaceTranscriptTurnEvents, ht as createChatsCompletionProvider, i as turnAsText, j as createFilesCompletionProvider, k as uniqueSkillNamesFromReferences, lt as resolveApprovalForPayload, n as deleteTurnSafely, o as displayNameFor, p as hiddenEarlierTranscriptCount, r as truncateTurnsAt, rt as summarizeEditPayload, s as formatToolCall, st as mergeApprovalAndBodyOutcomes, tt as previewEditPayload, u as capTranscriptEvents, ut as rewriteMultiEditHeader, v as splitPromptSegments, w as normalizeMarkdownCodeFences, y as buildModelCatalog, z as isUserBashEvent } from "./turn-operations-
|
|
22
|
+
import { $ as extractEditPayload, B as isVisible, C as chunkMarkdownForRender, E as stripHtmlCommentsOutsideCode, F as BASH_CALL_ID_PREFIX, G as streamEventSearchText, H as promptHistoryFromEvents, I as EDIT_TOOL_NAMES, J as buildContextualDiff, K as turnSelectionOwnership, L as isEditErrorResult, N as blendHsl, O as createSkillsCompletionProvider, P as buildLinearRamp, R as isTurnHighlighted, T as splitMarkdownCodeBlocks, U as selectableTurnIds, V as isVisibleDuringSearch, W as selectionAfterTurnRemoval, X as clipDiffForRender, Y as buildUnifiedDiff, _ as turnContextSize, a as TOOL_DISPLAY, at as buildEditOutcomesAnnotation, b as filterModelCatalog, ct as parseEditOutcomesFromResult, d as finalizeStreamingMarkdown, dt as stripEditOutcomesAnnotation, et as filetypeFromPath, f as finalizeStreamingMarkdownForOwner, ft as summarizeOutcomes, g as revealEarlierTranscriptEvents, h as replaceTranscriptTurnEvents, ht as createChatsCompletionProvider, i as turnAsText, j as createFilesCompletionProvider, k as uniqueSkillNamesFromReferences, lt as resolveApprovalForPayload, n as deleteTurnSafely, o as displayNameFor, p as hiddenEarlierTranscriptCount, r as truncateTurnsAt, rt as summarizeEditPayload, s as formatToolCall, st as mergeApprovalAndBodyOutcomes, tt as previewEditPayload, u as capTranscriptEvents, ut as rewriteMultiEditHeader, v as splitPromptSegments, w as normalizeMarkdownCodeFences, y as buildModelCatalog, z as isUserBashEvent } from "./turn-operations-4tnvKwfJ.js";
|
|
23
23
|
import { a as searchHighlightRanges, c as searchSessionHistoryIndexAsync, i as highlightSegments, n as buildSessionSearchIndexAsync, r as filterSessionSearchCatalog, u as searchSessionIndexAsync } from "./history-search-C4bk1Wz_.js";
|
|
24
24
|
import { basename, dirname, join, relative, resolve } from "node:path";
|
|
25
25
|
import { Buffer } from "node:buffer";
|
|
@@ -198,33 +198,70 @@ function claudeProjectSlug(path) {
|
|
|
198
198
|
* `projectRoot` is derived.
|
|
199
199
|
*/
|
|
200
200
|
function listClaudeSessionFiles(opts = {}) {
|
|
201
|
+
const out = [];
|
|
202
|
+
walkClaudeSessionFiles(opts, opts.allProjects ? (file) => out.push(file) : (file, scoped) => {
|
|
203
|
+
if (scoped()) out.push(file);
|
|
204
|
+
});
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Detection-preview counts — scoped and all-projects figures from ONE
|
|
209
|
+
* directory walk (the naive two-listing approach reads every project dir
|
|
210
|
+
* twice). The scoped classification (with its per-file cwd peek for
|
|
211
|
+
* candidate dirs) runs at most once per file via the lazy `scoped()`
|
|
212
|
+
* thunk.
|
|
213
|
+
*/
|
|
214
|
+
function countClaudeSessionFiles(opts = {}) {
|
|
215
|
+
let project = 0;
|
|
216
|
+
let all = 0;
|
|
217
|
+
walkClaudeSessionFiles({
|
|
218
|
+
...opts,
|
|
219
|
+
allProjects: false
|
|
220
|
+
}, (_file, scoped) => {
|
|
221
|
+
all++;
|
|
222
|
+
if (scoped()) project++;
|
|
223
|
+
}, true);
|
|
224
|
+
return {
|
|
225
|
+
project,
|
|
226
|
+
all
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Shared walk under `~/.claude/projects`. `visit` receives every
|
|
231
|
+
* transcript of every CANDIDATE dir (scoped mode) or every dir
|
|
232
|
+
* (`allProjects` / `visitAllDirs`), plus a lazy `scoped()` thunk that
|
|
233
|
+
* answers "does this file belong to the current project?" — lazy because
|
|
234
|
+
* the answer can cost a `transcriptProjectRoot` peek (up to the whole
|
|
235
|
+
* file), which pure all-projects listings never need.
|
|
236
|
+
*/
|
|
237
|
+
function walkClaudeSessionFiles(opts, visit, visitAllDirs = false) {
|
|
201
238
|
const { projectRoot, home } = roots(opts);
|
|
202
239
|
const projectsDir = resolve(home, ".claude/projects");
|
|
203
|
-
if (!existsSync(projectsDir)) return
|
|
240
|
+
if (!existsSync(projectsDir)) return;
|
|
204
241
|
const slugs = [claudeProjectSlug(projectRoot), claudeProjectSlug(realpathOr(projectRoot))];
|
|
205
242
|
const exact = new Set(slugs);
|
|
206
243
|
const prefixes = [...new Set(slugs.map((s) => `${s}-`))];
|
|
207
244
|
const wantedRoots = /* @__PURE__ */ new Set([projectRoot, realpathOr(projectRoot)]);
|
|
208
|
-
const out = [];
|
|
209
245
|
for (const entry of readdirSync(projectsDir, { withFileTypes: true })) {
|
|
210
246
|
if (!entry.isDirectory()) continue;
|
|
211
247
|
const exactMatch = exact.has(entry.name);
|
|
212
|
-
|
|
248
|
+
const candidate = exactMatch || prefixes.some((p) => entry.name.startsWith(p));
|
|
249
|
+
if (!opts.allProjects && !visitAllDirs && !candidate) continue;
|
|
213
250
|
const projectDir = join(projectsDir, entry.name);
|
|
214
251
|
for (const file of readdirSync(projectDir)) {
|
|
215
252
|
if (!file.endsWith(".jsonl")) continue;
|
|
216
253
|
const path = join(projectDir, file);
|
|
217
|
-
|
|
254
|
+
const scoped = () => {
|
|
255
|
+
if (!candidate) return false;
|
|
218
256
|
const root = transcriptProjectRoot(path);
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
|
|
257
|
+
return root === null ? exactMatch : wantedRoots.has(root) || wantedRoots.has(realpathOr(root));
|
|
258
|
+
};
|
|
259
|
+
visit({
|
|
222
260
|
path,
|
|
223
261
|
projectDir
|
|
224
|
-
});
|
|
262
|
+
}, scoped);
|
|
225
263
|
}
|
|
226
264
|
}
|
|
227
|
-
return out;
|
|
228
265
|
}
|
|
229
266
|
/**
|
|
230
267
|
* Peek a transcript's project root: scan the first chunk for the first
|
|
@@ -363,7 +400,7 @@ function convertClaudeSession(jsonl, opts = {}) {
|
|
|
363
400
|
});
|
|
364
401
|
}
|
|
365
402
|
if (turns.length === 0) return null;
|
|
366
|
-
const id =
|
|
403
|
+
const id = opts.fallbackId ?? claudeSessionId ?? crypto.randomUUID();
|
|
367
404
|
const projectRoot = cwd ? findGitRoot(cwd) ?? cwd : void 0;
|
|
368
405
|
return {
|
|
369
406
|
session: {
|
|
@@ -375,7 +412,8 @@ function convertClaudeSession(jsonl, opts = {}) {
|
|
|
375
412
|
metadata: {
|
|
376
413
|
...title ? { title } : {},
|
|
377
414
|
importedFrom: "claude-code",
|
|
378
|
-
claudeSessionId: id
|
|
415
|
+
claudeSessionId: id,
|
|
416
|
+
...claudeSessionId && claudeSessionId !== id ? { claudeLineageId: claudeSessionId } : {}
|
|
379
417
|
},
|
|
380
418
|
createdAt: turns[0].createdAt,
|
|
381
419
|
updatedAt: turns[turns.length - 1].createdAt
|
|
@@ -483,13 +521,14 @@ async function importClaudeSessions(store, opts = {}) {
|
|
|
483
521
|
failed: []
|
|
484
522
|
};
|
|
485
523
|
for (const file of listClaudeSessionFiles(opts)) try {
|
|
486
|
-
const
|
|
487
|
-
if (
|
|
488
|
-
result.
|
|
524
|
+
const fallbackId = basename(file.path, ".jsonl");
|
|
525
|
+
if (await store.load(fallbackId)) {
|
|
526
|
+
result.skipped++;
|
|
489
527
|
continue;
|
|
490
528
|
}
|
|
491
|
-
|
|
492
|
-
|
|
529
|
+
const converted = convertClaudeSession(readFileSync(file.path, "utf8"), { fallbackId });
|
|
530
|
+
if (!converted) {
|
|
531
|
+
result.empty++;
|
|
493
532
|
continue;
|
|
494
533
|
}
|
|
495
534
|
await store.save(converted.session);
|
|
@@ -519,7 +558,8 @@ function importClaudeMcps(opts = {}) {
|
|
|
519
558
|
const result = {
|
|
520
559
|
copied: [],
|
|
521
560
|
skipped: [],
|
|
522
|
-
failed: []
|
|
561
|
+
failed: [],
|
|
562
|
+
duplicates: []
|
|
523
563
|
};
|
|
524
564
|
const nativeNames = /* @__PURE__ */ new Set();
|
|
525
565
|
for (const candidate of defaultMcpsConfigPaths({
|
|
@@ -562,7 +602,10 @@ function importClaudeMcps(opts = {}) {
|
|
|
562
602
|
}
|
|
563
603
|
const seen = /* @__PURE__ */ new Set();
|
|
564
604
|
for (const { servers, scope } of sources) for (const server of servers) {
|
|
565
|
-
if (seen.has(server.name))
|
|
605
|
+
if (seen.has(server.name)) {
|
|
606
|
+
result.duplicates.push(server.name);
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
566
609
|
seen.add(server.name);
|
|
567
610
|
if (nativeNames.has(server.name)) {
|
|
568
611
|
result.skipped.push(server.name);
|
|
@@ -679,13 +722,28 @@ async function importFromClaudeCode(store, opts = {}) {
|
|
|
679
722
|
if (opts.skills !== false) summary.skills = importClaudeSkills(opts);
|
|
680
723
|
return summary;
|
|
681
724
|
}
|
|
725
|
+
/**
|
|
726
|
+
* Per-catalog fzf instance, keyed on catalog reference identity —
|
|
727
|
+
* `suggest()` runs per keystroke and `new Fzf(...)` walks the whole
|
|
728
|
+
* command list to build its match structures. The getter returns a
|
|
729
|
+
* stable array until a registry rebuild swaps it.
|
|
730
|
+
*/
|
|
731
|
+
const fzfByCatalog = /* @__PURE__ */ new WeakMap();
|
|
732
|
+
function fzfFor(catalog) {
|
|
733
|
+
let fzf = fzfByCatalog.get(catalog);
|
|
734
|
+
if (!fzf) {
|
|
735
|
+
fzf = new Fzf(catalog, {
|
|
736
|
+
selector: (c) => c.name,
|
|
737
|
+
casing: "case-insensitive"
|
|
738
|
+
});
|
|
739
|
+
fzfByCatalog.set(catalog, fzf);
|
|
740
|
+
}
|
|
741
|
+
return fzf;
|
|
742
|
+
}
|
|
682
743
|
/** Filter + rank commands against a query (name-priority, then description, then fuzzy on name). */
|
|
683
744
|
function scoreCommands(catalog, query) {
|
|
684
745
|
const q = query.trim().toLowerCase();
|
|
685
|
-
const fuzzyHits = q.length > 0 ? new Set(
|
|
686
|
-
selector: (c) => c.name,
|
|
687
|
-
casing: "case-insensitive"
|
|
688
|
-
}).find(q).map((r) => r.item)) : null;
|
|
746
|
+
const fuzzyHits = q.length > 0 ? new Set(fzfFor(catalog).find(q).map((r) => r.item)) : null;
|
|
689
747
|
const scored = [];
|
|
690
748
|
for (const command of catalog) {
|
|
691
749
|
const name = command.name.toLowerCase();
|
|
@@ -805,12 +863,252 @@ function attachMcpWarnLog(hooks, opts) {
|
|
|
805
863
|
} };
|
|
806
864
|
}
|
|
807
865
|
//#endregion
|
|
866
|
+
//#region src/tui/clickable.tsx
|
|
867
|
+
/** Glyph / word aliases → OpenTUI key names (`parse.keypress` conventions). */
|
|
868
|
+
const KEY_NAME_ALIASES = {
|
|
869
|
+
"esc": "escape",
|
|
870
|
+
"↵": "return",
|
|
871
|
+
"enter": "return",
|
|
872
|
+
"tab": "tab",
|
|
873
|
+
"space": "space",
|
|
874
|
+
"⌫": "backspace",
|
|
875
|
+
"backspace": "backspace",
|
|
876
|
+
"pgup": "pageup",
|
|
877
|
+
"pgdn": "pagedown",
|
|
878
|
+
"↑": "up",
|
|
879
|
+
"↓": "down",
|
|
880
|
+
"←": "left",
|
|
881
|
+
"→": "right",
|
|
882
|
+
"↑↓": "down",
|
|
883
|
+
"←→": "right",
|
|
884
|
+
"del": "delete"
|
|
885
|
+
};
|
|
886
|
+
/** Decorative pseudo-keys that must never dispatch (chips, markers). */
|
|
887
|
+
const NON_KEYS = /* @__PURE__ */ new Set([
|
|
888
|
+
"✦",
|
|
889
|
+
"·",
|
|
890
|
+
"…"
|
|
891
|
+
]);
|
|
892
|
+
/** Mac-style modifier glyphs → word modifiers (`⌘k`, `⌘+k`, `⇧↵`, …). */
|
|
893
|
+
const GLYPH_MODIFIERS = {
|
|
894
|
+
"⌘": "meta",
|
|
895
|
+
"⌃": "ctrl",
|
|
896
|
+
"⌥": "option",
|
|
897
|
+
"⇧": "shift"
|
|
898
|
+
};
|
|
899
|
+
/**
|
|
900
|
+
* Parse a hint key spec (`ctrl+g`, `shift+↵`, `esc`, `a`, `↑↓`) into a
|
|
901
|
+
* dispatchable {@link ParsedKey}, or `null` when the spec is decorative
|
|
902
|
+
* or ambiguous (the hint then renders non-clickable). Modifier segments
|
|
903
|
+
* are order-insensitive; the final segment is the key itself.
|
|
904
|
+
*/
|
|
905
|
+
function parseHintKeySpec(spec) {
|
|
906
|
+
const trimmed = spec.trim().toLowerCase();
|
|
907
|
+
if (!trimmed || NON_KEYS.has(trimmed)) return null;
|
|
908
|
+
let first = trimmed.split("/")[0] ?? "";
|
|
909
|
+
first = first.replace(/[⌘⌃⌥⇧]/g, (glyph) => `${GLYPH_MODIFIERS[glyph]}+`).replace(/\+\+/g, "+");
|
|
910
|
+
if (first.startsWith("^") && first.length > 1) first = `ctrl+${first.slice(1)}`;
|
|
911
|
+
const segments = first.split("+").map((s) => s.trim()).filter(Boolean);
|
|
912
|
+
if (segments.length === 0) return null;
|
|
913
|
+
const keyPart = segments[segments.length - 1] ?? "";
|
|
914
|
+
const modifiers = segments.slice(0, -1);
|
|
915
|
+
const mods = {
|
|
916
|
+
ctrl: false,
|
|
917
|
+
meta: false,
|
|
918
|
+
shift: false,
|
|
919
|
+
option: false
|
|
920
|
+
};
|
|
921
|
+
for (const mod of modifiers) if (mod === "ctrl" || mod === "control") mods.ctrl = true;
|
|
922
|
+
else if (mod === "shift") mods.shift = true;
|
|
923
|
+
else if (mod === "alt" || mod === "option") mods.option = true;
|
|
924
|
+
else if (mod === "meta" || mod === "cmd" || mod === "super") mods.meta = true;
|
|
925
|
+
else return null;
|
|
926
|
+
const name = KEY_NAME_ALIASES[keyPart] ?? (/^f(?:[1-9]|1[0-2])$/.test(keyPart) ? keyPart : null) ?? (keyPart.length === 1 ? keyPart : null);
|
|
927
|
+
if (!name) return null;
|
|
928
|
+
const sequence = keySequence(name, mods);
|
|
929
|
+
return {
|
|
930
|
+
name,
|
|
931
|
+
...mods,
|
|
932
|
+
sequence,
|
|
933
|
+
number: /^\d$/.test(name),
|
|
934
|
+
raw: sequence,
|
|
935
|
+
eventType: "press",
|
|
936
|
+
source: "raw"
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
/** Byte sequences real terminals send for the named specials we synthesize. */
|
|
940
|
+
const NAMED_KEY_SEQUENCES = {
|
|
941
|
+
return: "\r",
|
|
942
|
+
tab: " ",
|
|
943
|
+
escape: "\x1B",
|
|
944
|
+
space: " ",
|
|
945
|
+
backspace: "",
|
|
946
|
+
delete: "\x1B[3~",
|
|
947
|
+
up: "\x1B[A",
|
|
948
|
+
down: "\x1B[B",
|
|
949
|
+
right: "\x1B[C",
|
|
950
|
+
left: "\x1B[D",
|
|
951
|
+
pageup: "\x1B[5~",
|
|
952
|
+
pagedown: "\x1B[6~"
|
|
953
|
+
};
|
|
954
|
+
/**
|
|
955
|
+
* The `sequence`/`raw` a REAL keypress would carry — without it the
|
|
956
|
+
* synthetic event is second-class: focused inputs insert text from
|
|
957
|
+
* `key.sequence` (so a clicked `@ files` hint must actually type `@`),
|
|
958
|
+
* and some handlers match on `sequence` rather than `name`. Modifier
|
|
959
|
+
* chords return `''`: their handlers dispatch on `name` + flags, and
|
|
960
|
+
* fabricating control bytes would risk double interpretation.
|
|
961
|
+
*/
|
|
962
|
+
function keySequence(name, mods) {
|
|
963
|
+
if (mods.ctrl || mods.meta || mods.option) return "";
|
|
964
|
+
if (mods.shift) return name === "tab" ? "\x1B[Z" : "";
|
|
965
|
+
if (name.length === 1) return name;
|
|
966
|
+
return NAMED_KEY_SEQUENCES[name] ?? "";
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Dispatch a hint key spec through the renderer's key pipeline. Returns
|
|
970
|
+
* `false` for unparseable specs (no-op). Exposed for non-hint surfaces
|
|
971
|
+
* that want the same click==keypress contract.
|
|
972
|
+
*
|
|
973
|
+
* CONTRACT NOTE: `processParsedKey` wraps the parsed key in a real
|
|
974
|
+
* `KeyEvent`, so handlers receive the same object type as terminal
|
|
975
|
+
* input — but synthesized modifier chords carry an empty
|
|
976
|
+
* `sequence`/`raw` (fabricating control bytes would risk double
|
|
977
|
+
* interpretation by byte-level consumers). Every handler in this app
|
|
978
|
+
* discriminates on `name` + modifier flags, which is the contract this
|
|
979
|
+
* dispatch guarantees; a future handler matching on non-empty
|
|
980
|
+
* `sequence` for chords would see synthesized clicks differ from real
|
|
981
|
+
* keystrokes.
|
|
982
|
+
*/
|
|
983
|
+
function dispatchHintKey(renderer, spec) {
|
|
984
|
+
const parsed = parseHintKeySpec(spec);
|
|
985
|
+
if (!parsed) return false;
|
|
986
|
+
renderer.keyInput.processParsedKey(parsed);
|
|
987
|
+
return true;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* True when a row click landed on the row's `[✓] ` checkbox cell — the
|
|
991
|
+
* columns `[startCol, startCol + width)` of the FIRST line of the target
|
|
992
|
+
* renderable. Rows that must stay single `<text>` renderables (the MCP
|
|
993
|
+
* list documents an OpenTUI layout regression forbidding box wrappers)
|
|
994
|
+
* can't make the checkbox its own renderable, so zone-splitting works by
|
|
995
|
+
* coordinate instead: `event.x/y` are absolute, the target renderable
|
|
996
|
+
* knows its own absolute origin, and the difference is the glyph column.
|
|
997
|
+
* The `y` check pins line 0 so wrapped continuation lines can't false-
|
|
998
|
+
* positive into the checkbox range. Degrades to `false` (row semantics)
|
|
999
|
+
* when the target's geometry is unavailable.
|
|
1000
|
+
*/
|
|
1001
|
+
function inCheckboxZone(event, startCol, width = 4) {
|
|
1002
|
+
const target = event.target;
|
|
1003
|
+
if (!target || typeof target.x !== "number" || typeof target.y !== "number") return false;
|
|
1004
|
+
if (event.y - target.y !== 0) return false;
|
|
1005
|
+
const col = event.x - target.x;
|
|
1006
|
+
return col >= startCol && col < startCol + width;
|
|
1007
|
+
}
|
|
1008
|
+
/** Spans for one hint's text content — shared by hover and rest states. */
|
|
1009
|
+
function hintSpans(hint, COLOR, hovered) {
|
|
1010
|
+
const keyColor = hovered ? COLOR.accent : hint.keyColor ?? COLOR.warn;
|
|
1011
|
+
const labelColor = hovered ? COLOR.accent : hint.labelColor ?? COLOR.dim;
|
|
1012
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1013
|
+
hint.key !== "" && /* @__PURE__ */ jsx$1("span", {
|
|
1014
|
+
fg: keyColor,
|
|
1015
|
+
children: hint.key
|
|
1016
|
+
}),
|
|
1017
|
+
hint.extra && /* @__PURE__ */ jsx$1("span", {
|
|
1018
|
+
fg: hovered ? COLOR.accent : hint.extra.keyColor ?? COLOR.mute,
|
|
1019
|
+
children: hint.extra.key
|
|
1020
|
+
}),
|
|
1021
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
1022
|
+
fg: labelColor,
|
|
1023
|
+
children: hint.key === "" ? hint.label : ` ${hint.label}`
|
|
1024
|
+
}),
|
|
1025
|
+
hint.extra && /* @__PURE__ */ jsx$1("span", {
|
|
1026
|
+
fg: hovered ? COLOR.accent : hint.extra.labelColor ?? COLOR.dim,
|
|
1027
|
+
children: ` ${hint.extra.label}`
|
|
1028
|
+
})
|
|
1029
|
+
] });
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* One hint as its own `<text>` renderable — clickable when its key spec
|
|
1033
|
+
* parses, hover-highlighted in the theme accent. Non-parseable hints
|
|
1034
|
+
* render identically but inert, so decorative chips cost nothing.
|
|
1035
|
+
*/
|
|
1036
|
+
function ClickableHint({ hint }) {
|
|
1037
|
+
const COLOR = useColors();
|
|
1038
|
+
const renderer = useRenderer();
|
|
1039
|
+
const [hovered, setHovered] = useState(false);
|
|
1040
|
+
if (!(parseHintKeySpec(hint.key) !== null)) return /* @__PURE__ */ jsx$1("text", {
|
|
1041
|
+
selectable: false,
|
|
1042
|
+
children: hintSpans(hint, COLOR, false)
|
|
1043
|
+
});
|
|
1044
|
+
return /* @__PURE__ */ jsx$1("text", {
|
|
1045
|
+
selectable: false,
|
|
1046
|
+
onMouseDown: (event) => {
|
|
1047
|
+
event.stopPropagation();
|
|
1048
|
+
event.preventDefault();
|
|
1049
|
+
dispatchHintKey(renderer, hint.key);
|
|
1050
|
+
},
|
|
1051
|
+
onMouseOver: () => setHovered(true),
|
|
1052
|
+
onMouseOut: () => setHovered(false),
|
|
1053
|
+
children: hintSpans(hint, COLOR, hovered)
|
|
1054
|
+
});
|
|
1055
|
+
}
|
|
1056
|
+
/**
|
|
1057
|
+
* Modal-footer flavor of {@link HintRow}: same clickable hints, but with
|
|
1058
|
+
* the modal convention's mute labels (footers historically rendered as
|
|
1059
|
+
* `<text fg={mute}>` prose) and falsy-entry filtering so call sites can
|
|
1060
|
+
* express conditional hints inline:
|
|
1061
|
+
*
|
|
1062
|
+
* ```tsx
|
|
1063
|
+
* <ModalHints hints={[
|
|
1064
|
+
* { key: '↑↓', label: 'navigate' },
|
|
1065
|
+
* onRefresh && { key: 'ctrl+r', label: 'refresh' },
|
|
1066
|
+
* { key: 'esc', label: 'close' },
|
|
1067
|
+
* ]}
|
|
1068
|
+
* />
|
|
1069
|
+
* ```
|
|
1070
|
+
*
|
|
1071
|
+
* Per-hint `keyColor`/`labelColor` overrides still win over the defaults.
|
|
1072
|
+
*/
|
|
1073
|
+
function ModalHints({ hints }) {
|
|
1074
|
+
const COLOR = useColors();
|
|
1075
|
+
return /* @__PURE__ */ jsx$1(HintRow, { hints: hints.filter((h) => Boolean(h)).map((h) => ({
|
|
1076
|
+
labelColor: COLOR.mute,
|
|
1077
|
+
...h
|
|
1078
|
+
})) });
|
|
1079
|
+
}
|
|
1080
|
+
/**
|
|
1081
|
+
* A row of clickable hints with ` · ` separators — the renderable-per-hint
|
|
1082
|
+
* replacement for the span-based `renderHintSpans`. Text content is
|
|
1083
|
+
* byte-identical to the span renderer, so existing `hintsLength` width
|
|
1084
|
+
* math keeps holding.
|
|
1085
|
+
*/
|
|
1086
|
+
function HintRow({ hints }) {
|
|
1087
|
+
const COLOR = useColors();
|
|
1088
|
+
return /* @__PURE__ */ jsx$1("box", {
|
|
1089
|
+
style: {
|
|
1090
|
+
flexDirection: "row",
|
|
1091
|
+
flexWrap: "wrap"
|
|
1092
|
+
},
|
|
1093
|
+
children: hints.map((hint, i) => /* @__PURE__ */ jsxs("box", {
|
|
1094
|
+
style: { flexDirection: "row" },
|
|
1095
|
+
children: [i > 0 && /* @__PURE__ */ jsx$1("text", {
|
|
1096
|
+
selectable: false,
|
|
1097
|
+
fg: COLOR.mute,
|
|
1098
|
+
children: " · "
|
|
1099
|
+
}), /* @__PURE__ */ jsx$1(ClickableHint, { hint })]
|
|
1100
|
+
}, `${hint.key}\u0000${hint.label}\u0000${i}`))
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
//#endregion
|
|
808
1104
|
//#region src/tui/modal.tsx
|
|
809
1105
|
const ModalContext = createContext(null);
|
|
810
1106
|
function ModalRoot({ children }) {
|
|
811
1107
|
const [active, setActive] = useState(null);
|
|
812
1108
|
const [lockCount, setLockCount] = useState(0);
|
|
813
1109
|
const [escLockCount, setEscLockCount] = useState(0);
|
|
1110
|
+
const backdropRef = useRef(null);
|
|
1111
|
+
const renderer = useRenderer();
|
|
814
1112
|
const api = useMemo(() => ({
|
|
815
1113
|
open: (node) => setActive(node),
|
|
816
1114
|
close: () => setActive(null),
|
|
@@ -837,6 +1135,7 @@ function ModalRoot({ children }) {
|
|
|
837
1135
|
},
|
|
838
1136
|
children
|
|
839
1137
|
}), active && /* @__PURE__ */ jsx$1("box", {
|
|
1138
|
+
ref: backdropRef,
|
|
840
1139
|
style: {
|
|
841
1140
|
position: "absolute",
|
|
842
1141
|
top: 0,
|
|
@@ -847,6 +1146,12 @@ function ModalRoot({ children }) {
|
|
|
847
1146
|
justifyContent: "center",
|
|
848
1147
|
zIndex: 100
|
|
849
1148
|
},
|
|
1149
|
+
onMouseDown: (event) => {
|
|
1150
|
+
if (event.target !== backdropRef.current) return;
|
|
1151
|
+
event.stopPropagation();
|
|
1152
|
+
event.preventDefault();
|
|
1153
|
+
dispatchHintKey(renderer, "esc");
|
|
1154
|
+
},
|
|
850
1155
|
children: active
|
|
851
1156
|
})]
|
|
852
1157
|
});
|
|
@@ -990,26 +1295,20 @@ function AgentPickerModal({ agents, currentAgentId, onPick }) {
|
|
|
990
1295
|
if (option) onPick(option.value);
|
|
991
1296
|
}
|
|
992
1297
|
}),
|
|
993
|
-
/* @__PURE__ */
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
fg: COLOR.warn,
|
|
1008
|
-
children: "esc"
|
|
1009
|
-
}),
|
|
1010
|
-
" close"
|
|
1011
|
-
]
|
|
1012
|
-
})
|
|
1298
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
1299
|
+
{
|
|
1300
|
+
key: "↑↓",
|
|
1301
|
+
label: "navigate"
|
|
1302
|
+
},
|
|
1303
|
+
{
|
|
1304
|
+
key: "↵",
|
|
1305
|
+
label: "select"
|
|
1306
|
+
},
|
|
1307
|
+
{
|
|
1308
|
+
key: "esc",
|
|
1309
|
+
label: "close"
|
|
1310
|
+
}
|
|
1311
|
+
] })
|
|
1013
1312
|
]
|
|
1014
1313
|
});
|
|
1015
1314
|
}
|
|
@@ -1217,31 +1516,28 @@ function CancelToolModal({ inFlight, onCancel, onCancelAll, onClose }) {
|
|
|
1217
1516
|
callIdColWidth,
|
|
1218
1517
|
childColWidth
|
|
1219
1518
|
}, row.callId))
|
|
1220
|
-
}), /* @__PURE__ */
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
" close"
|
|
1243
|
-
]
|
|
1244
|
-
})]
|
|
1519
|
+
}), /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
1520
|
+
{
|
|
1521
|
+
key: "↑↓",
|
|
1522
|
+
label: "navigate",
|
|
1523
|
+
labelColor: COLOR.dim
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
key: "↵",
|
|
1527
|
+
label: "cancel selected",
|
|
1528
|
+
labelColor: COLOR.dim
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
key: "a",
|
|
1532
|
+
label: "cancel all",
|
|
1533
|
+
labelColor: COLOR.dim
|
|
1534
|
+
},
|
|
1535
|
+
{
|
|
1536
|
+
key: "esc",
|
|
1537
|
+
label: "close",
|
|
1538
|
+
labelColor: COLOR.dim
|
|
1539
|
+
}
|
|
1540
|
+
] })]
|
|
1245
1541
|
});
|
|
1246
1542
|
}
|
|
1247
1543
|
function CancelToolRow({ row, isFocused, highlightBg, elapsedColWidth, callIdColWidth, childColWidth }) {
|
|
@@ -1354,13 +1650,7 @@ function ClaudeImportModal({ store, cwd, prefix, onDone }) {
|
|
|
1354
1650
|
const [summary, setSummary] = useState(null);
|
|
1355
1651
|
const [error, setError] = useState(null);
|
|
1356
1652
|
const runningRef = useRef(false);
|
|
1357
|
-
const counts = useMemo(() => ({
|
|
1358
|
-
project: listClaudeSessionFiles({ cwd }).length,
|
|
1359
|
-
all: listClaudeSessionFiles({
|
|
1360
|
-
cwd,
|
|
1361
|
-
allProjects: true
|
|
1362
|
-
}).length
|
|
1363
|
-
}), [cwd]);
|
|
1653
|
+
const counts = useMemo(() => countClaudeSessionFiles({ cwd }), [cwd]);
|
|
1364
1654
|
const rows = [
|
|
1365
1655
|
{
|
|
1366
1656
|
key: "sessions",
|
|
@@ -1415,18 +1705,19 @@ function ClaudeImportModal({ store, cwd, prefix, onDone }) {
|
|
|
1415
1705
|
await onDone?.(result);
|
|
1416
1706
|
} catch {}
|
|
1417
1707
|
};
|
|
1708
|
+
/** ↵/space/click on a row: the Import row runs, every other row toggles. */
|
|
1709
|
+
const activateRow = (row) => {
|
|
1710
|
+
if (row.key === "run") runImport();
|
|
1711
|
+
else setOptions((prev) => ({
|
|
1712
|
+
...prev,
|
|
1713
|
+
[row.key]: !prev[row.key]
|
|
1714
|
+
}));
|
|
1715
|
+
};
|
|
1418
1716
|
useKeyboard((key) => {
|
|
1419
1717
|
if (phase !== "pick") return;
|
|
1420
1718
|
if (key.name === "up" || key.ctrl && key.name === "p") setCursor((c) => (c - 1 + rows.length) % rows.length);
|
|
1421
1719
|
else if (key.name === "down" || key.ctrl && key.name === "n") setCursor((c) => (c + 1) % rows.length);
|
|
1422
|
-
else if (key.name === "return" || key.name === "space")
|
|
1423
|
-
const row = rows[cursor];
|
|
1424
|
-
if (row.key === "run") runImport();
|
|
1425
|
-
else setOptions((prev) => ({
|
|
1426
|
-
...prev,
|
|
1427
|
-
[row.key]: !prev[row.key]
|
|
1428
|
-
}));
|
|
1429
|
-
}
|
|
1720
|
+
else if (key.name === "return" || key.name === "space") activateRow(rows[cursor]);
|
|
1430
1721
|
});
|
|
1431
1722
|
if (phase === "running") return /* @__PURE__ */ jsx$1(Modal, {
|
|
1432
1723
|
title: "Import from Claude Code",
|
|
@@ -1453,26 +1744,35 @@ function ClaudeImportModal({ store, cwd, prefix, onDone }) {
|
|
|
1453
1744
|
summary.sessions.failed.length > 0 ? `, ${summary.sessions.failed.length} failed` : ""
|
|
1454
1745
|
]
|
|
1455
1746
|
}),
|
|
1747
|
+
summary?.sessions && failLine(summary.sessions.failed.map((f) => f.error)) !== null && /* @__PURE__ */ jsx$1("text", {
|
|
1748
|
+
fg: COLOR.error,
|
|
1749
|
+
children: failLine(summary.sessions.failed.map((f) => f.error))
|
|
1750
|
+
}),
|
|
1456
1751
|
summary?.mcps && /* @__PURE__ */ jsx$1("text", {
|
|
1457
1752
|
fg: COLOR.dim,
|
|
1458
1753
|
children: copyLine("mcp servers", summary.mcps)
|
|
1459
1754
|
}),
|
|
1755
|
+
summary?.mcps && failLine(summary.mcps.failed.map((f) => `${f.name}: ${f.error}`)) !== null && /* @__PURE__ */ jsx$1("text", {
|
|
1756
|
+
fg: COLOR.error,
|
|
1757
|
+
children: failLine(summary.mcps.failed.map((f) => `${f.name}: ${f.error}`))
|
|
1758
|
+
}),
|
|
1460
1759
|
summary?.skills && /* @__PURE__ */ jsx$1("text", {
|
|
1461
1760
|
fg: COLOR.dim,
|
|
1462
1761
|
children: copyLine("skills", summary.skills)
|
|
1463
1762
|
}),
|
|
1763
|
+
summary?.skills && failLine(summary.skills.failed.map((f) => `${f.name}: ${f.error}`)) !== null && /* @__PURE__ */ jsx$1("text", {
|
|
1764
|
+
fg: COLOR.error,
|
|
1765
|
+
children: failLine(summary.skills.failed.map((f) => `${f.name}: ${f.error}`))
|
|
1766
|
+
}),
|
|
1464
1767
|
summary?.notes.map((note) => /* @__PURE__ */ jsx$1("text", {
|
|
1465
1768
|
fg: COLOR.mute,
|
|
1466
1769
|
children: `· ${note}`
|
|
1467
1770
|
}, note))
|
|
1468
1771
|
]
|
|
1469
|
-
}), /* @__PURE__ */
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
children: "esc"
|
|
1474
|
-
}), " close"]
|
|
1475
|
-
})]
|
|
1772
|
+
}), /* @__PURE__ */ jsx$1(ModalHints, { hints: [{
|
|
1773
|
+
key: "esc",
|
|
1774
|
+
label: "close"
|
|
1775
|
+
}] })]
|
|
1476
1776
|
});
|
|
1477
1777
|
const enabledFor = (key) => key === "run" ? void 0 : options[key];
|
|
1478
1778
|
return /* @__PURE__ */ jsxs(Modal, {
|
|
@@ -1484,6 +1784,14 @@ function ClaudeImportModal({ store, cwd, prefix, onDone }) {
|
|
|
1484
1784
|
const enabled = enabledFor(row.key);
|
|
1485
1785
|
return /* @__PURE__ */ jsxs("text", {
|
|
1486
1786
|
fg: focused ? COLOR.brand : COLOR.dim,
|
|
1787
|
+
selectable: false,
|
|
1788
|
+
onMouseOver: () => setCursor(i),
|
|
1789
|
+
onMouseDown: (event) => {
|
|
1790
|
+
event.stopPropagation();
|
|
1791
|
+
event.preventDefault();
|
|
1792
|
+
setCursor(i);
|
|
1793
|
+
activateRow(row);
|
|
1794
|
+
},
|
|
1487
1795
|
children: [
|
|
1488
1796
|
/* @__PURE__ */ jsx$1("span", {
|
|
1489
1797
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -1504,32 +1812,32 @@ function ClaudeImportModal({ store, cwd, prefix, onDone }) {
|
|
|
1504
1812
|
]
|
|
1505
1813
|
}, row.key);
|
|
1506
1814
|
})
|
|
1507
|
-
}), /* @__PURE__ */
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
"
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
fg: COLOR.warn,
|
|
1522
|
-
children: "esc"
|
|
1523
|
-
}),
|
|
1524
|
-
" close"
|
|
1525
|
-
]
|
|
1526
|
-
})]
|
|
1815
|
+
}), /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
1816
|
+
{
|
|
1817
|
+
key: "↑↓",
|
|
1818
|
+
label: "navigate"
|
|
1819
|
+
},
|
|
1820
|
+
{
|
|
1821
|
+
key: "↵",
|
|
1822
|
+
label: "toggle / run"
|
|
1823
|
+
},
|
|
1824
|
+
{
|
|
1825
|
+
key: "esc",
|
|
1826
|
+
label: "close"
|
|
1827
|
+
}
|
|
1828
|
+
] })]
|
|
1527
1829
|
});
|
|
1528
1830
|
}
|
|
1831
|
+
/** First failure reason (+count of the rest), or null when nothing failed. */
|
|
1832
|
+
function failLine(errors) {
|
|
1833
|
+
if (errors.length === 0) return null;
|
|
1834
|
+
return errors.length > 1 ? ` ⚠ ${errors[0]} (+${errors.length - 1} more)` : ` ⚠ ${errors[0]}`;
|
|
1835
|
+
}
|
|
1529
1836
|
function copyLine(label, result) {
|
|
1530
1837
|
const parts = [];
|
|
1531
1838
|
parts.push(result.copied.length > 0 ? `${result.copied.length} copied (${result.copied.join(", ")})` : "none copied");
|
|
1532
1839
|
if (result.skipped.length > 0) parts.push(`${result.skipped.length} skipped as native (${result.skipped.join(", ")})`);
|
|
1840
|
+
if (result.duplicates && result.duplicates.length > 0) parts.push(`${result.duplicates.length} duplicate source entr${result.duplicates.length === 1 ? "y" : "ies"} dropped (${result.duplicates.join(", ")})`);
|
|
1533
1841
|
if (result.failed.length > 0) parts.push(`${result.failed.length} failed`);
|
|
1534
1842
|
return `${label}: ${parts.join(" · ")}`;
|
|
1535
1843
|
}
|
|
@@ -2311,7 +2619,7 @@ function onInputSubmit(handler) {
|
|
|
2311
2619
|
* Width tiering is driven by plain-text length estimates — close enough
|
|
2312
2620
|
* since the segments are ASCII-heavy.
|
|
2313
2621
|
*/
|
|
2314
|
-
function Footer({ hints, context, cost = null, status = null, compactionTokens = null, compactionStartedAt = null }) {
|
|
2622
|
+
function Footer({ hints, context, cost = null, status = null, compactionTokens = null, compactionStartedAt = null, retry = null, contextKey = null }) {
|
|
2315
2623
|
const { width } = useTerminalDimensions();
|
|
2316
2624
|
const showCost = typeof cost === "number" && cost > 0;
|
|
2317
2625
|
const inner = Math.max(0, width - 2);
|
|
@@ -2325,8 +2633,8 @@ function Footer({ hints, context, cost = null, status = null, compactionTokens =
|
|
|
2325
2633
|
const timer = setInterval(() => setCompactTick((t) => t + 1), 1e3);
|
|
2326
2634
|
return () => clearInterval(timer);
|
|
2327
2635
|
}, [status]);
|
|
2328
|
-
const statusLabel = status === "compacting" ? compactingLabel(compactionTokens, compactionStartedAt) : status === "searching" ? " Searching messages…" : "";
|
|
2329
|
-
const sW = status === "compacting" || status === "searching" ? 2 + statusLabel.length : status === "asking" ? 3 : status ? 2 : 0;
|
|
2636
|
+
const statusLabel = status === "compacting" ? compactingLabel(compactionTokens, compactionStartedAt) : status === "searching" ? " Searching messages…" : status === "retrying" ? retryingLabel(retry) : "";
|
|
2637
|
+
const sW = status === "compacting" || status === "searching" || status === "retrying" ? 2 + statusLabel.length : status === "asking" ? 3 : status ? 2 : 0;
|
|
2330
2638
|
if (hW + sW + (rightW > 0 ? rightW + 1 : 0) <= inner) return /* @__PURE__ */ jsxs("box", {
|
|
2331
2639
|
style: {
|
|
2332
2640
|
flexDirection: "row",
|
|
@@ -2343,7 +2651,8 @@ function Footer({ hints, context, cost = null, status = null, compactionTokens =
|
|
|
2343
2651
|
/* @__PURE__ */ jsx$1("box", { style: { flexGrow: 1 } }),
|
|
2344
2652
|
/* @__PURE__ */ jsx$1(RightStatus, {
|
|
2345
2653
|
cost: showCost ? cost : null,
|
|
2346
|
-
context
|
|
2654
|
+
context,
|
|
2655
|
+
contextKey: contextKey ?? null
|
|
2347
2656
|
})
|
|
2348
2657
|
]
|
|
2349
2658
|
});
|
|
@@ -2370,22 +2679,43 @@ function Footer({ hints, context, cost = null, status = null, compactionTokens =
|
|
|
2370
2679
|
},
|
|
2371
2680
|
children: [/* @__PURE__ */ jsx$1("box", { style: { flexGrow: 1 } }), /* @__PURE__ */ jsx$1(RightStatus, {
|
|
2372
2681
|
cost: showCost ? cost : null,
|
|
2373
|
-
context
|
|
2682
|
+
context,
|
|
2683
|
+
contextKey: contextKey ?? null
|
|
2374
2684
|
})]
|
|
2375
2685
|
})]
|
|
2376
2686
|
});
|
|
2377
2687
|
}
|
|
2378
|
-
function RightStatus({ cost, context }) {
|
|
2688
|
+
function RightStatus({ cost, context, contextKey }) {
|
|
2379
2689
|
const COLOR = useColors();
|
|
2690
|
+
const renderer = useRenderer();
|
|
2691
|
+
const [hovered, setHovered] = useState(false);
|
|
2380
2692
|
if (cost == null && !context) return null;
|
|
2381
|
-
|
|
2382
|
-
cost != null && /* @__PURE__ */ jsx$1(CostIndicator, {
|
|
2693
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2694
|
+
cost != null && /* @__PURE__ */ jsx$1(CostIndicator, {
|
|
2695
|
+
cost,
|
|
2696
|
+
accent: hovered
|
|
2697
|
+
}),
|
|
2383
2698
|
cost != null && context && /* @__PURE__ */ jsx$1("span", {
|
|
2384
2699
|
fg: COLOR.mute,
|
|
2385
2700
|
children: " · "
|
|
2386
2701
|
}),
|
|
2387
|
-
context && /* @__PURE__ */ jsx$1(ContextIndicator, {
|
|
2702
|
+
context && /* @__PURE__ */ jsx$1(ContextIndicator, {
|
|
2703
|
+
context,
|
|
2704
|
+
accent: hovered
|
|
2705
|
+
})
|
|
2388
2706
|
] });
|
|
2707
|
+
if (!(contextKey !== null && parseHintKeySpec(contextKey) !== null)) return /* @__PURE__ */ jsx$1("text", { children: body });
|
|
2708
|
+
return /* @__PURE__ */ jsx$1("text", {
|
|
2709
|
+
selectable: false,
|
|
2710
|
+
onMouseDown: (event) => {
|
|
2711
|
+
event.stopPropagation();
|
|
2712
|
+
event.preventDefault();
|
|
2713
|
+
dispatchHintKey(renderer, contextKey);
|
|
2714
|
+
},
|
|
2715
|
+
onMouseOver: () => setHovered(true),
|
|
2716
|
+
onMouseOut: () => setHovered(false),
|
|
2717
|
+
children: body
|
|
2718
|
+
});
|
|
2389
2719
|
}
|
|
2390
2720
|
/**
|
|
2391
2721
|
* Right-edge status in the Footer's left section. Busy stays glyph-only;
|
|
@@ -2395,17 +2725,25 @@ function RightStatus({ cost, context }) {
|
|
|
2395
2725
|
function FooterStatusIcon({ status, label = "" }) {
|
|
2396
2726
|
const COLOR = useColors();
|
|
2397
2727
|
if (!status) return null;
|
|
2398
|
-
const glyph = status === "asking" ? /* @__PURE__ */ jsx$1("span", { children: "❓" }) : status === "busy" ? /* @__PURE__ */ jsx$1(StatusSpinner, { color: COLOR.warn }) : /* @__PURE__ */ jsx$1(StatusSpinner, { color: COLOR.accent });
|
|
2728
|
+
const glyph = status === "asking" ? /* @__PURE__ */ jsx$1("span", { children: "❓" }) : status === "busy" || status === "retrying" ? /* @__PURE__ */ jsx$1(StatusSpinner, { color: COLOR.warn }) : /* @__PURE__ */ jsx$1(StatusSpinner, { color: COLOR.accent });
|
|
2399
2729
|
return /* @__PURE__ */ jsxs("text", { children: [
|
|
2400
2730
|
/* @__PURE__ */ jsx$1("span", { children: " " }),
|
|
2401
2731
|
glyph,
|
|
2402
2732
|
label && /* @__PURE__ */ jsx$1("span", {
|
|
2403
|
-
fg: COLOR.accent,
|
|
2733
|
+
fg: status === "retrying" ? COLOR.warn : COLOR.accent,
|
|
2404
2734
|
children: label
|
|
2405
2735
|
})
|
|
2406
2736
|
] });
|
|
2407
2737
|
}
|
|
2408
2738
|
/**
|
|
2739
|
+
* Footer label for the retrying state — ` Retrying (n/max)...` where `n`
|
|
2740
|
+
* is the attempt about to be issued. Plain string for the same width-math
|
|
2741
|
+
* reason as {@link compactingLabel}.
|
|
2742
|
+
*/
|
|
2743
|
+
function retryingLabel(retry) {
|
|
2744
|
+
return retry ? ` Retrying (${retry.attempt}/${retry.max})...` : " Retrying...";
|
|
2745
|
+
}
|
|
2746
|
+
/**
|
|
2409
2747
|
* Footer label for the compacting state — ` Compacting...` plus liveness:
|
|
2410
2748
|
* a `~2.1k` output-token estimate once the summary streams, and an elapsed
|
|
2411
2749
|
* suffix while it doesn't (prompt ingestion is minutes of silence on
|
|
@@ -2419,11 +2757,7 @@ function compactingLabel(estTokens, startedAt) {
|
|
|
2419
2757
|
return typeof estTokens === "number" && estTokens > 0 ? `${base} ~${fmtTokens(estTokens)}${elapsed}` : `${base}${elapsed}`;
|
|
2420
2758
|
}
|
|
2421
2759
|
function HintsText({ hints }) {
|
|
2422
|
-
|
|
2423
|
-
return /* @__PURE__ */ jsx$1("text", {
|
|
2424
|
-
fg: COLOR.dim,
|
|
2425
|
-
children: renderHintSpans(hints, COLOR)
|
|
2426
|
-
});
|
|
2760
|
+
return /* @__PURE__ */ jsx$1(HintRow, { hints });
|
|
2427
2761
|
}
|
|
2428
2762
|
/**
|
|
2429
2763
|
* Pure renderer for a list of {@link Hint}s as colored spans —
|
|
@@ -2463,14 +2797,15 @@ function renderHintSpans(hints, COLOR) {
|
|
|
2463
2797
|
})
|
|
2464
2798
|
] }, i));
|
|
2465
2799
|
}
|
|
2466
|
-
function ContextIndicator({ context }) {
|
|
2800
|
+
function ContextIndicator({ context, accent = false }) {
|
|
2467
2801
|
const COLOR = useColors();
|
|
2468
2802
|
const ratio = context.max > 0 ? context.used / context.max : 0;
|
|
2469
2803
|
const pct = Math.round(ratio * 100);
|
|
2470
|
-
const color = ratio >= .85 ? COLOR.error : ratio >= .6 ? COLOR.warn : COLOR.dim;
|
|
2804
|
+
const color = accent ? COLOR.accent : ratio >= .85 ? COLOR.error : ratio >= .6 ? COLOR.warn : COLOR.dim;
|
|
2805
|
+
const muted = accent ? COLOR.accent : COLOR.mute;
|
|
2471
2806
|
return /* @__PURE__ */ jsxs("span", { children: [
|
|
2472
2807
|
/* @__PURE__ */ jsx$1("span", {
|
|
2473
|
-
fg:
|
|
2808
|
+
fg: muted,
|
|
2474
2809
|
children: "ctx "
|
|
2475
2810
|
}),
|
|
2476
2811
|
/* @__PURE__ */ jsx$1("span", {
|
|
@@ -2478,7 +2813,7 @@ function ContextIndicator({ context }) {
|
|
|
2478
2813
|
children: fmtTokens(context.used)
|
|
2479
2814
|
}),
|
|
2480
2815
|
/* @__PURE__ */ jsx$1("span", {
|
|
2481
|
-
fg:
|
|
2816
|
+
fg: muted,
|
|
2482
2817
|
children: ` / ${fmtTokens(context.max)} `
|
|
2483
2818
|
}),
|
|
2484
2819
|
/* @__PURE__ */ jsx$1("span", {
|
|
@@ -2487,11 +2822,11 @@ function ContextIndicator({ context }) {
|
|
|
2487
2822
|
})
|
|
2488
2823
|
] });
|
|
2489
2824
|
}
|
|
2490
|
-
function CostIndicator({ cost }) {
|
|
2825
|
+
function CostIndicator({ cost, accent = false }) {
|
|
2491
2826
|
const COLOR = useColors();
|
|
2492
|
-
const fg = COLOR.money ?? COLOR.warn;
|
|
2827
|
+
const fg = accent ? COLOR.accent : COLOR.money ?? COLOR.warn;
|
|
2493
2828
|
return /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx$1("span", {
|
|
2494
|
-
fg: COLOR.mute,
|
|
2829
|
+
fg: accent ? COLOR.accent : COLOR.mute,
|
|
2495
2830
|
children: "$"
|
|
2496
2831
|
}), /* @__PURE__ */ jsx$1("span", {
|
|
2497
2832
|
fg,
|
|
@@ -2560,8 +2895,11 @@ function renderGradientText(text, from, to) {
|
|
|
2560
2895
|
* </box>
|
|
2561
2896
|
* ```
|
|
2562
2897
|
*/
|
|
2563
|
-
function TitleOverlay({ title, meta = null, titleColor, parentWidth, statusIcon = null, statusIconCells = 1 }) {
|
|
2898
|
+
function TitleOverlay({ title, meta = null, titleColor, parentWidth, statusIcon = null, statusIconCells = 1, clickKey = null }) {
|
|
2564
2899
|
const COLOR = useColors();
|
|
2900
|
+
const renderer = useRenderer();
|
|
2901
|
+
const [titleHovered, setTitleHovered] = useState(false);
|
|
2902
|
+
const clickable = clickKey !== null && parseHintKeySpec(clickKey) !== null;
|
|
2565
2903
|
const { width: termWidth } = useTerminalDimensions();
|
|
2566
2904
|
const useGradient = titleColor === void 0;
|
|
2567
2905
|
const gradientFrom = COLOR.throbber?.to ?? COLOR.accent;
|
|
@@ -2574,32 +2912,51 @@ function TitleOverlay({ title, meta = null, titleColor, parentWidth, statusIcon
|
|
|
2574
2912
|
const showMeta = meta != null && metaLen > 0 && title.length + iconReserve + TITLE_OVERLAY_WRAP + TITLE_OVERLAY_GAP + metaLen + TITLE_OVERLAY_META_WRAP <= inner;
|
|
2575
2913
|
const titleBudget = (showMeta ? inner - (metaLen + TITLE_OVERLAY_META_WRAP) - TITLE_OVERLAY_GAP - TITLE_OVERLAY_WRAP : inner - TITLE_OVERLAY_WRAP) - iconReserve;
|
|
2576
2914
|
const visibleTitle = titleBudget <= 0 ? "" : truncateTrailing(title, titleBudget);
|
|
2577
|
-
|
|
2915
|
+
const titleBody = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2916
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
2917
|
+
fg: COLOR.mute,
|
|
2918
|
+
children: " "
|
|
2919
|
+
}),
|
|
2920
|
+
titleHovered ? /* @__PURE__ */ jsx$1("span", {
|
|
2921
|
+
fg: COLOR.accent,
|
|
2922
|
+
children: visibleTitle
|
|
2923
|
+
}) : useGradient && visibleTitle.length > 0 ? renderGradientText(visibleTitle, gradientFrom, gradientTo) : /* @__PURE__ */ jsx$1("span", {
|
|
2924
|
+
fg,
|
|
2925
|
+
children: visibleTitle
|
|
2926
|
+
}),
|
|
2927
|
+
statusIcon && /* @__PURE__ */ jsx$1("span", {
|
|
2928
|
+
fg: COLOR.mute,
|
|
2929
|
+
children: " "
|
|
2930
|
+
}),
|
|
2931
|
+
statusIcon,
|
|
2932
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
2933
|
+
fg: COLOR.mute,
|
|
2934
|
+
children: " "
|
|
2935
|
+
})
|
|
2936
|
+
] });
|
|
2937
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [(visibleTitle || statusIcon) && (clickable ? /* @__PURE__ */ jsx$1("text", {
|
|
2578
2938
|
style: {
|
|
2579
2939
|
position: "absolute",
|
|
2580
2940
|
top: 0,
|
|
2581
2941
|
left: 1
|
|
2582
2942
|
},
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
})
|
|
2601
|
-
]
|
|
2602
|
-
}), showMeta && meta && /* @__PURE__ */ jsxs("text", {
|
|
2943
|
+
selectable: false,
|
|
2944
|
+
onMouseDown: (event) => {
|
|
2945
|
+
event.stopPropagation();
|
|
2946
|
+
event.preventDefault();
|
|
2947
|
+
dispatchHintKey(renderer, clickKey);
|
|
2948
|
+
},
|
|
2949
|
+
onMouseOver: () => setTitleHovered(true),
|
|
2950
|
+
onMouseOut: () => setTitleHovered(false),
|
|
2951
|
+
children: titleBody
|
|
2952
|
+
}) : /* @__PURE__ */ jsx$1("text", {
|
|
2953
|
+
style: {
|
|
2954
|
+
position: "absolute",
|
|
2955
|
+
top: 0,
|
|
2956
|
+
left: 1
|
|
2957
|
+
},
|
|
2958
|
+
children: titleBody
|
|
2959
|
+
})), showMeta && meta && /* @__PURE__ */ jsxs("text", {
|
|
2603
2960
|
style: {
|
|
2604
2961
|
position: "absolute",
|
|
2605
2962
|
top: 0,
|
|
@@ -2691,14 +3048,79 @@ function StatusSpinner({ color }) {
|
|
|
2691
3048
|
children: useSpinnerFrame()
|
|
2692
3049
|
});
|
|
2693
3050
|
}
|
|
2694
|
-
|
|
3051
|
+
/**
|
|
3052
|
+
* Bordered container for one run of subagent events. The box's border +
|
|
3053
|
+
* left padding give the visual "this is a subagent" affordance, so events
|
|
3054
|
+
* inside render with `depthOffset: 1` — a direct child of the parent
|
|
3055
|
+
* (depth 1) sits flush against the box's inner padding rather than being
|
|
3056
|
+
* indented twice. Grandchildren (depth ≥ 2) still indent further, so
|
|
3057
|
+
* nested subagents remain visually distinct.
|
|
3058
|
+
*
|
|
3059
|
+
* Memoized like {@link EventLine} so completed historical runs don't
|
|
3060
|
+
* re-execute per drain tick — but with a custom comparator:
|
|
3061
|
+
* `partitionTranscript` / `computeTurnAnchors` rebuild the per-run
|
|
3062
|
+
* `events` / `anchorIds` arrays on every transcript change, so the default
|
|
3063
|
+
* shallow compare would never bail while streaming. The inner event
|
|
3064
|
+
* references (and the deterministic anchor-id strings) ARE stable until
|
|
3065
|
+
* their content changes, so an element-wise compare recovers the bail-out.
|
|
3066
|
+
*/
|
|
3067
|
+
const SubagentBlock = memo(({ events, previous, selectedTurnId = null, anchorIds, codeSettleTargets, codeSettleEpoch = 0, live, searchQuery, searchTitleMatches }) => {
|
|
2695
3068
|
const COLOR = useColors();
|
|
2696
|
-
const
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
3069
|
+
const childIds = useMemo(() => {
|
|
3070
|
+
const set = /* @__PURE__ */ new Set();
|
|
3071
|
+
for (const e of events) if (e.childId) set.add(e.childId);
|
|
3072
|
+
return Array.from(set);
|
|
3073
|
+
}, [events]);
|
|
3074
|
+
const title = childIds.length === 0 ? " subagent " : childIds.length === 1 ? ` ${childIds[0]} ` : ` subagents · ${childIds.join(", ")} `;
|
|
3075
|
+
const marginTop = previous ? 1 : 0;
|
|
3076
|
+
const hideChildLabel = childIds.length === 1;
|
|
3077
|
+
return /* @__PURE__ */ jsx$1("box", {
|
|
3078
|
+
title,
|
|
3079
|
+
style: {
|
|
3080
|
+
border: true,
|
|
3081
|
+
borderColor: COLOR.brand,
|
|
3082
|
+
paddingLeft: 1,
|
|
3083
|
+
paddingRight: 1,
|
|
3084
|
+
paddingTop: 0,
|
|
3085
|
+
paddingBottom: 0,
|
|
3086
|
+
marginTop,
|
|
3087
|
+
flexDirection: "column",
|
|
3088
|
+
flexShrink: 0,
|
|
3089
|
+
alignSelf: "stretch"
|
|
3090
|
+
},
|
|
3091
|
+
children: events.map((evt, i) => /* @__PURE__ */ jsx$1(EventLine, {
|
|
3092
|
+
event: evt,
|
|
3093
|
+
previous: events[i - 1],
|
|
3094
|
+
depthOffset: 1,
|
|
3095
|
+
selected: selectedTurnId !== null && evt.turnId === selectedTurnId,
|
|
3096
|
+
anchorId: anchorIds?.[i],
|
|
3097
|
+
hideChildLabel,
|
|
3098
|
+
settleCodeEpoch: codeSettleTargets?.has(evt) ? codeSettleEpoch : 0,
|
|
3099
|
+
liveSpawn: evt.kind === "spawn-start" ? live?.find((spawn) => spawn.id === evt.childId) : void 0,
|
|
3100
|
+
searchQuery,
|
|
3101
|
+
searchTitleMatch: evt.kind === "tool" && evt.callId !== void 0 && searchTitleMatches?.callIds.has(evt.callId) || (evt.kind === "spawn-start" || evt.kind === "spawn-end") && evt.childId !== void 0 && searchTitleMatches?.childIds.has(evt.childId)
|
|
3102
|
+
}, i))
|
|
3103
|
+
});
|
|
3104
|
+
}, (prev, next) => sameElements(prev.events, next.events) && sameElements(prev.anchorIds, next.anchorIds) && prev.previous === next.previous && prev.selectedTurnId === next.selectedTurnId && prev.codeSettleTargets === next.codeSettleTargets && prev.codeSettleEpoch === next.codeSettleEpoch && prev.live === next.live && prev.searchQuery === next.searchQuery && prev.searchTitleMatches === next.searchTitleMatches);
|
|
3105
|
+
/** Element-wise `===` over possibly-rebuilt arrays — see {@link SubagentBlock}. */
|
|
3106
|
+
function sameElements(a, b) {
|
|
3107
|
+
if (a === b) return true;
|
|
3108
|
+
if (!a || !b || a.length !== b.length) return false;
|
|
3109
|
+
return a.every((value, i) => value === b[i]);
|
|
3110
|
+
}
|
|
3111
|
+
const NO_SEARCH_MATCHES = {
|
|
3112
|
+
direct: /* @__PURE__ */ new Set(),
|
|
3113
|
+
callIds: /* @__PURE__ */ new Set(),
|
|
3114
|
+
childIds: /* @__PURE__ */ new Set()
|
|
3115
|
+
};
|
|
3116
|
+
function Transcript({ events, settings, selectedTurnId = null, busy = false, searchQuery, searchPending = false, onLoadEarlier, onSelectTurn, onOpenTurn }) {
|
|
3117
|
+
const COLOR = useColors();
|
|
3118
|
+
const showThrobber = busy && settings.showThrobber;
|
|
3119
|
+
const codeSettle = useRef({
|
|
3120
|
+
wasBusy: false,
|
|
3121
|
+
epoch: 0,
|
|
3122
|
+
activeTargets: /* @__PURE__ */ new Set(),
|
|
3123
|
+
targets: /* @__PURE__ */ new Set()
|
|
2702
3124
|
});
|
|
2703
3125
|
const lastUserPromptIndex = events.findLastIndex((event) => event.kind === "user-prompt");
|
|
2704
3126
|
if (busy) {
|
|
@@ -2716,14 +3138,10 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false, sea
|
|
|
2716
3138
|
const throbberLabel = events.length > 0 && events[events.length - 1].kind === "thinking" ? "Thinking" : void 0;
|
|
2717
3139
|
const ownership = useMemo(() => turnSelectionOwnership(events), [events]);
|
|
2718
3140
|
const searchMatches = useMemo(() => {
|
|
3141
|
+
if (!searchQuery) return NO_SEARCH_MATCHES;
|
|
2719
3142
|
const direct = /* @__PURE__ */ new Set();
|
|
2720
3143
|
const callIds = /* @__PURE__ */ new Set();
|
|
2721
3144
|
const childIds = /* @__PURE__ */ new Set();
|
|
2722
|
-
if (!searchQuery) return {
|
|
2723
|
-
direct,
|
|
2724
|
-
callIds,
|
|
2725
|
-
childIds
|
|
2726
|
-
};
|
|
2727
3145
|
const stack = [];
|
|
2728
3146
|
for (const event of events) {
|
|
2729
3147
|
if (event.kind === "spawn-start") stack.push(event);
|
|
@@ -2752,9 +3170,13 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false, sea
|
|
|
2752
3170
|
searchMatches
|
|
2753
3171
|
]);
|
|
2754
3172
|
const scrollboxRef = useRef(null);
|
|
3173
|
+
const mouseSelectionRef = useRef(false);
|
|
3174
|
+
const pressedTurnRef = useRef(null);
|
|
2755
3175
|
const rowVisibility = useRef(createRowVisibilityStore());
|
|
2756
3176
|
const loadEarlierRef = useRef(onLoadEarlier);
|
|
2757
3177
|
loadEarlierRef.current = onLoadEarlier;
|
|
3178
|
+
const eventsRef = useRef(events);
|
|
3179
|
+
eventsRef.current = events;
|
|
2758
3180
|
const earlierLoad = useRef(null);
|
|
2759
3181
|
const earlierLoadArmed = useRef(false);
|
|
2760
3182
|
useEffect(() => {
|
|
@@ -2767,7 +3189,7 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false, sea
|
|
|
2767
3189
|
});
|
|
2768
3190
|
const topThreshold = Math.max(4, Math.floor(sb.viewport.height / 4));
|
|
2769
3191
|
if (sb.scrollTop > topThreshold) earlierLoadArmed.current = true;
|
|
2770
|
-
else if (earlierLoadArmed.current && !earlierLoad.current && loadEarlierRef.current && hiddenEarlierTranscriptCount(
|
|
3192
|
+
else if (earlierLoadArmed.current && !earlierLoad.current && loadEarlierRef.current && hiddenEarlierTranscriptCount(eventsRef.current) > 0) {
|
|
2771
3193
|
earlierLoadArmed.current = false;
|
|
2772
3194
|
const snapshot = {
|
|
2773
3195
|
oldHeight: sb.scrollHeight,
|
|
@@ -2781,7 +3203,7 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false, sea
|
|
|
2781
3203
|
}
|
|
2782
3204
|
}, 200);
|
|
2783
3205
|
return () => clearInterval(timer);
|
|
2784
|
-
}, [
|
|
3206
|
+
}, []);
|
|
2785
3207
|
useEffect(() => {
|
|
2786
3208
|
const pending = earlierLoad.current;
|
|
2787
3209
|
if (!pending) return;
|
|
@@ -2835,6 +3257,10 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false, sea
|
|
|
2835
3257
|
}, [items, events]);
|
|
2836
3258
|
useEffect(() => {
|
|
2837
3259
|
if (!selectedTurnId) return;
|
|
3260
|
+
if (mouseSelectionRef.current) {
|
|
3261
|
+
mouseSelectionRef.current = false;
|
|
3262
|
+
return;
|
|
3263
|
+
}
|
|
2838
3264
|
let handle = 0;
|
|
2839
3265
|
let attempts = 0;
|
|
2840
3266
|
const align = () => {
|
|
@@ -2895,7 +3321,7 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false, sea
|
|
|
2895
3321
|
children: [items.map((item, i) => {
|
|
2896
3322
|
if (item.kind === "event") {
|
|
2897
3323
|
const live = liveByItem.get(i);
|
|
2898
|
-
|
|
3324
|
+
const line = /* @__PURE__ */ jsx$1(EventLine, {
|
|
2899
3325
|
event: item.event,
|
|
2900
3326
|
previous: item.previous,
|
|
2901
3327
|
selected: isTurnHighlighted(item.event, selectedTurnId, ownership),
|
|
@@ -2904,6 +3330,33 @@ function Transcript({ events, settings, selectedTurnId = null, busy = false, sea
|
|
|
2904
3330
|
liveSpawn: live?.[0],
|
|
2905
3331
|
searchQuery,
|
|
2906
3332
|
searchTitleMatch: item.event.kind === "tool" && item.event.callId !== void 0 && searchMatches.callIds.has(item.event.callId) || (item.event.kind === "spawn-start" || item.event.kind === "spawn-end") && item.event.childId !== void 0 && searchMatches.childIds.has(item.event.childId)
|
|
3333
|
+
});
|
|
3334
|
+
const selectActive = selectedTurnId !== null && (onSelectTurn !== void 0 || onOpenTurn !== void 0);
|
|
3335
|
+
const targetTurn = item.event.turnId && !item.event.childId ? ownership.get(item.event.turnId) ?? item.event.turnId : null;
|
|
3336
|
+
const active = selectActive && targetTurn !== null;
|
|
3337
|
+
return /* @__PURE__ */ jsx$1("box", {
|
|
3338
|
+
style: { flexDirection: "column" },
|
|
3339
|
+
onMouseOver: active ? () => {
|
|
3340
|
+
if (targetTurn === selectedTurnId) return;
|
|
3341
|
+
if (onSelectTurn?.(targetTurn) !== false) mouseSelectionRef.current = true;
|
|
3342
|
+
} : void 0,
|
|
3343
|
+
onMouseDown: active && onOpenTurn ? (event) => {
|
|
3344
|
+
pressedTurnRef.current = event.button === 0 ? {
|
|
3345
|
+
turnId: targetTurn,
|
|
3346
|
+
x: event.x,
|
|
3347
|
+
y: event.y
|
|
3348
|
+
} : null;
|
|
3349
|
+
} : void 0,
|
|
3350
|
+
onMouseUp: active && onOpenTurn ? (event) => {
|
|
3351
|
+
const pressed = pressedTurnRef.current;
|
|
3352
|
+
pressedTurnRef.current = null;
|
|
3353
|
+
if (event.button !== 0 || pressed === null || pressed.turnId !== targetTurn) return;
|
|
3354
|
+
if (pressed.x !== event.x || pressed.y !== event.y) return;
|
|
3355
|
+
event.stopPropagation();
|
|
3356
|
+
event.preventDefault();
|
|
3357
|
+
if (onOpenTurn(targetTurn) !== false && targetTurn !== selectedTurnId) mouseSelectionRef.current = true;
|
|
3358
|
+
} : void 0,
|
|
3359
|
+
children: line
|
|
2907
3360
|
}, i);
|
|
2908
3361
|
}
|
|
2909
3362
|
return /* @__PURE__ */ jsx$1(SubagentBlock, {
|
|
@@ -3051,52 +3504,6 @@ function partitionTranscript(events, settings, searchReveal) {
|
|
|
3051
3504
|
return items;
|
|
3052
3505
|
}
|
|
3053
3506
|
/**
|
|
3054
|
-
* Bordered container for one run of subagent events. The box's border +
|
|
3055
|
-
* left padding give the visual "this is a subagent" affordance, so events
|
|
3056
|
-
* inside render with `depthOffset: 1` — a direct child of the parent
|
|
3057
|
-
* (depth 1) sits flush against the box's inner padding rather than being
|
|
3058
|
-
* indented twice. Grandchildren (depth ≥ 2) still indent further, so
|
|
3059
|
-
* nested subagents remain visually distinct.
|
|
3060
|
-
*/
|
|
3061
|
-
function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds, codeSettleTargets, codeSettleEpoch = 0, live, searchQuery, searchTitleMatches }) {
|
|
3062
|
-
const COLOR = useColors();
|
|
3063
|
-
const childIds = useMemo(() => {
|
|
3064
|
-
const set = /* @__PURE__ */ new Set();
|
|
3065
|
-
for (const e of events) if (e.childId) set.add(e.childId);
|
|
3066
|
-
return Array.from(set);
|
|
3067
|
-
}, [events]);
|
|
3068
|
-
const title = childIds.length === 0 ? " subagent " : childIds.length === 1 ? ` ${childIds[0]} ` : ` subagents · ${childIds.join(", ")} `;
|
|
3069
|
-
const marginTop = previous ? 1 : 0;
|
|
3070
|
-
const hideChildLabel = childIds.length === 1;
|
|
3071
|
-
return /* @__PURE__ */ jsx$1("box", {
|
|
3072
|
-
title,
|
|
3073
|
-
style: {
|
|
3074
|
-
border: true,
|
|
3075
|
-
borderColor: COLOR.brand,
|
|
3076
|
-
paddingLeft: 1,
|
|
3077
|
-
paddingRight: 1,
|
|
3078
|
-
paddingTop: 0,
|
|
3079
|
-
paddingBottom: 0,
|
|
3080
|
-
marginTop,
|
|
3081
|
-
flexDirection: "column",
|
|
3082
|
-
flexShrink: 0,
|
|
3083
|
-
alignSelf: "stretch"
|
|
3084
|
-
},
|
|
3085
|
-
children: events.map((evt, i) => /* @__PURE__ */ jsx$1(EventLine, {
|
|
3086
|
-
event: evt,
|
|
3087
|
-
previous: events[i - 1],
|
|
3088
|
-
depthOffset: 1,
|
|
3089
|
-
selected: selectedTurnId !== null && evt.turnId === selectedTurnId,
|
|
3090
|
-
anchorId: anchorIds?.[i],
|
|
3091
|
-
hideChildLabel,
|
|
3092
|
-
settleCodeEpoch: codeSettleTargets?.has(evt) ? codeSettleEpoch : 0,
|
|
3093
|
-
liveSpawn: evt.kind === "spawn-start" ? live?.find((spawn) => spawn.id === evt.childId) : void 0,
|
|
3094
|
-
searchQuery,
|
|
3095
|
-
searchTitleMatch: evt.kind === "tool" && evt.callId !== void 0 && searchTitleMatches?.callIds.has(evt.callId) || (evt.kind === "spawn-start" || evt.kind === "spawn-end") && evt.childId !== void 0 && searchTitleMatches?.childIds.has(evt.childId)
|
|
3096
|
-
}, i))
|
|
3097
|
-
});
|
|
3098
|
-
}
|
|
3099
|
-
/**
|
|
3100
3507
|
* Stable one-row subagent lifecycle layout. Identity/model/task stay in
|
|
3101
3508
|
* the left lane for the whole run; only the right tail changes:
|
|
3102
3509
|
* active `2 turns · 14s · ⠋ tool call`, done `4 turns`.
|
|
@@ -4716,29 +5123,23 @@ function ContextPanelModal({ breakdown, modelUsage }) {
|
|
|
4716
5123
|
children: "~"
|
|
4717
5124
|
}), " estimated — exact counts unavailable for this provider"]
|
|
4718
5125
|
}),
|
|
4719
|
-
/* @__PURE__ */ jsx$1(
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
" close"
|
|
4737
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx$1("span", {
|
|
4738
|
-
fg: COLOR.warn,
|
|
4739
|
-
children: "esc"
|
|
4740
|
-
}), " close"] })
|
|
4741
|
-
})
|
|
5126
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
5127
|
+
expandableIds.length > 0 && {
|
|
5128
|
+
key: "↑↓",
|
|
5129
|
+
label: "navigate",
|
|
5130
|
+
labelColor: COLOR.dim
|
|
5131
|
+
},
|
|
5132
|
+
expandableIds.length > 0 && {
|
|
5133
|
+
key: "↵/space",
|
|
5134
|
+
label: "expand",
|
|
5135
|
+
labelColor: COLOR.dim
|
|
5136
|
+
},
|
|
5137
|
+
{
|
|
5138
|
+
key: "esc",
|
|
5139
|
+
label: "close",
|
|
5140
|
+
labelColor: COLOR.dim
|
|
5141
|
+
}
|
|
5142
|
+
] })
|
|
4742
5143
|
]
|
|
4743
5144
|
});
|
|
4744
5145
|
}
|
|
@@ -5247,26 +5648,23 @@ function CreateExtensionModal({ userRoot, projectRoot, loadProjectExtensions, on
|
|
|
5247
5648
|
fg: COLOR.error,
|
|
5248
5649
|
children: error
|
|
5249
5650
|
}),
|
|
5250
|
-
/* @__PURE__ */
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
" cancel"
|
|
5268
|
-
]
|
|
5269
|
-
})
|
|
5651
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
5652
|
+
{
|
|
5653
|
+
key: "tab",
|
|
5654
|
+
label: "scope",
|
|
5655
|
+
labelColor: COLOR.dim
|
|
5656
|
+
},
|
|
5657
|
+
{
|
|
5658
|
+
key: "↵",
|
|
5659
|
+
label: "create",
|
|
5660
|
+
labelColor: COLOR.dim
|
|
5661
|
+
},
|
|
5662
|
+
{
|
|
5663
|
+
key: "esc",
|
|
5664
|
+
label: "cancel",
|
|
5665
|
+
labelColor: COLOR.dim
|
|
5666
|
+
}
|
|
5667
|
+
] })
|
|
5270
5668
|
]
|
|
5271
5669
|
});
|
|
5272
5670
|
}
|
|
@@ -5575,40 +5973,37 @@ function CwdPickerModal({ currentCwd, onPick }) {
|
|
|
5575
5973
|
}, result.item.path);
|
|
5576
5974
|
})
|
|
5577
5975
|
}),
|
|
5578
|
-
/* @__PURE__ */
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
})
|
|
5610
|
-
]
|
|
5611
|
-
})
|
|
5976
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
5977
|
+
{
|
|
5978
|
+
key: "↑↓",
|
|
5979
|
+
label: "navigate",
|
|
5980
|
+
labelColor: COLOR.dim
|
|
5981
|
+
},
|
|
5982
|
+
{
|
|
5983
|
+
key: "tab",
|
|
5984
|
+
label: "enter dir",
|
|
5985
|
+
labelColor: COLOR.dim
|
|
5986
|
+
},
|
|
5987
|
+
{
|
|
5988
|
+
key: "←",
|
|
5989
|
+
label: "parent",
|
|
5990
|
+
labelColor: COLOR.dim
|
|
5991
|
+
},
|
|
5992
|
+
{
|
|
5993
|
+
key: "↵",
|
|
5994
|
+
label: "select",
|
|
5995
|
+
labelColor: COLOR.dim
|
|
5996
|
+
},
|
|
5997
|
+
{
|
|
5998
|
+
key: "esc",
|
|
5999
|
+
label: "close",
|
|
6000
|
+
labelColor: COLOR.dim
|
|
6001
|
+
},
|
|
6002
|
+
{
|
|
6003
|
+
key: "",
|
|
6004
|
+
label: `${results.length} match${results.length === 1 ? "" : "es"}`
|
|
6005
|
+
}
|
|
6006
|
+
] })
|
|
5612
6007
|
]
|
|
5613
6008
|
});
|
|
5614
6009
|
}
|
|
@@ -5895,6 +6290,21 @@ async function resolveExtensionModalNode(node) {
|
|
|
5895
6290
|
let nextClientId = 1;
|
|
5896
6291
|
/** Mirror of the TUI's ZIDANE_DEBUG-gated logger — silent by default. */
|
|
5897
6292
|
const debugFallback = process.env.ZIDANE_DEBUG ? (op, error) => console.error(`[zidane/tui] history search ${op} fell back to the main thread:`, error) : () => {};
|
|
6293
|
+
/**
|
|
6294
|
+
* Rough searchable-size estimate for degraded builds — string block
|
|
6295
|
+
* payloads only, mirroring what index extraction keeps (attachments /
|
|
6296
|
+
* base64 are stripped there). Cheap enough to run inline; only feeds the
|
|
6297
|
+
* byte budget, so precision doesn't matter.
|
|
6298
|
+
*/
|
|
6299
|
+
function estimateTurnsBytes(turns) {
|
|
6300
|
+
let total = 0;
|
|
6301
|
+
for (const turn of turns) for (const block of turn.content) {
|
|
6302
|
+
const b = block;
|
|
6303
|
+
if (typeof b.text === "string") total += b.text.length;
|
|
6304
|
+
if (typeof b.output === "string") total += b.output.length;
|
|
6305
|
+
}
|
|
6306
|
+
return total;
|
|
6307
|
+
}
|
|
5898
6308
|
function workerUrl() {
|
|
5899
6309
|
if (typeof Bun !== "undefined" && Bun.isStandaloneExecutable) return new URL("./history-search-worker.ts", import.meta.url);
|
|
5900
6310
|
return new URL(import.meta.url.endsWith(".ts") ? "./history-search-worker.ts" : "./history-search-worker.js", import.meta.url);
|
|
@@ -5909,6 +6319,12 @@ var HistorySearchWorkerClient = class {
|
|
|
5909
6319
|
this.createWorker = createWorker;
|
|
5910
6320
|
}
|
|
5911
6321
|
indexes = /* @__PURE__ */ new WeakMap();
|
|
6322
|
+
/**
|
|
6323
|
+
* Handles whose index lives in the worker (a successful `build`). Only
|
|
6324
|
+
* these are safe to `slim()` — a degraded handle's turns are the sole
|
|
6325
|
+
* source for its main-thread fallback index.
|
|
6326
|
+
*/
|
|
6327
|
+
workerBuilt = /* @__PURE__ */ new WeakSet();
|
|
5912
6328
|
registrations = /* @__PURE__ */ new Map();
|
|
5913
6329
|
rebuilds = /* @__PURE__ */ new Map();
|
|
5914
6330
|
pending = /* @__PURE__ */ new Map();
|
|
@@ -5926,10 +6342,11 @@ var HistorySearchWorkerClient = class {
|
|
|
5926
6342
|
if (this.unavailable) return {
|
|
5927
6343
|
indexId,
|
|
5928
6344
|
length: turns.length,
|
|
6345
|
+
bytes: estimateTurnsBytes(turns),
|
|
5929
6346
|
turns
|
|
5930
6347
|
};
|
|
5931
6348
|
try {
|
|
5932
|
-
|
|
6349
|
+
const handle = {
|
|
5933
6350
|
...await this.request({
|
|
5934
6351
|
type: "build",
|
|
5935
6352
|
indexId,
|
|
@@ -5937,16 +6354,47 @@ var HistorySearchWorkerClient = class {
|
|
|
5937
6354
|
}, signal),
|
|
5938
6355
|
turns
|
|
5939
6356
|
};
|
|
6357
|
+
this.workerBuilt.add(handle);
|
|
6358
|
+
return handle;
|
|
5940
6359
|
} catch (error) {
|
|
5941
6360
|
if (signal?.aborted) throw signal.reason;
|
|
5942
6361
|
debugFallback("build", error);
|
|
5943
6362
|
return {
|
|
5944
6363
|
indexId,
|
|
5945
6364
|
length: turns.length,
|
|
6365
|
+
bytes: estimateTurnsBytes(turns),
|
|
5946
6366
|
turns
|
|
5947
6367
|
};
|
|
5948
6368
|
}
|
|
5949
6369
|
}
|
|
6370
|
+
/**
|
|
6371
|
+
* Drop the handle's main-thread turn retention once the worker owns the
|
|
6372
|
+
* index. Callers whose turns are alive anyway (live session, transcript
|
|
6373
|
+
* search) skip this; the cross-session cache calls it so 64 cached
|
|
6374
|
+
* handles don't pin 64 full sessions on the main thread. A slimmed
|
|
6375
|
+
* handle can't rebuild after a worker-side eviction — the caller is
|
|
6376
|
+
* expected to self-heal by rebuilding from the store on failure.
|
|
6377
|
+
*/
|
|
6378
|
+
slim(index) {
|
|
6379
|
+
if (!this.workerBuilt.has(index)) return;
|
|
6380
|
+
index.turns = void 0;
|
|
6381
|
+
}
|
|
6382
|
+
/**
|
|
6383
|
+
* Main-thread eviction notice: free the handle's retained data AND the
|
|
6384
|
+
* worker's cached index. Without this the worker kept its copy until
|
|
6385
|
+
* its own LRU happened to cycle it out. Fire-and-forget by design.
|
|
6386
|
+
*/
|
|
6387
|
+
release(index) {
|
|
6388
|
+
index.turns = void 0;
|
|
6389
|
+
index.fallback = void 0;
|
|
6390
|
+
if (!this.worker) return;
|
|
6391
|
+
try {
|
|
6392
|
+
this.worker.postMessage({
|
|
6393
|
+
type: "release",
|
|
6394
|
+
indexId: index.indexId
|
|
6395
|
+
});
|
|
6396
|
+
} catch {}
|
|
6397
|
+
}
|
|
5950
6398
|
async search(index, query, limit, signal) {
|
|
5951
6399
|
if (this.unavailable) return searchSessionIndexAsync(await this.fallbackIndex(index, signal), query, {
|
|
5952
6400
|
limit,
|
|
@@ -6016,6 +6464,7 @@ var HistorySearchWorkerClient = class {
|
|
|
6016
6464
|
rebuild(index) {
|
|
6017
6465
|
const inFlight = this.rebuilds.get(index.indexId);
|
|
6018
6466
|
if (inFlight) return inFlight;
|
|
6467
|
+
if (!index.turns) return Promise.reject(/* @__PURE__ */ new Error(`History search index released: ${index.indexId}`));
|
|
6019
6468
|
const rebuild = this.request({
|
|
6020
6469
|
type: "build",
|
|
6021
6470
|
indexId: index.indexId,
|
|
@@ -6026,10 +6475,13 @@ var HistorySearchWorkerClient = class {
|
|
|
6026
6475
|
}
|
|
6027
6476
|
fallbackIndex(index, signal) {
|
|
6028
6477
|
if (!("indexId" in index)) return Promise.resolve(index);
|
|
6029
|
-
if (!index.fallback)
|
|
6030
|
-
index.
|
|
6031
|
-
|
|
6032
|
-
|
|
6478
|
+
if (!index.fallback) {
|
|
6479
|
+
if (!index.turns) return Promise.reject(/* @__PURE__ */ new Error(`History search index released: ${index.indexId}`));
|
|
6480
|
+
index.fallback = buildSessionSearchIndexAsync(index.turns).catch((error) => {
|
|
6481
|
+
index.fallback = void 0;
|
|
6482
|
+
throw error;
|
|
6483
|
+
});
|
|
6484
|
+
}
|
|
6033
6485
|
signal?.throwIfAborted();
|
|
6034
6486
|
return index.fallback;
|
|
6035
6487
|
}
|
|
@@ -6085,6 +6537,10 @@ var HistorySearchWorkerClient = class {
|
|
|
6085
6537
|
}
|
|
6086
6538
|
});
|
|
6087
6539
|
this.registrations.set(indexId, registration);
|
|
6540
|
+
registration.catch(() => {
|
|
6541
|
+
this.registrations.delete(indexId);
|
|
6542
|
+
this.indexes.delete(index);
|
|
6543
|
+
});
|
|
6088
6544
|
return registration.then(() => indexId);
|
|
6089
6545
|
}
|
|
6090
6546
|
request(payload, signal) {
|
|
@@ -6455,26 +6911,23 @@ function ModelOptionsPickerModal({ supportsReasoning, supportsAdaptive, currentE
|
|
|
6455
6911
|
})]
|
|
6456
6912
|
}, `option:${row.option.id}`);
|
|
6457
6913
|
})]
|
|
6458
|
-
}), /* @__PURE__ */
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
" close"
|
|
6476
|
-
]
|
|
6477
|
-
})]
|
|
6914
|
+
}), /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
6915
|
+
{
|
|
6916
|
+
key: "↑↓",
|
|
6917
|
+
label: "navigate",
|
|
6918
|
+
labelColor: COLOR.dim
|
|
6919
|
+
},
|
|
6920
|
+
{
|
|
6921
|
+
key: "↵/space",
|
|
6922
|
+
label: "select/toggle",
|
|
6923
|
+
labelColor: COLOR.dim
|
|
6924
|
+
},
|
|
6925
|
+
{
|
|
6926
|
+
key: "esc",
|
|
6927
|
+
label: "close",
|
|
6928
|
+
labelColor: COLOR.dim
|
|
6929
|
+
}
|
|
6930
|
+
] })]
|
|
6478
6931
|
});
|
|
6479
6932
|
}
|
|
6480
6933
|
function SectionHeader({ label, color }) {
|
|
@@ -6795,38 +7248,37 @@ function ModelPickerModal({ providers, modelsFor, current, onPick, chain, onAppl
|
|
|
6795
7248
|
chainPosition: chainMode ? chainPositionOf(chainState, entry.providerKey, entry.model.id) : null
|
|
6796
7249
|
}, `${entry.providerKey}:${entry.model.id}`))
|
|
6797
7250
|
}),
|
|
6798
|
-
/* @__PURE__ */
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6821
|
-
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
})
|
|
7251
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
7252
|
+
{
|
|
7253
|
+
key: "↑↓",
|
|
7254
|
+
label: "navigate",
|
|
7255
|
+
labelColor: COLOR.dim
|
|
7256
|
+
},
|
|
7257
|
+
{
|
|
7258
|
+
key: "↵",
|
|
7259
|
+
label: chainMode ? "add/remove" : "select",
|
|
7260
|
+
labelColor: COLOR.dim
|
|
7261
|
+
},
|
|
7262
|
+
chainMode && {
|
|
7263
|
+
key: "ctrl+shift+↑↓",
|
|
7264
|
+
label: "reorder",
|
|
7265
|
+
labelColor: COLOR.dim
|
|
7266
|
+
},
|
|
7267
|
+
{
|
|
7268
|
+
key: "esc",
|
|
7269
|
+
label: chainMode ? "apply" : "close",
|
|
7270
|
+
labelColor: COLOR.dim
|
|
7271
|
+
},
|
|
7272
|
+
chainMode && {
|
|
7273
|
+
key: "",
|
|
7274
|
+
label: `${chainState.length} selected`,
|
|
7275
|
+
labelColor: COLOR.brand
|
|
7276
|
+
},
|
|
7277
|
+
{
|
|
7278
|
+
key: "",
|
|
7279
|
+
label: `${filtered.length} / ${catalog.length} model${catalog.length === 1 ? "" : "s"}`
|
|
7280
|
+
}
|
|
7281
|
+
] })
|
|
6830
7282
|
]
|
|
6831
7283
|
});
|
|
6832
7284
|
}
|
|
@@ -6987,38 +7439,37 @@ function ModelSelectList({ catalog, multi = false, initial, onApply, onCancel, v
|
|
|
6987
7439
|
chainPosition: multi ? picks.includes(entry.model.id) ? picks.indexOf(entry.model.id) + 1 : null : null
|
|
6988
7440
|
}, `${entry.providerKey}:${entry.model.id}`))
|
|
6989
7441
|
}),
|
|
6990
|
-
/* @__PURE__ */
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
})
|
|
7442
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
7443
|
+
{
|
|
7444
|
+
key: "↑↓",
|
|
7445
|
+
label: "navigate",
|
|
7446
|
+
labelColor: COLOR.dim
|
|
7447
|
+
},
|
|
7448
|
+
{
|
|
7449
|
+
key: "↵",
|
|
7450
|
+
label: multi ? "add/remove" : "select",
|
|
7451
|
+
labelColor: COLOR.dim
|
|
7452
|
+
},
|
|
7453
|
+
multi && {
|
|
7454
|
+
key: "ctrl+shift+↑↓",
|
|
7455
|
+
label: "reorder",
|
|
7456
|
+
labelColor: COLOR.dim
|
|
7457
|
+
},
|
|
7458
|
+
{
|
|
7459
|
+
key: "esc",
|
|
7460
|
+
label: multi ? "apply" : "cancel",
|
|
7461
|
+
labelColor: COLOR.dim
|
|
7462
|
+
},
|
|
7463
|
+
multi && {
|
|
7464
|
+
key: "",
|
|
7465
|
+
label: `${picks.length} selected`,
|
|
7466
|
+
labelColor: COLOR.brand
|
|
7467
|
+
},
|
|
7468
|
+
{
|
|
7469
|
+
key: "",
|
|
7470
|
+
label: `${filtered.length} / ${deduped.length} model${deduped.length === 1 ? "" : "s"}`
|
|
7471
|
+
}
|
|
7472
|
+
] })
|
|
7022
7473
|
]
|
|
7023
7474
|
});
|
|
7024
7475
|
}
|
|
@@ -7565,33 +8016,27 @@ function CompletionPopup({ state, visibleRows = 6 }) {
|
|
|
7565
8016
|
})
|
|
7566
8017
|
}, item.id);
|
|
7567
8018
|
})
|
|
7568
|
-
}), /* @__PURE__ */
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
fg: COLOR.warn,
|
|
7590
|
-
children: "esc"
|
|
7591
|
-
}),
|
|
7592
|
-
" close"
|
|
7593
|
-
]
|
|
7594
|
-
})] });
|
|
8019
|
+
}), /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
8020
|
+
{
|
|
8021
|
+
key: "↑↓",
|
|
8022
|
+
label: "navigate"
|
|
8023
|
+
},
|
|
8024
|
+
{
|
|
8025
|
+
key: enterSelects ? "↵" : "tab",
|
|
8026
|
+
label: "select"
|
|
8027
|
+
},
|
|
8028
|
+
enterSelects ? {
|
|
8029
|
+
key: "tab",
|
|
8030
|
+
label: "scope"
|
|
8031
|
+
} : {
|
|
8032
|
+
key: "↵",
|
|
8033
|
+
label: "submit"
|
|
8034
|
+
},
|
|
8035
|
+
{
|
|
8036
|
+
key: "esc",
|
|
8037
|
+
label: "close"
|
|
8038
|
+
}
|
|
8039
|
+
] })] });
|
|
7595
8040
|
}
|
|
7596
8041
|
return /* @__PURE__ */ jsxs("box", {
|
|
7597
8042
|
style: {
|
|
@@ -7851,7 +8296,7 @@ const BULK_ACTIONS = [
|
|
|
7851
8296
|
destructive: true
|
|
7852
8297
|
}
|
|
7853
8298
|
];
|
|
7854
|
-
function ActionBar({ actions, selected, customLabel }) {
|
|
8299
|
+
function ActionBar({ actions, selected, customLabel, onActivate, onHover }) {
|
|
7855
8300
|
const COLOR = useColors();
|
|
7856
8301
|
const SURFACE = useSurfaces();
|
|
7857
8302
|
return /* @__PURE__ */ jsx$1("box", {
|
|
@@ -7869,6 +8314,12 @@ function ActionBar({ actions, selected, customLabel }) {
|
|
|
7869
8314
|
marginRight: 2,
|
|
7870
8315
|
flexShrink: 0
|
|
7871
8316
|
},
|
|
8317
|
+
onMouseDown: (event) => {
|
|
8318
|
+
event.stopPropagation();
|
|
8319
|
+
event.preventDefault();
|
|
8320
|
+
onActivate?.(action, i);
|
|
8321
|
+
},
|
|
8322
|
+
onMouseOver: () => onHover?.(i),
|
|
7872
8323
|
children: isSelected ? /* @__PURE__ */ jsx$1("text", {
|
|
7873
8324
|
bg: tint,
|
|
7874
8325
|
fg: SURFACE.background,
|
|
@@ -8030,7 +8481,9 @@ function SingleEditApprovalModal({ request, payload, priorContent, priorError, t
|
|
|
8030
8481
|
})]
|
|
8031
8482
|
}), /* @__PURE__ */ jsx$1(ActionBar, {
|
|
8032
8483
|
actions: BULK_ACTIONS,
|
|
8033
|
-
selected
|
|
8484
|
+
selected,
|
|
8485
|
+
onActivate: (action) => decide(action.decision),
|
|
8486
|
+
onHover: setSelected
|
|
8034
8487
|
})]
|
|
8035
8488
|
}), /* @__PURE__ */ jsxs("text", {
|
|
8036
8489
|
style: {
|
|
@@ -8355,6 +8808,10 @@ function MultiEditApprovalModal({ request, payload, priorContent, priorError, ta
|
|
|
8355
8808
|
customLabel: {
|
|
8356
8809
|
idx: 0,
|
|
8357
8810
|
label: applyLabel
|
|
8811
|
+
},
|
|
8812
|
+
onActivate: (action) => decide(resolveDecision(action.decision)),
|
|
8813
|
+
onHover: (i) => {
|
|
8814
|
+
if (zone === "actions") setActionIdx(i);
|
|
8358
8815
|
}
|
|
8359
8816
|
})
|
|
8360
8817
|
]
|
|
@@ -9341,6 +9798,19 @@ function MultiSelectQuestionInput({ question, initialChoiceIds, onSubmit }) {
|
|
|
9341
9798
|
const isPicked = picked.has(choice.id);
|
|
9342
9799
|
return /* @__PURE__ */ jsxs("text", {
|
|
9343
9800
|
wrapMode: "word",
|
|
9801
|
+
onMouseDown: (event) => {
|
|
9802
|
+
event.stopPropagation();
|
|
9803
|
+
event.preventDefault();
|
|
9804
|
+
setCursor(i);
|
|
9805
|
+
if (!inCheckboxZone(event, 5)) return;
|
|
9806
|
+
setPicked((prev) => {
|
|
9807
|
+
const next = new Set(prev);
|
|
9808
|
+
if (next.has(choice.id)) next.delete(choice.id);
|
|
9809
|
+
else next.add(choice.id);
|
|
9810
|
+
return next;
|
|
9811
|
+
});
|
|
9812
|
+
},
|
|
9813
|
+
onMouseOver: () => setCursor(i),
|
|
9344
9814
|
children: [
|
|
9345
9815
|
/* @__PURE__ */ jsx$1("span", {
|
|
9346
9816
|
fg: COLOR.mute,
|
|
@@ -9364,25 +9834,28 @@ function MultiSelectQuestionInput({ question, initialChoiceIds, onSubmit }) {
|
|
|
9364
9834
|
})
|
|
9365
9835
|
]
|
|
9366
9836
|
}, choice.id);
|
|
9367
|
-
}), /* @__PURE__ */ jsxs("
|
|
9368
|
-
|
|
9369
|
-
children: [
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9837
|
+
}), /* @__PURE__ */ jsxs("box", {
|
|
9838
|
+
style: { flexDirection: "row" },
|
|
9839
|
+
children: [/* @__PURE__ */ jsx$1("text", {
|
|
9840
|
+
fg: COLOR.mute,
|
|
9841
|
+
children: " "
|
|
9842
|
+
}), /* @__PURE__ */ jsx$1(HintRow, { hints: [
|
|
9843
|
+
{
|
|
9844
|
+
key: "space",
|
|
9845
|
+
label: "toggle",
|
|
9846
|
+
labelColor: COLOR.mute
|
|
9847
|
+
},
|
|
9848
|
+
{
|
|
9849
|
+
key: "↵",
|
|
9850
|
+
label: "submit",
|
|
9851
|
+
labelColor: COLOR.mute
|
|
9852
|
+
},
|
|
9853
|
+
...required ? [{
|
|
9854
|
+
key: "",
|
|
9855
|
+
label: "required",
|
|
9856
|
+
labelColor: COLOR.warn
|
|
9857
|
+
}] : []
|
|
9858
|
+
] })]
|
|
9386
9859
|
})]
|
|
9387
9860
|
});
|
|
9388
9861
|
}
|
|
@@ -9407,7 +9880,9 @@ function OptionList({ items, initialCursor, onPick }) {
|
|
|
9407
9880
|
if (typeof initialCursor !== "number" || items.length === 0) return 0;
|
|
9408
9881
|
return Math.max(0, Math.min(items.length - 1, initialCursor));
|
|
9409
9882
|
});
|
|
9883
|
+
const [clickArmed, setClickArmed] = useState(false);
|
|
9410
9884
|
const moveCursor = useCallback((delta) => {
|
|
9885
|
+
setClickArmed(true);
|
|
9411
9886
|
setCursor((c) => {
|
|
9412
9887
|
if (items.length === 0) return c;
|
|
9413
9888
|
return ((c + delta) % items.length + items.length) % items.length;
|
|
@@ -9438,6 +9913,16 @@ function OptionList({ items, initialCursor, onPick }) {
|
|
|
9438
9913
|
const isCursor = i === cursor;
|
|
9439
9914
|
return /* @__PURE__ */ jsxs("text", {
|
|
9440
9915
|
wrapMode: "word",
|
|
9916
|
+
onMouseDown: (event) => {
|
|
9917
|
+
event.stopPropagation();
|
|
9918
|
+
event.preventDefault();
|
|
9919
|
+
if (isCursor && clickArmed) {
|
|
9920
|
+
onPick(item.id);
|
|
9921
|
+
return;
|
|
9922
|
+
}
|
|
9923
|
+
setCursor(i);
|
|
9924
|
+
setClickArmed(true);
|
|
9925
|
+
},
|
|
9441
9926
|
children: [
|
|
9442
9927
|
/* @__PURE__ */ jsx$1("span", {
|
|
9443
9928
|
fg: COLOR.mute,
|
|
@@ -9676,10 +10161,11 @@ function toneColor(tone, COLOR) {
|
|
|
9676
10161
|
* the parent picker's `useKeyboard` (via a ref) to suppress single-key
|
|
9677
10162
|
* shortcuts (`l` / `o` / `r`) while the user is typing into the input.
|
|
9678
10163
|
*/
|
|
9679
|
-
function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, inputFocused }) {
|
|
10164
|
+
function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, inputFocused, fill = false }) {
|
|
9680
10165
|
const COLOR = useColors();
|
|
9681
10166
|
const inputRef = useRef(null);
|
|
9682
10167
|
const [hint, setHint] = useState(null);
|
|
10168
|
+
const status = hint && hint.tone !== "error" ? hint.text : authUrl === null ? "starting login flow…" : "complete the login in your browser — waiting for the callback…";
|
|
9683
10169
|
const onSubmit = useCallback(() => {
|
|
9684
10170
|
const value = inputRef.current?.value?.trim() ?? "";
|
|
9685
10171
|
if (!value) return;
|
|
@@ -9709,32 +10195,37 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
|
|
|
9709
10195
|
return /* @__PURE__ */ jsxs("box", {
|
|
9710
10196
|
style: {
|
|
9711
10197
|
flexDirection: "column",
|
|
9712
|
-
|
|
9713
|
-
borderColor: COLOR.border,
|
|
9714
|
-
paddingTop: 1
|
|
10198
|
+
...fill ? { flexGrow: 1 } : { flexShrink: 0 }
|
|
9715
10199
|
},
|
|
9716
|
-
children: [
|
|
9717
|
-
|
|
9718
|
-
|
|
9719
|
-
|
|
9720
|
-
|
|
9721
|
-
|
|
9722
|
-
|
|
9723
|
-
|
|
9724
|
-
}
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
|
|
9728
|
-
|
|
9729
|
-
|
|
9730
|
-
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
10200
|
+
children: [/* @__PURE__ */ jsxs("box", {
|
|
10201
|
+
style: {
|
|
10202
|
+
flexDirection: "column",
|
|
10203
|
+
border: true,
|
|
10204
|
+
borderColor: COLOR.border,
|
|
10205
|
+
padding: 1,
|
|
10206
|
+
gap: 1,
|
|
10207
|
+
...fill ? { flexGrow: 1 } : {}
|
|
10208
|
+
},
|
|
10209
|
+
children: [
|
|
10210
|
+
/* @__PURE__ */ jsx$1(Spinner, { label: status }),
|
|
10211
|
+
authUrl !== null && /* @__PURE__ */ jsx$1(OAuthAuthBlock, {
|
|
10212
|
+
authUrl,
|
|
10213
|
+
maxLineWidth,
|
|
10214
|
+
chromeWidth: (chromeWidth ?? 14) + 4,
|
|
10215
|
+
paste: {
|
|
10216
|
+
inputRef,
|
|
10217
|
+
focused: inputFocused,
|
|
10218
|
+
onSubmit,
|
|
10219
|
+
placeholder: "paste redirect URL and press enter…",
|
|
10220
|
+
hint: hint?.tone === "error" ? hint : void 0
|
|
10221
|
+
}
|
|
10222
|
+
}),
|
|
10223
|
+
/* @__PURE__ */ jsx$1("text", {
|
|
10224
|
+
fg: COLOR.dim,
|
|
10225
|
+
children: "esc cancel — the server stays signed out until you retry"
|
|
10226
|
+
})
|
|
10227
|
+
]
|
|
10228
|
+
}), /* @__PURE__ */ jsx$1(TitleOverlay, { title: `authorizing ${serverName} — OAuth` })]
|
|
9738
10229
|
});
|
|
9739
10230
|
}
|
|
9740
10231
|
//#endregion
|
|
@@ -10796,7 +11287,13 @@ function SessionsScreen({ sessions, currentId, focusedSessionId, onPick, onCreat
|
|
|
10796
11287
|
focused: idx === cursorIndex && focused,
|
|
10797
11288
|
isCurrent: row.kind === "session" && row.rowId === currentId,
|
|
10798
11289
|
showProject: showAllProjects,
|
|
10799
|
-
currentProjectRoot
|
|
11290
|
+
currentProjectRoot,
|
|
11291
|
+
onHover: focused ? () => moveCursor(idx) : void 0,
|
|
11292
|
+
onClick: focused ? () => {
|
|
11293
|
+
moveCursor(idx);
|
|
11294
|
+
if (row.kind === "new") onCreate();
|
|
11295
|
+
else onPick(row.rowId);
|
|
11296
|
+
} : void 0
|
|
10800
11297
|
}, row.rowId)), filteredSessions.length === 0 && query.trim().length > 0 && /* @__PURE__ */ jsxs("text", {
|
|
10801
11298
|
wrapMode: "none",
|
|
10802
11299
|
children: [
|
|
@@ -10838,7 +11335,7 @@ function SessionsScreen({ sessions, currentId, focusedSessionId, onPick, onCreat
|
|
|
10838
11335
|
* exactly the width of the focus + current markers above — so the first
|
|
10839
11336
|
* stat (the turn count) sits flush under the title's first letter.
|
|
10840
11337
|
*/
|
|
10841
|
-
function SessionRow({ row, anchorId, focused, isCurrent, separator = false, showProject = false, currentProjectRoot }) {
|
|
11338
|
+
function SessionRow({ row, anchorId, focused, isCurrent, separator = false, showProject = false, currentProjectRoot, onClick, onHover }) {
|
|
10842
11339
|
const COLOR = useColors();
|
|
10843
11340
|
const SURFACE = useSurfaces();
|
|
10844
11341
|
const STATS_INDENT = " ";
|
|
@@ -10854,9 +11351,18 @@ function SessionRow({ row, anchorId, focused, isCurrent, separator = false, show
|
|
|
10854
11351
|
borderColor: COLOR.border
|
|
10855
11352
|
} : {}
|
|
10856
11353
|
};
|
|
11354
|
+
const mouseProps = {
|
|
11355
|
+
...onClick ? { onMouseDown: (event) => {
|
|
11356
|
+
event.stopPropagation();
|
|
11357
|
+
event.preventDefault();
|
|
11358
|
+
onClick();
|
|
11359
|
+
} } : {},
|
|
11360
|
+
...onHover ? { onMouseOver: () => onHover() } : {}
|
|
11361
|
+
};
|
|
10857
11362
|
if (row.kind === "new") return /* @__PURE__ */ jsxs("box", {
|
|
10858
11363
|
id: anchorId,
|
|
10859
11364
|
style: rowStyle,
|
|
11365
|
+
...mouseProps,
|
|
10860
11366
|
children: [/* @__PURE__ */ jsxs("text", {
|
|
10861
11367
|
wrapMode: "none",
|
|
10862
11368
|
children: [
|
|
@@ -10890,6 +11396,7 @@ function SessionRow({ row, anchorId, focused, isCurrent, separator = false, show
|
|
|
10890
11396
|
return /* @__PURE__ */ jsxs("box", {
|
|
10891
11397
|
id: anchorId,
|
|
10892
11398
|
style: rowStyle,
|
|
11399
|
+
...mouseProps,
|
|
10893
11400
|
children: [
|
|
10894
11401
|
/* @__PURE__ */ jsxs("text", {
|
|
10895
11402
|
wrapMode: "none",
|
|
@@ -11083,7 +11590,7 @@ const EMPTY_QUEUED_MESSAGES = [];
|
|
|
11083
11590
|
function shouldRenderTranscriptSearch(searchMode, query) {
|
|
11084
11591
|
return searchMode && query.trim().length > 0;
|
|
11085
11592
|
}
|
|
11086
|
-
function ChatScreen({ cwd, events, busy, compacting = false, queuedMessages = EMPTY_QUEUED_MESSAGES, queueSelectionIndex = null, queueShortcuts, onEnterQueueFromEmptyPrompt, settings, onSubmit, session, pending, onApproval, pendingInteraction, onInteraction, completionProviders, inlineAutocompleteProviders, onCompletionTab, enterSelectsCompletion, onPopupOpenChange, selectedTurnId, transcriptSearchMode = false, transcriptSearchQuery = "", transcriptSearchEvents = [], transcriptSearchSearching = false, onTranscriptSearchModeChange, onTranscriptSearchQueryChange, onTranscriptSearchNavigate, onTranscriptSearchOpen, onLoadEarlierTranscript, promptTriggerHints, attachImageBinding, editorBinding, sessionDetailsBinding, liveSession = null }) {
|
|
11593
|
+
function ChatScreen({ cwd, events, busy, compacting = false, queuedMessages = EMPTY_QUEUED_MESSAGES, queueSelectionIndex = null, queueShortcuts, onEnterQueueFromEmptyPrompt, settings, onSubmit, session, pending, onApproval, pendingInteraction, onInteraction, completionProviders, inlineAutocompleteProviders, onCompletionTab, enterSelectsCompletion, onPopupOpenChange, selectedTurnId, onSelectTurn, onOpenTurn, transcriptSearchMode = false, transcriptSearchQuery = "", transcriptSearchEvents = [], transcriptSearchSearching = false, onTranscriptSearchModeChange, onTranscriptSearchQueryChange, onTranscriptSearchNavigate, onTranscriptSearchOpen, onLoadEarlierTranscript, promptTriggerHints, attachImageBinding, editorBinding, sessionDetailsBinding, liveSession = null }) {
|
|
11087
11594
|
const COLOR = useColors();
|
|
11088
11595
|
const titleText = session?.title ?? "New session";
|
|
11089
11596
|
const sessionShortcutKey = formatBindingForDisplay(sessionDetailsBinding);
|
|
@@ -11173,6 +11680,8 @@ function ChatScreen({ cwd, events, busy, compacting = false, queuedMessages = EM
|
|
|
11173
11680
|
events: displayedEvents,
|
|
11174
11681
|
settings,
|
|
11175
11682
|
selectedTurnId: selectedTurnId ?? null,
|
|
11683
|
+
onSelectTurn,
|
|
11684
|
+
onOpenTurn,
|
|
11176
11685
|
searchQuery: transcriptSearchActive ? transcriptSearchQuery : void 0,
|
|
11177
11686
|
searchPending: transcriptSearchSearching,
|
|
11178
11687
|
busy: !transcriptSearchActive && busy && !pending && !pendingInteraction,
|
|
@@ -11221,7 +11730,8 @@ function ChatScreen({ cwd, events, busy, compacting = false, queuedMessages = EM
|
|
|
11221
11730
|
] }),
|
|
11222
11731
|
/* @__PURE__ */ jsx$1(TitleOverlay, {
|
|
11223
11732
|
title: titleText,
|
|
11224
|
-
meta: metaSegments
|
|
11733
|
+
meta: metaSegments,
|
|
11734
|
+
clickKey: sessionDetailsBinding ?? null
|
|
11225
11735
|
})
|
|
11226
11736
|
]
|
|
11227
11737
|
});
|
|
@@ -12302,7 +12812,6 @@ const PROMPT_HINTS_SELECT_QUEUE = [{
|
|
|
12302
12812
|
* shortcuts that actually do something in the active mode.
|
|
12303
12813
|
*/
|
|
12304
12814
|
function PromptHints({ selectMode, searchMode = false, triggerHints, busy = false }) {
|
|
12305
|
-
const COLOR = useColors();
|
|
12306
12815
|
const { settings } = useSettings();
|
|
12307
12816
|
const { width: termWidth } = useTerminalDimensions();
|
|
12308
12817
|
const minimalResting = !selectMode && !searchMode && !busy && settings.uiMode === "minimal";
|
|
@@ -12319,21 +12828,21 @@ function PromptHints({ selectMode, searchMode = false, triggerHints, busy = fals
|
|
|
12319
12828
|
termWidth
|
|
12320
12829
|
]);
|
|
12321
12830
|
if (hints.length === 0) return null;
|
|
12322
|
-
return /* @__PURE__ */ jsxs("
|
|
12831
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
12323
12832
|
style: {
|
|
12324
12833
|
position: "absolute",
|
|
12325
12834
|
top: 0,
|
|
12326
|
-
right: 1
|
|
12835
|
+
right: 1,
|
|
12836
|
+
flexDirection: "row"
|
|
12327
12837
|
},
|
|
12328
|
-
fg: COLOR.dim,
|
|
12329
12838
|
children: [
|
|
12330
|
-
/* @__PURE__ */ jsx$1("
|
|
12331
|
-
|
|
12839
|
+
/* @__PURE__ */ jsx$1("text", {
|
|
12840
|
+
selectable: false,
|
|
12332
12841
|
children: " "
|
|
12333
12842
|
}),
|
|
12334
|
-
|
|
12335
|
-
/* @__PURE__ */ jsx$1("
|
|
12336
|
-
|
|
12843
|
+
/* @__PURE__ */ jsx$1(HintRow, { hints }),
|
|
12844
|
+
/* @__PURE__ */ jsx$1("text", {
|
|
12845
|
+
selectable: false,
|
|
12337
12846
|
children: " "
|
|
12338
12847
|
})
|
|
12339
12848
|
]
|
|
@@ -12896,81 +13405,64 @@ function ActionRow$2({ pending, copyStatus, titleStatus, titleError, hasGenerate
|
|
|
12896
13405
|
})]
|
|
12897
13406
|
});
|
|
12898
13407
|
}
|
|
12899
|
-
if (copyStatus === "copied") return /* @__PURE__ */
|
|
12900
|
-
|
|
12901
|
-
|
|
12902
|
-
|
|
12903
|
-
|
|
12904
|
-
|
|
12905
|
-
|
|
12906
|
-
|
|
12907
|
-
|
|
12908
|
-
|
|
12909
|
-
|
|
12910
|
-
|
|
12911
|
-
|
|
12912
|
-
|
|
12913
|
-
|
|
12914
|
-
|
|
12915
|
-
|
|
12916
|
-
|
|
12917
|
-
|
|
12918
|
-
|
|
12919
|
-
|
|
12920
|
-
|
|
12921
|
-
|
|
12922
|
-
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
12926
|
-
|
|
12927
|
-
|
|
12928
|
-
|
|
12929
|
-
|
|
12930
|
-
|
|
12931
|
-
|
|
12932
|
-
|
|
12933
|
-
|
|
12934
|
-
|
|
12935
|
-
|
|
12936
|
-
|
|
12937
|
-
|
|
12938
|
-
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12948
|
-
|
|
12949
|
-
|
|
12950
|
-
|
|
12951
|
-
|
|
12952
|
-
|
|
12953
|
-
|
|
12954
|
-
|
|
12955
|
-
|
|
12956
|
-
|
|
12957
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
12958
|
-
fg: COLOR.warn,
|
|
12959
|
-
children: keys.delete
|
|
12960
|
-
}),
|
|
12961
|
-
" delete · ",
|
|
12962
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
12963
|
-
fg: COLOR.warn,
|
|
12964
|
-
children: keys.copy
|
|
12965
|
-
}),
|
|
12966
|
-
" copy · ",
|
|
12967
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
12968
|
-
fg: COLOR.warn,
|
|
12969
|
-
children: "esc"
|
|
12970
|
-
}),
|
|
12971
|
-
" close"
|
|
12972
|
-
]
|
|
12973
|
-
});
|
|
13408
|
+
if (copyStatus === "copied") return /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
13409
|
+
{
|
|
13410
|
+
key: "",
|
|
13411
|
+
label: "✓ session id copied",
|
|
13412
|
+
labelColor: COLOR.accent
|
|
13413
|
+
},
|
|
13414
|
+
{
|
|
13415
|
+
key: keys.delete,
|
|
13416
|
+
label: "delete",
|
|
13417
|
+
labelColor: COLOR.dim
|
|
13418
|
+
},
|
|
13419
|
+
{
|
|
13420
|
+
key: "esc",
|
|
13421
|
+
label: "close",
|
|
13422
|
+
labelColor: COLOR.dim
|
|
13423
|
+
}
|
|
13424
|
+
] });
|
|
13425
|
+
if (copyStatus === "failed") return /* @__PURE__ */ jsx$1(ModalHints, { hints: [{
|
|
13426
|
+
key: "",
|
|
13427
|
+
label: "copy failed (terminal may not support OSC 52)",
|
|
13428
|
+
labelColor: COLOR.error
|
|
13429
|
+
}, {
|
|
13430
|
+
key: "esc",
|
|
13431
|
+
label: "close",
|
|
13432
|
+
labelColor: COLOR.dim
|
|
13433
|
+
}] });
|
|
13434
|
+
return /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
13435
|
+
hasGenerate && {
|
|
13436
|
+
key: keys.generate,
|
|
13437
|
+
label: "title",
|
|
13438
|
+
labelColor: COLOR.dim
|
|
13439
|
+
},
|
|
13440
|
+
hasExport && {
|
|
13441
|
+
key: `${keys.markdown}/${keys.json}`,
|
|
13442
|
+
label: "export",
|
|
13443
|
+
labelColor: COLOR.dim
|
|
13444
|
+
},
|
|
13445
|
+
hasCompact && {
|
|
13446
|
+
key: keys.compact,
|
|
13447
|
+
label: "compact",
|
|
13448
|
+
labelColor: COLOR.dim
|
|
13449
|
+
},
|
|
13450
|
+
{
|
|
13451
|
+
key: keys.delete,
|
|
13452
|
+
label: "delete",
|
|
13453
|
+
labelColor: COLOR.dim
|
|
13454
|
+
},
|
|
13455
|
+
{
|
|
13456
|
+
key: keys.copy,
|
|
13457
|
+
label: "copy",
|
|
13458
|
+
labelColor: COLOR.dim
|
|
13459
|
+
},
|
|
13460
|
+
{
|
|
13461
|
+
key: "esc",
|
|
13462
|
+
label: "close",
|
|
13463
|
+
labelColor: COLOR.dim
|
|
13464
|
+
}
|
|
13465
|
+
] });
|
|
12974
13466
|
}
|
|
12975
13467
|
/**
|
|
12976
13468
|
* Sum token + cost figures across every {@link SessionRun}. Preference
|
|
@@ -14434,8 +14926,8 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14434
14926
|
[activeTab]: 0
|
|
14435
14927
|
}));
|
|
14436
14928
|
}, [activeTab]);
|
|
14437
|
-
const
|
|
14438
|
-
const row = mcpVisibleRows[
|
|
14929
|
+
const expandMcpRowAt = useCallback((index) => {
|
|
14930
|
+
const row = mcpVisibleRows[index];
|
|
14439
14931
|
if (!row || row.kind !== "server") return;
|
|
14440
14932
|
const name = row.entry.config.name;
|
|
14441
14933
|
if ((mcpToolsByServer[name]?.length ?? 0) === 0) fireMcpToolsRefresh();
|
|
@@ -14447,12 +14939,11 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14447
14939
|
});
|
|
14448
14940
|
}, [
|
|
14449
14941
|
mcpVisibleRows,
|
|
14450
|
-
cursor,
|
|
14451
14942
|
mcpToolsByServer,
|
|
14452
14943
|
fireMcpToolsRefresh
|
|
14453
14944
|
]);
|
|
14454
|
-
const
|
|
14455
|
-
const row = mcpVisibleRows[
|
|
14945
|
+
const collapseMcpRowAt = useCallback((index) => {
|
|
14946
|
+
const row = mcpVisibleRows[index];
|
|
14456
14947
|
if (!row) return;
|
|
14457
14948
|
const parentName = parentServerName(row);
|
|
14458
14949
|
if (row.kind !== "server") {
|
|
@@ -14468,7 +14959,18 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14468
14959
|
next.delete(parentName);
|
|
14469
14960
|
return next;
|
|
14470
14961
|
});
|
|
14471
|
-
}, [mcpVisibleRows
|
|
14962
|
+
}, [mcpVisibleRows]);
|
|
14963
|
+
const toggleExpandMcpRowAt = useCallback((index) => {
|
|
14964
|
+
const row = mcpVisibleRows[index];
|
|
14965
|
+
if (!row) return;
|
|
14966
|
+
if (expandedMcps.has(parentServerName(row))) collapseMcpRowAt(index);
|
|
14967
|
+
else expandMcpRowAt(index);
|
|
14968
|
+
}, [
|
|
14969
|
+
mcpVisibleRows,
|
|
14970
|
+
expandedMcps,
|
|
14971
|
+
collapseMcpRowAt,
|
|
14972
|
+
expandMcpRowAt
|
|
14973
|
+
]);
|
|
14472
14974
|
/**
|
|
14473
14975
|
* Single `tab` press toggles between expanded / collapsed based on
|
|
14474
14976
|
* the focused row's current state. The split helpers above remain
|
|
@@ -14476,21 +14978,9 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14476
14978
|
* users expect — expand-only / collapse-only). Toggle is the
|
|
14477
14979
|
* default that the footer hint advertises.
|
|
14478
14980
|
*/
|
|
14479
|
-
const toggleExpandFocusedMcpRow = useCallback(() =>
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
const parentName = parentServerName(row);
|
|
14483
|
-
if (expandedMcps.has(parentName)) collapseFocusedMcpRow();
|
|
14484
|
-
else expandFocusedMcpRow();
|
|
14485
|
-
}, [
|
|
14486
|
-
mcpVisibleRows,
|
|
14487
|
-
cursor,
|
|
14488
|
-
expandedMcps,
|
|
14489
|
-
collapseFocusedMcpRow,
|
|
14490
|
-
expandFocusedMcpRow
|
|
14491
|
-
]);
|
|
14492
|
-
const toggleExpandFocusedExtensionRow = useCallback(() => {
|
|
14493
|
-
const row = extensionVisibleRows[cursor];
|
|
14981
|
+
const toggleExpandFocusedMcpRow = useCallback(() => toggleExpandMcpRowAt(cursor), [toggleExpandMcpRowAt, cursor]);
|
|
14982
|
+
const toggleExpandExtensionRowAt = useCallback((index) => {
|
|
14983
|
+
const row = extensionVisibleRows[index];
|
|
14494
14984
|
const parentName = parentExtensionName(row);
|
|
14495
14985
|
if (!parentName) return;
|
|
14496
14986
|
setExpandedExtensions((prev) => {
|
|
@@ -14507,7 +14997,8 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14507
14997
|
} else next.add(parentName);
|
|
14508
14998
|
return next;
|
|
14509
14999
|
});
|
|
14510
|
-
}, [extensionVisibleRows
|
|
15000
|
+
}, [extensionVisibleRows]);
|
|
15001
|
+
const toggleExpandFocusedExtensionRow = useCallback(() => toggleExpandExtensionRowAt(cursor), [toggleExpandExtensionRowAt, cursor]);
|
|
14511
15002
|
const mcpRowCount = mcpVisibleRows.length;
|
|
14512
15003
|
const extensionRowCount = extensionVisibleRows.length;
|
|
14513
15004
|
useEffect(() => {
|
|
@@ -14590,13 +15081,163 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14590
15081
|
useEffect(() => {
|
|
14591
15082
|
setMcpRemoveArmed(null);
|
|
14592
15083
|
}, [focusedMcp?.config.name, activeTab]);
|
|
14593
|
-
const
|
|
15084
|
+
const authorizingMcp = activeTab === "mcps" ? mcpsCatalog.map((entry) => ({
|
|
15085
|
+
entry,
|
|
15086
|
+
status: getMcpAuthStatus(authState, entry.config.name)
|
|
15087
|
+
})).find(({ status }) => status.kind === "authorizing") : void 0;
|
|
15088
|
+
const oauthPasteActive = !!authorizingMcp && authorizingMcp.status.kind === "authorizing" && !!authorizingMcp.status.url;
|
|
14594
15089
|
useEffect(() => {
|
|
14595
|
-
if (!oauthPasteActive && !editingInputKey) inputRef.current?.focus();
|
|
14596
|
-
}, [
|
|
15090
|
+
if (!oauthPasteActive && !editingInputKey && !authorizingMcp) inputRef.current?.focus();
|
|
15091
|
+
}, [
|
|
15092
|
+
oauthPasteActive,
|
|
15093
|
+
editingInputKey,
|
|
15094
|
+
authorizingMcp
|
|
15095
|
+
]);
|
|
14597
15096
|
useEffect(() => {
|
|
14598
15097
|
if (editingInputKey) editInputRef.current?.focus();
|
|
14599
15098
|
}, [editingInputKey]);
|
|
15099
|
+
/**
|
|
15100
|
+
* Activate the row at `index` on the ACTIVE tab — the ↵ semantics
|
|
15101
|
+
* (toggle / cycle / open editor / run action), extracted so row
|
|
15102
|
+
* CLICKS can activate the clicked row directly. Cursor-based
|
|
15103
|
+
* callers (the keyboard handler) pass `cursor`.
|
|
15104
|
+
*/
|
|
15105
|
+
const activateRowAt = useCallback((index) => {
|
|
15106
|
+
if (isCategoryTab(activeTab)) {
|
|
15107
|
+
const it = filteredByCategory[activeTab][index];
|
|
15108
|
+
if (!it) return;
|
|
15109
|
+
if (it.kind === "toggle") toggleBoolean(it.key);
|
|
15110
|
+
else if (it.kind === "choice") {
|
|
15111
|
+
const current = settings[it.key];
|
|
15112
|
+
const idx = it.options.findIndex((o) => o.value === current);
|
|
15113
|
+
const next = it.options[(idx + 1) % it.options.length];
|
|
15114
|
+
if (next) setSetting(it.key, next.value);
|
|
15115
|
+
} else if (it.kind === "input") setEditingInputKey(it.key);
|
|
15116
|
+
else it.onPick();
|
|
15117
|
+
return;
|
|
15118
|
+
}
|
|
15119
|
+
if (activeTab === "skills") {
|
|
15120
|
+
const s = filteredSkills[index];
|
|
15121
|
+
if (s) skillsToggle.toggle(s.name);
|
|
15122
|
+
return;
|
|
15123
|
+
}
|
|
15124
|
+
if (activeTab === "extensions") {
|
|
15125
|
+
const row = extensionVisibleRows[index];
|
|
15126
|
+
if (!row) return;
|
|
15127
|
+
if (row.kind === "extension") extensionsToggle.toggle(row.ext.name);
|
|
15128
|
+
else if (row.kind === "config") activateConfigRow(row.extName, row.item);
|
|
15129
|
+
return;
|
|
15130
|
+
}
|
|
15131
|
+
if (activeTab === "mcps") {
|
|
15132
|
+
const row = mcpVisibleRows[index];
|
|
15133
|
+
if (!row) return;
|
|
15134
|
+
if (row.kind === "server") {
|
|
15135
|
+
const name = row.entry.config.name;
|
|
15136
|
+
const enabling = !mcpsToggle.enabledSet.has(name);
|
|
15137
|
+
mcpsToggle.toggle(name);
|
|
15138
|
+
if (enabling && (mcpToolsByServer[name]?.length ?? 0) === 0) fireMcpToolsRefresh();
|
|
15139
|
+
} else if (row.kind === "tool") mcpToolToggleMap[row.serverName]?.toggle(row.tool.name);
|
|
15140
|
+
return;
|
|
15141
|
+
}
|
|
15142
|
+
if (activeTab === "keybindings") {
|
|
15143
|
+
actions?.onOpenKeybindings?.();
|
|
15144
|
+
return;
|
|
15145
|
+
}
|
|
15146
|
+
if (activeTab === "authentication") {
|
|
15147
|
+
const provider = filteredProviders[index];
|
|
15148
|
+
if (provider) actions?.onConfigureProvider?.(provider);
|
|
15149
|
+
}
|
|
15150
|
+
}, [
|
|
15151
|
+
activeTab,
|
|
15152
|
+
filteredByCategory,
|
|
15153
|
+
settings,
|
|
15154
|
+
setSetting,
|
|
15155
|
+
toggleBoolean,
|
|
15156
|
+
filteredSkills,
|
|
15157
|
+
skillsToggle,
|
|
15158
|
+
extensionVisibleRows,
|
|
15159
|
+
extensionsToggle,
|
|
15160
|
+
activateConfigRow,
|
|
15161
|
+
mcpVisibleRows,
|
|
15162
|
+
mcpsToggle,
|
|
15163
|
+
mcpToolsByServer,
|
|
15164
|
+
fireMcpToolsRefresh,
|
|
15165
|
+
mcpToolToggleMap,
|
|
15166
|
+
actions,
|
|
15167
|
+
filteredProviders
|
|
15168
|
+
]);
|
|
15169
|
+
/**
|
|
15170
|
+
* True while an inline editor or overlay dialog owns the modal's input
|
|
15171
|
+
* — the same states the keyboard handler early-returns on. Mouse paths
|
|
15172
|
+
* (`clickRowAt`, tab-strip clicks) must honor it too: a click on a row
|
|
15173
|
+
* or tab underneath an open dialog would otherwise toggle settings or
|
|
15174
|
+
* switch tabs behind the user's back. Also drives the lists' `focused`
|
|
15175
|
+
* prop, so "list looks focused" and "list accepts input" cannot drift.
|
|
15176
|
+
*/
|
|
15177
|
+
const modalInputCaptured = oauthPasteActive || configEditActive || editingInputKey !== null || extInstallActive || skillInstallActive || skillImportAllActive || mcpAddActive;
|
|
15178
|
+
/**
|
|
15179
|
+
* Row CLICK dispatch: focus the clicked row, then act on it. Expandable
|
|
15180
|
+
* headers (MCP servers, extensions with config) expand/collapse — the
|
|
15181
|
+
* disclosure is the row's primary affordance; everything else gets the
|
|
15182
|
+
* ↵ semantics (toggle / cycle / edit / action). Rows stay single
|
|
15183
|
+
* renderables (the MCP list documents an OpenTUI layout regression that
|
|
15184
|
+
* forbids box wrappers there), so the whole row is one click target —
|
|
15185
|
+
* the enable checkbox on expandable headers remains ↵.
|
|
15186
|
+
*/
|
|
15187
|
+
/**
|
|
15188
|
+
* Row CLICK dispatch, by ZONE:
|
|
15189
|
+
*
|
|
15190
|
+
* - `checkbox` — the click landed on the row's `[✓] ` cell (rows
|
|
15191
|
+
* compute this by glyph column — see `inCheckboxZone`): flip the
|
|
15192
|
+
* toggle (↵ semantics). The checkbox is a SOLO target, including
|
|
15193
|
+
* the enable checkbox on MCP server / extension header rows.
|
|
15194
|
+
* - `row` — anywhere else: expandable headers expand/collapse;
|
|
15195
|
+
* checkbox-bearing rows only FOCUS (a body click must never flip
|
|
15196
|
+
* state the user didn't aim at); rows whose whole body is one
|
|
15197
|
+
* action (choices, inputs, actions, auth) activate.
|
|
15198
|
+
*/
|
|
15199
|
+
const clickRowAt = useCallback((index, zone = "row") => {
|
|
15200
|
+
if (modalInputCaptured) return;
|
|
15201
|
+
setCursorByTab((prev) => ({
|
|
15202
|
+
...prev,
|
|
15203
|
+
[activeTab]: index
|
|
15204
|
+
}));
|
|
15205
|
+
if (zone === "checkbox") {
|
|
15206
|
+
activateRowAt(index);
|
|
15207
|
+
return;
|
|
15208
|
+
}
|
|
15209
|
+
if (activeTab === "mcps") {
|
|
15210
|
+
if (mcpVisibleRows[index]?.kind === "server") toggleExpandMcpRowAt(index);
|
|
15211
|
+
return;
|
|
15212
|
+
}
|
|
15213
|
+
if (activeTab === "extensions") {
|
|
15214
|
+
const row = extensionVisibleRows[index];
|
|
15215
|
+
if (row?.kind === "extension") {
|
|
15216
|
+
if (row.hasConfig) toggleExpandExtensionRowAt(index);
|
|
15217
|
+
return;
|
|
15218
|
+
}
|
|
15219
|
+
if (row?.kind === "config" && row.item.type === "boolean") return;
|
|
15220
|
+
activateRowAt(index);
|
|
15221
|
+
return;
|
|
15222
|
+
}
|
|
15223
|
+
if (activeTab === "skills") return;
|
|
15224
|
+
if (isCategoryTab(activeTab) && filteredByCategory[activeTab][index]?.kind === "toggle") return;
|
|
15225
|
+
activateRowAt(index);
|
|
15226
|
+
}, [
|
|
15227
|
+
activeTab,
|
|
15228
|
+
modalInputCaptured,
|
|
15229
|
+
mcpVisibleRows,
|
|
15230
|
+
extensionVisibleRows,
|
|
15231
|
+
filteredByCategory,
|
|
15232
|
+
toggleExpandMcpRowAt,
|
|
15233
|
+
toggleExpandExtensionRowAt,
|
|
15234
|
+
activateRowAt
|
|
15235
|
+
]);
|
|
15236
|
+
/** Tab-strip clicks — same input-capture guard as row clicks. */
|
|
15237
|
+
const clickTab = useCallback((id) => {
|
|
15238
|
+
if (modalInputCaptured) return;
|
|
15239
|
+
setActiveTab(id);
|
|
15240
|
+
}, [modalInputCaptured]);
|
|
14600
15241
|
useKeyboard((key) => {
|
|
14601
15242
|
if (configEditActive) {
|
|
14602
15243
|
if (key.name === "escape" && configEdit?.kind !== "model") setConfigEdit(null);
|
|
@@ -14604,8 +15245,8 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14604
15245
|
}
|
|
14605
15246
|
if (extInstallActive || skillInstallActive || skillImportAllActive) return;
|
|
14606
15247
|
if (mcpAddActive) return;
|
|
14607
|
-
if (key.name === "escape" && oauthPasteActive &&
|
|
14608
|
-
actions?.onCancelLoginMcp?.(
|
|
15248
|
+
if (key.name === "escape" && oauthPasteActive && authorizingMcp) {
|
|
15249
|
+
actions?.onCancelLoginMcp?.(authorizingMcp.entry.config.name);
|
|
14609
15250
|
return;
|
|
14610
15251
|
}
|
|
14611
15252
|
if (oauthPasteActive) return;
|
|
@@ -14659,51 +15300,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14659
15300
|
return;
|
|
14660
15301
|
}
|
|
14661
15302
|
if (key.name === "return") {
|
|
14662
|
-
|
|
14663
|
-
const it = filteredByCategory[activeTab][cursor];
|
|
14664
|
-
if (!it) return;
|
|
14665
|
-
if (it.kind === "toggle") toggleBoolean(it.key);
|
|
14666
|
-
else if (it.kind === "choice") {
|
|
14667
|
-
const current = settings[it.key];
|
|
14668
|
-
const idx = it.options.findIndex((o) => o.value === current);
|
|
14669
|
-
const next = it.options[(idx + 1) % it.options.length];
|
|
14670
|
-
if (next) setSetting(it.key, next.value);
|
|
14671
|
-
} else if (it.kind === "input") setEditingInputKey(it.key);
|
|
14672
|
-
else it.onPick();
|
|
14673
|
-
return;
|
|
14674
|
-
}
|
|
14675
|
-
if (activeTab === "skills") {
|
|
14676
|
-
const s = filteredSkills[cursor];
|
|
14677
|
-
if (s) skillsToggle.toggle(s.name);
|
|
14678
|
-
return;
|
|
14679
|
-
}
|
|
14680
|
-
if (activeTab === "extensions") {
|
|
14681
|
-
const row = extensionVisibleRows[cursor];
|
|
14682
|
-
if (!row) return;
|
|
14683
|
-
if (row.kind === "extension") extensionsToggle.toggle(row.ext.name);
|
|
14684
|
-
else if (row.kind === "config") activateConfigRow(row.extName, row.item);
|
|
14685
|
-
return;
|
|
14686
|
-
}
|
|
14687
|
-
if (activeTab === "mcps") {
|
|
14688
|
-
const row = mcpVisibleRows[cursor];
|
|
14689
|
-
if (!row) return;
|
|
14690
|
-
if (row.kind === "server") {
|
|
14691
|
-
const name = row.entry.config.name;
|
|
14692
|
-
const enabling = !mcpsToggle.enabledSet.has(name);
|
|
14693
|
-
mcpsToggle.toggle(name);
|
|
14694
|
-
if (enabling && (mcpToolsByServer[name]?.length ?? 0) === 0) fireMcpToolsRefresh();
|
|
14695
|
-
} else if (row.kind === "tool") mcpToolToggleMap[row.serverName]?.toggle(row.tool.name);
|
|
14696
|
-
return;
|
|
14697
|
-
}
|
|
14698
|
-
if (activeTab === "keybindings") {
|
|
14699
|
-
actions?.onOpenKeybindings?.();
|
|
14700
|
-
return;
|
|
14701
|
-
}
|
|
14702
|
-
if (activeTab === "authentication") {
|
|
14703
|
-
const provider = filteredProviders[cursor];
|
|
14704
|
-
if (provider) actions?.onConfigureProvider?.(provider);
|
|
14705
|
-
return;
|
|
14706
|
-
}
|
|
15303
|
+
activateRowAt(cursor);
|
|
14707
15304
|
return;
|
|
14708
15305
|
}
|
|
14709
15306
|
if (activeTab === "extensions") {
|
|
@@ -14787,7 +15384,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14787
15384
|
actions?.onLogoutMcp?.(focusedMcp.config.name);
|
|
14788
15385
|
return;
|
|
14789
15386
|
}
|
|
14790
|
-
if (key.name === "escape" &&
|
|
15387
|
+
if (key.name === "escape" && authorizingMcp) actions?.onCancelLoginMcp?.(authorizingMcp.entry.config.name);
|
|
14791
15388
|
}
|
|
14792
15389
|
if (key.ctrl && !key.shift && key.name === "l" && activeTab === "logs") {
|
|
14793
15390
|
key.preventDefault();
|
|
@@ -14908,10 +15505,11 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14908
15505
|
children: /* @__PURE__ */ jsx$1(TabStrip, {
|
|
14909
15506
|
order: tabOrder,
|
|
14910
15507
|
active: activeTab,
|
|
14911
|
-
counts: tabCounts
|
|
15508
|
+
counts: tabCounts,
|
|
15509
|
+
onSelect: clickTab
|
|
14912
15510
|
})
|
|
14913
15511
|
}),
|
|
14914
|
-
/* @__PURE__ */ jsx$1("box", {
|
|
15512
|
+
!authorizingMcp && /* @__PURE__ */ jsx$1("box", {
|
|
14915
15513
|
style: {
|
|
14916
15514
|
border: true,
|
|
14917
15515
|
borderColor: COLOR.borderActive,
|
|
@@ -14922,14 +15520,26 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14922
15520
|
},
|
|
14923
15521
|
children: /* @__PURE__ */ jsx$1("input", {
|
|
14924
15522
|
ref: inputRef,
|
|
14925
|
-
focused: !
|
|
15523
|
+
focused: !modalInputCaptured,
|
|
14926
15524
|
placeholder: searchPlaceholder(activeTab),
|
|
14927
15525
|
onInput: handleQueryChange,
|
|
14928
15526
|
onSubmit: () => {},
|
|
14929
15527
|
style: { flexGrow: 1 }
|
|
14930
15528
|
})
|
|
14931
15529
|
}),
|
|
14932
|
-
/* @__PURE__ */
|
|
15530
|
+
authorizingMcp ? /* @__PURE__ */ jsx$1("box", {
|
|
15531
|
+
style: {
|
|
15532
|
+
flexGrow: 1,
|
|
15533
|
+
flexDirection: "column"
|
|
15534
|
+
},
|
|
15535
|
+
children: /* @__PURE__ */ jsx$1(McpAuthorizingPanel, {
|
|
15536
|
+
serverName: authorizingMcp.entry.config.name,
|
|
15537
|
+
authUrl: authorizingMcp.status.kind === "authorizing" ? authorizingMcp.status.url ?? null : null,
|
|
15538
|
+
maxLineWidth: 154,
|
|
15539
|
+
inputFocused: true,
|
|
15540
|
+
fill: true
|
|
15541
|
+
})
|
|
15542
|
+
}) : /* @__PURE__ */ jsxs("scrollbox", {
|
|
14933
15543
|
ref: scrollboxRef,
|
|
14934
15544
|
focusable: false,
|
|
14935
15545
|
style: {
|
|
@@ -14941,6 +15551,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14941
15551
|
viewportCulling: false,
|
|
14942
15552
|
children: [
|
|
14943
15553
|
isCategoryTab(activeTab) && /* @__PURE__ */ jsx$1(GeneralList, {
|
|
15554
|
+
onRowClick: clickRowAt,
|
|
14944
15555
|
items: filteredByCategory[activeTab],
|
|
14945
15556
|
cursor,
|
|
14946
15557
|
highlightBg: SURFACE.selection,
|
|
@@ -14949,6 +15560,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14949
15560
|
editingKey: editingInputKey
|
|
14950
15561
|
}),
|
|
14951
15562
|
activeTab === "skills" && /* @__PURE__ */ jsx$1(SkillsList, {
|
|
15563
|
+
onRowClick: clickRowAt,
|
|
14952
15564
|
items: filteredSkills,
|
|
14953
15565
|
enabledSet: skillsToggle.enabledSet,
|
|
14954
15566
|
totalCount: skillsCatalog.length,
|
|
@@ -14958,6 +15570,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14958
15570
|
contentCols
|
|
14959
15571
|
}),
|
|
14960
15572
|
activeTab === "extensions" && /* @__PURE__ */ jsx$1(ExtensionsList, {
|
|
15573
|
+
onRowClick: clickRowAt,
|
|
14961
15574
|
rows: extensionVisibleRows,
|
|
14962
15575
|
enabledSet: extensionsToggle.enabledSet,
|
|
14963
15576
|
extensionConfig: settings.extensionConfig,
|
|
@@ -14977,6 +15590,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14977
15590
|
actionProbes
|
|
14978
15591
|
}),
|
|
14979
15592
|
activeTab === "mcps" && /* @__PURE__ */ jsx$1(McpsList, {
|
|
15593
|
+
onRowClick: clickRowAt,
|
|
14980
15594
|
rows: mcpVisibleRows,
|
|
14981
15595
|
filteredCount: filteredMcps.length,
|
|
14982
15596
|
enabledSet: mcpsToggle.enabledSet,
|
|
@@ -15020,7 +15634,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
15020
15634
|
highlightBg: SURFACE.selection
|
|
15021
15635
|
})
|
|
15022
15636
|
}),
|
|
15023
|
-
activeTab === "mcps" && focusedMcp && focusedMcpStatus && /* @__PURE__ */ jsx$1("box", {
|
|
15637
|
+
activeTab === "mcps" && !authorizingMcp && focusedMcp && focusedMcpStatus && /* @__PURE__ */ jsx$1("box", {
|
|
15024
15638
|
style: { flexShrink: 0 },
|
|
15025
15639
|
children: renderMcpDetailPanel(focusedMcp, focusedMcpStatus, COLOR)
|
|
15026
15640
|
}),
|
|
@@ -15090,27 +15704,27 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
15090
15704
|
style: { flexGrow: 1 }
|
|
15091
15705
|
})
|
|
15092
15706
|
}),
|
|
15093
|
-
/* @__PURE__ */
|
|
15094
|
-
|
|
15095
|
-
|
|
15096
|
-
|
|
15097
|
-
|
|
15098
|
-
|
|
15099
|
-
|
|
15100
|
-
|
|
15101
|
-
|
|
15102
|
-
|
|
15103
|
-
|
|
15104
|
-
}
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
})
|
|
15707
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
15708
|
+
{
|
|
15709
|
+
key: "↵",
|
|
15710
|
+
label: "save"
|
|
15711
|
+
},
|
|
15712
|
+
{
|
|
15713
|
+
key: "esc",
|
|
15714
|
+
label: "cancel"
|
|
15715
|
+
},
|
|
15716
|
+
{
|
|
15717
|
+
key: "",
|
|
15718
|
+
label: `empty = ${editingInputItem.placeholder}`
|
|
15719
|
+
}
|
|
15720
|
+
] })
|
|
15108
15721
|
]
|
|
15109
15722
|
}),
|
|
15110
15723
|
/* @__PURE__ */ jsx$1("box", {
|
|
15111
15724
|
style: { flexShrink: 0 },
|
|
15112
15725
|
children: /* @__PURE__ */ jsx$1(Hints, {
|
|
15113
15726
|
activeTab,
|
|
15727
|
+
authorizing: !!authorizingMcp,
|
|
15114
15728
|
focusedMcp,
|
|
15115
15729
|
focusedMcpRow,
|
|
15116
15730
|
focusedMcpStatus,
|
|
@@ -15183,9 +15797,10 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
15183
15797
|
]
|
|
15184
15798
|
});
|
|
15185
15799
|
}
|
|
15186
|
-
function TabStrip({ order, active, counts }) {
|
|
15800
|
+
function TabStrip({ order, active, counts, onSelect }) {
|
|
15187
15801
|
const COLOR = useColors();
|
|
15188
15802
|
const SURFACE = useSurfaces();
|
|
15803
|
+
const [hoveredTab, setHoveredTab] = useState(null);
|
|
15189
15804
|
return /* @__PURE__ */ jsx$1("box", {
|
|
15190
15805
|
style: {
|
|
15191
15806
|
flexDirection: "row",
|
|
@@ -15193,11 +15808,19 @@ function TabStrip({ order, active, counts }) {
|
|
|
15193
15808
|
},
|
|
15194
15809
|
children: order.map((id, i) => {
|
|
15195
15810
|
const isActive = id === active;
|
|
15811
|
+
const hovered = hoveredTab === id && !isActive;
|
|
15196
15812
|
const label = TAB_LABELS[id];
|
|
15197
15813
|
const tabCounts = counts[id];
|
|
15198
15814
|
const showBadge = !!tabCounts;
|
|
15199
15815
|
const badge = tabCounts ? tabCounts.current !== tabCounts.total ? `${tabCounts.current}/${tabCounts.total}` : `${tabCounts.total}` : "";
|
|
15200
15816
|
return /* @__PURE__ */ jsx$1("box", {
|
|
15817
|
+
onMouseDown: (event) => {
|
|
15818
|
+
event.stopPropagation();
|
|
15819
|
+
event.preventDefault();
|
|
15820
|
+
onSelect(id);
|
|
15821
|
+
},
|
|
15822
|
+
onMouseOver: () => setHoveredTab(id),
|
|
15823
|
+
onMouseOut: () => setHoveredTab((current) => current === id ? null : current),
|
|
15201
15824
|
style: {
|
|
15202
15825
|
paddingLeft: 1,
|
|
15203
15826
|
paddingRight: 1,
|
|
@@ -15207,10 +15830,10 @@ function TabStrip({ order, active, counts }) {
|
|
|
15207
15830
|
children: /* @__PURE__ */ jsxs("text", {
|
|
15208
15831
|
wrapMode: "none",
|
|
15209
15832
|
children: [/* @__PURE__ */ jsx$1("span", {
|
|
15210
|
-
fg: isActive ? COLOR.brand : COLOR.dim,
|
|
15833
|
+
fg: isActive ? COLOR.brand : hovered ? COLOR.accent : COLOR.dim,
|
|
15211
15834
|
children: label
|
|
15212
15835
|
}), showBadge && /* @__PURE__ */ jsx$1("span", {
|
|
15213
|
-
fg: isActive ? COLOR.brand : COLOR.mute,
|
|
15836
|
+
fg: isActive ? COLOR.brand : hovered ? COLOR.accent : COLOR.mute,
|
|
15214
15837
|
children: ` ${badge}`
|
|
15215
15838
|
})]
|
|
15216
15839
|
})
|
|
@@ -15218,7 +15841,7 @@ function TabStrip({ order, active, counts }) {
|
|
|
15218
15841
|
})
|
|
15219
15842
|
});
|
|
15220
15843
|
}
|
|
15221
|
-
function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKey }) {
|
|
15844
|
+
function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKey, onRowClick }) {
|
|
15222
15845
|
const { settings } = useSettings();
|
|
15223
15846
|
if (items.length === 0) return /* @__PURE__ */ jsx$1(EmptyRow, { label: query ? `no settings match "${query}"` : "no settings" });
|
|
15224
15847
|
const descCols = Math.max(0, contentCols - 1 - 1 - 6);
|
|
@@ -15229,6 +15852,7 @@ function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKe
|
|
|
15229
15852
|
const bg = focused ? highlightBg : void 0;
|
|
15230
15853
|
const id = anchorIdFor(i);
|
|
15231
15854
|
if (item.kind === "toggle") return /* @__PURE__ */ jsx$1(ToggleRow, {
|
|
15855
|
+
onClick: (zone) => onRowClick?.(i, zone),
|
|
15232
15856
|
id,
|
|
15233
15857
|
label: item.label,
|
|
15234
15858
|
description: truncateToCols(item.description, descCols),
|
|
@@ -15240,6 +15864,7 @@ function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKe
|
|
|
15240
15864
|
const current = settings[item.key];
|
|
15241
15865
|
const opt = item.options.find((o) => o.value === current);
|
|
15242
15866
|
return /* @__PURE__ */ jsx$1(ChoiceRow, {
|
|
15867
|
+
onClick: () => onRowClick?.(i),
|
|
15243
15868
|
id,
|
|
15244
15869
|
label: item.label,
|
|
15245
15870
|
description: truncateToCols(item.description, descCols),
|
|
@@ -15250,6 +15875,7 @@ function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKe
|
|
|
15250
15875
|
}, item.key);
|
|
15251
15876
|
}
|
|
15252
15877
|
if (item.kind === "input") return /* @__PURE__ */ jsx$1(InputRow, {
|
|
15878
|
+
onClick: () => onRowClick?.(i),
|
|
15253
15879
|
id,
|
|
15254
15880
|
label: item.label,
|
|
15255
15881
|
description: truncateToCols(item.description, descCols),
|
|
@@ -15270,7 +15896,7 @@ function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKe
|
|
|
15270
15896
|
});
|
|
15271
15897
|
}
|
|
15272
15898
|
const EXTENSION_CONFIG_INDENT = 3;
|
|
15273
|
-
function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCount, cursor, highlightBg, query, contentCols, editing, inputRef, onCommitEdit, modelCatalog, onApplyModelEdit, onCancelEdit, actionStatus, actionProbes }) {
|
|
15899
|
+
function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCount, cursor, highlightBg, query, contentCols, editing, inputRef, onCommitEdit, modelCatalog, onApplyModelEdit, onCancelEdit, actionStatus, actionProbes, onRowClick }) {
|
|
15274
15900
|
const COLOR = useColors();
|
|
15275
15901
|
const home = homedir();
|
|
15276
15902
|
if (totalCount === 0) return /* @__PURE__ */ jsxs("box", {
|
|
@@ -15420,6 +16046,7 @@ function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCo
|
|
|
15420
16046
|
if (item.type === "action") {
|
|
15421
16047
|
const status = actionStatus && actionStatus.extName === group.ext.name && actionStatus.key === item.key ? actionStatus : null;
|
|
15422
16048
|
childEls.push(/* @__PURE__ */ jsx$1(ConfigActionRow, {
|
|
16049
|
+
onClick: () => onRowClick?.(index),
|
|
15423
16050
|
id: anchorIdFor(index),
|
|
15424
16051
|
indent: EXTENSION_CONFIG_INDENT,
|
|
15425
16052
|
label: item.label,
|
|
@@ -15430,6 +16057,7 @@ function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCo
|
|
|
15430
16057
|
bg: childBg
|
|
15431
16058
|
}, item.key));
|
|
15432
16059
|
} else if (item.type === "boolean") childEls.push(/* @__PURE__ */ jsx$1(ToggleRow, {
|
|
16060
|
+
onClick: (zone) => onRowClick?.(index, zone),
|
|
15433
16061
|
id: anchorIdFor(index),
|
|
15434
16062
|
indent: EXTENSION_CONFIG_INDENT,
|
|
15435
16063
|
label: item.label,
|
|
@@ -15441,6 +16069,7 @@ function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCo
|
|
|
15441
16069
|
else if (item.type === "enum") {
|
|
15442
16070
|
const opt = item.options.find((o) => o.value === value);
|
|
15443
16071
|
childEls.push(/* @__PURE__ */ jsx$1(ChoiceRow, {
|
|
16072
|
+
onClick: () => onRowClick?.(index),
|
|
15444
16073
|
id: anchorIdFor(index),
|
|
15445
16074
|
indent: EXTENSION_CONFIG_INDENT,
|
|
15446
16075
|
label: item.label,
|
|
@@ -15489,6 +16118,11 @@ function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCo
|
|
|
15489
16118
|
id: anchorIdFor(group.index),
|
|
15490
16119
|
wrapMode: "none",
|
|
15491
16120
|
bg,
|
|
16121
|
+
onMouseDown: onRowClick && ((event) => {
|
|
16122
|
+
event.stopPropagation();
|
|
16123
|
+
event.preventDefault();
|
|
16124
|
+
onRowClick(group.index, inCheckboxZone(event, 4) ? "checkbox" : "row");
|
|
16125
|
+
}),
|
|
15492
16126
|
children: [
|
|
15493
16127
|
/* @__PURE__ */ jsx$1("span", {
|
|
15494
16128
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -15568,11 +16202,16 @@ function CreateExtensionButton() {
|
|
|
15568
16202
|
})]
|
|
15569
16203
|
});
|
|
15570
16204
|
}
|
|
15571
|
-
function ConfigActionRow({ id, label, description, status, probe, focused, bg, indent = 0 }) {
|
|
16205
|
+
function ConfigActionRow({ id, label, description, status, probe, focused, bg, indent = 0, onClick }) {
|
|
15572
16206
|
const COLOR = useColors();
|
|
15573
16207
|
const statusText = (status?.state === "busy" ? "running…" : status?.text) ?? probe?.message;
|
|
15574
16208
|
const statusColor = status ? status.state === "error" ? COLOR.error : status.state === "busy" ? COLOR.mute : COLOR.accent : probe ? probe.state === "error" ? COLOR.error : probe.state === "off" ? COLOR.mute : COLOR.accent : COLOR.mute;
|
|
15575
16209
|
return /* @__PURE__ */ jsxs("box", {
|
|
16210
|
+
onMouseDown: onClick && ((event) => {
|
|
16211
|
+
event.stopPropagation();
|
|
16212
|
+
event.preventDefault();
|
|
16213
|
+
onClick();
|
|
16214
|
+
}),
|
|
15576
16215
|
id,
|
|
15577
16216
|
style: {
|
|
15578
16217
|
flexDirection: "column",
|
|
@@ -15745,7 +16384,7 @@ function ConfigModelPickerRow({ id, label, description, catalog, multi, initial,
|
|
|
15745
16384
|
]
|
|
15746
16385
|
});
|
|
15747
16386
|
}
|
|
15748
|
-
function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query, contentCols }) {
|
|
16387
|
+
function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query, contentCols, onRowClick }) {
|
|
15749
16388
|
const COLOR = useColors();
|
|
15750
16389
|
if (totalCount === 0) return /* @__PURE__ */ jsxs("box", {
|
|
15751
16390
|
style: { flexDirection: "column" },
|
|
@@ -15790,6 +16429,11 @@ function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query,
|
|
|
15790
16429
|
const description = truncateToCols(entry.description ?? "", descCols);
|
|
15791
16430
|
const origin = skillOriginLabel(entry);
|
|
15792
16431
|
return /* @__PURE__ */ jsxs("box", {
|
|
16432
|
+
onMouseDown: onRowClick && ((event) => {
|
|
16433
|
+
event.stopPropagation();
|
|
16434
|
+
event.preventDefault();
|
|
16435
|
+
onRowClick(i, "row");
|
|
16436
|
+
}),
|
|
15793
16437
|
id: anchorIdFor(i),
|
|
15794
16438
|
style: {
|
|
15795
16439
|
flexDirection: "column",
|
|
@@ -15800,6 +16444,11 @@ function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query,
|
|
|
15800
16444
|
},
|
|
15801
16445
|
children: [/* @__PURE__ */ jsxs("text", {
|
|
15802
16446
|
wrapMode: "none",
|
|
16447
|
+
onMouseDown: onRowClick && ((event) => {
|
|
16448
|
+
event.stopPropagation();
|
|
16449
|
+
event.preventDefault();
|
|
16450
|
+
onRowClick(i, inCheckboxZone(event, 2) ? "checkbox" : "row");
|
|
16451
|
+
}),
|
|
15803
16452
|
children: [
|
|
15804
16453
|
/* @__PURE__ */ jsx$1("span", {
|
|
15805
16454
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -15827,7 +16476,7 @@ function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query,
|
|
|
15827
16476
|
})
|
|
15828
16477
|
});
|
|
15829
16478
|
}
|
|
15830
|
-
function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServer, toolsRefreshing, expanded, totalCount, cursor, highlightBg, query, errors, authState, contentCols }) {
|
|
16479
|
+
function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServer, toolsRefreshing, expanded, totalCount, cursor, highlightBg, query, errors, authState, contentCols, onRowClick }) {
|
|
15831
16480
|
const COLOR = useColors();
|
|
15832
16481
|
const home = homedir();
|
|
15833
16482
|
if (totalCount === 0) return /* @__PURE__ */ jsxs("box", {
|
|
@@ -15897,6 +16546,7 @@ function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServe
|
|
|
15897
16546
|
children: [renderMcpErrors(errors, home, COLOR.warn, COLOR.dim), groups.map((group) => /* @__PURE__ */ jsxs("box", {
|
|
15898
16547
|
style: { flexDirection: "column" },
|
|
15899
16548
|
children: [renderServerListRow({
|
|
16549
|
+
onClick: onRowClick ? (zone) => onRowClick(group.serverIndex, zone) : void 0,
|
|
15900
16550
|
entry: group.server.entry,
|
|
15901
16551
|
focused: group.serverIndex === cursor,
|
|
15902
16552
|
bg: group.serverIndex === cursor ? highlightBg : void 0,
|
|
@@ -15912,6 +16562,7 @@ function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServe
|
|
|
15912
16562
|
const focused = index === cursor;
|
|
15913
16563
|
const bg = focused ? highlightBg : void 0;
|
|
15914
16564
|
if (row.kind === "tool") return renderToolListRow({
|
|
16565
|
+
onClick: onRowClick ? (zone) => onRowClick(index, zone) : void 0,
|
|
15915
16566
|
serverName: row.serverName,
|
|
15916
16567
|
tool: row.tool,
|
|
15917
16568
|
focused,
|
|
@@ -15933,7 +16584,7 @@ function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServe
|
|
|
15933
16584
|
}, `group:${group.server.entry.config.name}`))]
|
|
15934
16585
|
});
|
|
15935
16586
|
}
|
|
15936
|
-
function renderServerListRow({ entry, focused, bg, enabled, expanded, toolEnabledSet, toolTotal, anchorId, status, COLOR, contentCols }) {
|
|
16587
|
+
function renderServerListRow({ onClick, entry, focused, bg, enabled, expanded, toolEnabledSet, toolTotal, anchorId, status, COLOR, contentCols }) {
|
|
15937
16588
|
const name = entry.config.name;
|
|
15938
16589
|
const chevron = expanded ? "▾" : "▸";
|
|
15939
16590
|
const toolCountChip = toolEnabledSet && typeof toolTotal === "number" ? ` (${toolEnabledSet.size}/${toolTotal})` : "";
|
|
@@ -15944,6 +16595,11 @@ function renderServerListRow({ entry, focused, bg, enabled, expanded, toolEnable
|
|
|
15944
16595
|
id: anchorId,
|
|
15945
16596
|
wrapMode: "none",
|
|
15946
16597
|
bg,
|
|
16598
|
+
onMouseDown: onClick && ((event) => {
|
|
16599
|
+
event.stopPropagation();
|
|
16600
|
+
event.preventDefault();
|
|
16601
|
+
onClick(inCheckboxZone(event, 4) ? "checkbox" : "row");
|
|
16602
|
+
}),
|
|
15947
16603
|
children: [
|
|
15948
16604
|
/* @__PURE__ */ jsx$1("span", {
|
|
15949
16605
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -15975,13 +16631,18 @@ function renderServerListRow({ entry, focused, bg, enabled, expanded, toolEnable
|
|
|
15975
16631
|
}
|
|
15976
16632
|
const TOOL_ROW_INDENT$1 = " ";
|
|
15977
16633
|
const TOOL_ROW_FOCUS_INDENT$1 = " ▶ ";
|
|
15978
|
-
function renderToolListRow({ serverName, tool, focused, bg, enabled, anchorId, COLOR, contentCols }) {
|
|
16634
|
+
function renderToolListRow({ onClick, serverName, tool, focused, bg, enabled, anchorId, COLOR, contentCols }) {
|
|
15979
16635
|
const descBudget = Math.max(0, contentCols - 6 - 4 - tool.name.length - 2);
|
|
15980
16636
|
const description = truncateToCols(tool.description ?? "", descBudget);
|
|
15981
16637
|
return /* @__PURE__ */ jsxs("text", {
|
|
15982
16638
|
id: anchorId,
|
|
15983
16639
|
wrapMode: "none",
|
|
15984
16640
|
bg,
|
|
16641
|
+
onMouseDown: onClick && ((event) => {
|
|
16642
|
+
event.stopPropagation();
|
|
16643
|
+
event.preventDefault();
|
|
16644
|
+
onClick(inCheckboxZone(event, 6) ? "checkbox" : "row");
|
|
16645
|
+
}),
|
|
15985
16646
|
children: [
|
|
15986
16647
|
/* @__PURE__ */ jsx$1("span", {
|
|
15987
16648
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -16204,9 +16865,14 @@ function AuthenticationList({ view, providers, cursor, highlightBg, query }) {
|
|
|
16204
16865
|
]
|
|
16205
16866
|
});
|
|
16206
16867
|
}
|
|
16207
|
-
function ToggleRow({ id, label, description, enabled, focused, bg, indent = 0 }) {
|
|
16868
|
+
function ToggleRow({ id, label, description, enabled, focused, bg, indent = 0, onClick }) {
|
|
16208
16869
|
const COLOR = useColors();
|
|
16209
16870
|
return /* @__PURE__ */ jsxs("box", {
|
|
16871
|
+
onMouseDown: onClick && ((event) => {
|
|
16872
|
+
event.stopPropagation();
|
|
16873
|
+
event.preventDefault();
|
|
16874
|
+
onClick("row");
|
|
16875
|
+
}),
|
|
16210
16876
|
id,
|
|
16211
16877
|
style: {
|
|
16212
16878
|
flexDirection: "column",
|
|
@@ -16217,6 +16883,11 @@ function ToggleRow({ id, label, description, enabled, focused, bg, indent = 0 })
|
|
|
16217
16883
|
},
|
|
16218
16884
|
children: [/* @__PURE__ */ jsxs("text", {
|
|
16219
16885
|
wrapMode: "none",
|
|
16886
|
+
onMouseDown: onClick && ((event) => {
|
|
16887
|
+
event.stopPropagation();
|
|
16888
|
+
event.preventDefault();
|
|
16889
|
+
onClick(inCheckboxZone(event, 2) ? "checkbox" : "row");
|
|
16890
|
+
}),
|
|
16220
16891
|
children: [
|
|
16221
16892
|
/* @__PURE__ */ jsx$1("span", {
|
|
16222
16893
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -16238,9 +16909,14 @@ function ToggleRow({ id, label, description, enabled, focused, bg, indent = 0 })
|
|
|
16238
16909
|
})]
|
|
16239
16910
|
});
|
|
16240
16911
|
}
|
|
16241
|
-
function ChoiceRow({ id, label, description, value, cyclable, focused, bg, indent = 0 }) {
|
|
16912
|
+
function ChoiceRow({ id, label, description, value, cyclable, focused, bg, indent = 0, onClick }) {
|
|
16242
16913
|
const COLOR = useColors();
|
|
16243
16914
|
return /* @__PURE__ */ jsxs("box", {
|
|
16915
|
+
onMouseDown: onClick && ((event) => {
|
|
16916
|
+
event.stopPropagation();
|
|
16917
|
+
event.preventDefault();
|
|
16918
|
+
onClick();
|
|
16919
|
+
}),
|
|
16244
16920
|
id,
|
|
16245
16921
|
style: {
|
|
16246
16922
|
flexDirection: "column",
|
|
@@ -16284,9 +16960,14 @@ function ChoiceRow({ id, label, description, value, cyclable, focused, bg, inden
|
|
|
16284
16960
|
})]
|
|
16285
16961
|
});
|
|
16286
16962
|
}
|
|
16287
|
-
function ActionRow$1({ id, label, description, focused, bg }) {
|
|
16963
|
+
function ActionRow$1({ id, label, description, focused, bg, onClick }) {
|
|
16288
16964
|
const COLOR = useColors();
|
|
16289
16965
|
return /* @__PURE__ */ jsxs("box", {
|
|
16966
|
+
onMouseDown: onClick && ((event) => {
|
|
16967
|
+
event.stopPropagation();
|
|
16968
|
+
event.preventDefault();
|
|
16969
|
+
onClick();
|
|
16970
|
+
}),
|
|
16290
16971
|
id,
|
|
16291
16972
|
style: {
|
|
16292
16973
|
flexDirection: "column",
|
|
@@ -16322,10 +17003,15 @@ function ActionRow$1({ id, label, description, focused, bg }) {
|
|
|
16322
17003
|
})]
|
|
16323
17004
|
});
|
|
16324
17005
|
}
|
|
16325
|
-
function InputRow({ id, label, description, value, placeholder, editing, focused, bg }) {
|
|
17006
|
+
function InputRow({ id, label, description, value, placeholder, editing, focused, bg, onClick }) {
|
|
16326
17007
|
const COLOR = useColors();
|
|
16327
17008
|
const hasValue = value.length > 0;
|
|
16328
17009
|
return /* @__PURE__ */ jsxs("box", {
|
|
17010
|
+
onMouseDown: onClick && ((event) => {
|
|
17011
|
+
event.stopPropagation();
|
|
17012
|
+
event.preventDefault();
|
|
17013
|
+
onClick();
|
|
17014
|
+
}),
|
|
16329
17015
|
id,
|
|
16330
17016
|
style: {
|
|
16331
17017
|
flexDirection: "column",
|
|
@@ -16379,29 +17065,7 @@ function EmptyRow({ label }) {
|
|
|
16379
17065
|
});
|
|
16380
17066
|
}
|
|
16381
17067
|
function renderMcpDetailPanel(entry, status, COLOR) {
|
|
16382
|
-
if (status.kind === "authorizing")
|
|
16383
|
-
if (!status.url) return /* @__PURE__ */ jsxs("box", {
|
|
16384
|
-
style: {
|
|
16385
|
-
flexDirection: "column",
|
|
16386
|
-
border: ["top"],
|
|
16387
|
-
borderColor: COLOR.border,
|
|
16388
|
-
paddingTop: 1
|
|
16389
|
-
},
|
|
16390
|
-
children: [/* @__PURE__ */ jsx$1("text", {
|
|
16391
|
-
fg: COLOR.brand,
|
|
16392
|
-
children: `Authorizing ${entry.config.name}`
|
|
16393
|
-
}), /* @__PURE__ */ jsx$1("text", {
|
|
16394
|
-
fg: COLOR.dim,
|
|
16395
|
-
children: "Starting login flow…"
|
|
16396
|
-
})]
|
|
16397
|
-
});
|
|
16398
|
-
return /* @__PURE__ */ jsx$1(McpAuthorizingPanel, {
|
|
16399
|
-
serverName: entry.config.name,
|
|
16400
|
-
authUrl: status.url,
|
|
16401
|
-
maxLineWidth: 154,
|
|
16402
|
-
inputFocused: true
|
|
16403
|
-
});
|
|
16404
|
-
}
|
|
17068
|
+
if (status.kind === "authorizing") return null;
|
|
16405
17069
|
if (status.kind === "error") return /* @__PURE__ */ jsxs("box", {
|
|
16406
17070
|
style: {
|
|
16407
17071
|
flexDirection: "column",
|
|
@@ -16501,162 +17165,96 @@ function renderMcpErrors(errors, home, warnColor, dimColor) {
|
|
|
16501
17165
|
}, err.path))
|
|
16502
17166
|
});
|
|
16503
17167
|
}
|
|
16504
|
-
function Hints({ activeTab, focusedMcp, focusedMcpRow, focusedMcpStatus, canRefreshSkills, canRefreshMcps, canEditExtension, canCreateExtension, canUpdateExtension, canRemoveExtension, canInstallExtension, canInstallSkill, canAddMcp, canRemoveSkill, canRemoveMcp, focusedExtensionExpandable }) {
|
|
17168
|
+
function Hints({ activeTab, authorizing = false, focusedMcp, focusedMcpRow, focusedMcpStatus, canRefreshSkills, canRefreshMcps, canEditExtension, canCreateExtension, canUpdateExtension, canRemoveExtension, canInstallExtension, canInstallSkill, canAddMcp, canRemoveSkill, canRemoveMcp, focusedExtensionExpandable }) {
|
|
16505
17169
|
const COLOR = useColors();
|
|
16506
17170
|
const onServerRow = focusedMcpRow?.kind === "server";
|
|
16507
17171
|
const showLogin = activeTab === "mcps" && onServerRow && !!focusedMcp && !!focusedMcpStatus && canLogin$1(focusedMcp, focusedMcpStatus);
|
|
16508
17172
|
const showLogout = activeTab === "mcps" && onServerRow && !!focusedMcpStatus && canLogout$1(focusedMcpStatus);
|
|
16509
|
-
const showCancel = activeTab === "mcps" &&
|
|
17173
|
+
const showCancel = activeTab === "mcps" && authorizing;
|
|
16510
17174
|
const showRefresh = activeTab === "skills" && canRefreshSkills || activeTab === "mcps" && canRefreshMcps;
|
|
16511
|
-
return /* @__PURE__ */
|
|
16512
|
-
|
|
16513
|
-
|
|
16514
|
-
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
"
|
|
16519
|
-
|
|
16520
|
-
|
|
16521
|
-
|
|
16522
|
-
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
|
|
16535
|
-
|
|
16536
|
-
|
|
16537
|
-
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
|
|
16542
|
-
|
|
16543
|
-
|
|
16544
|
-
|
|
16545
|
-
|
|
16546
|
-
|
|
16547
|
-
|
|
16548
|
-
|
|
16549
|
-
|
|
16550
|
-
|
|
16551
|
-
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
16556
|
-
|
|
16557
|
-
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
|
|
16561
|
-
|
|
16562
|
-
|
|
16563
|
-
|
|
16564
|
-
|
|
16565
|
-
|
|
16566
|
-
|
|
16567
|
-
|
|
16568
|
-
|
|
16569
|
-
|
|
16570
|
-
|
|
16571
|
-
|
|
16572
|
-
|
|
16573
|
-
|
|
16574
|
-
|
|
16575
|
-
|
|
16576
|
-
|
|
16577
|
-
|
|
16578
|
-
|
|
16579
|
-
|
|
16580
|
-
|
|
16581
|
-
|
|
16582
|
-
|
|
16583
|
-
|
|
16584
|
-
|
|
16585
|
-
|
|
16586
|
-
|
|
16587
|
-
|
|
16588
|
-
|
|
16589
|
-
|
|
16590
|
-
|
|
16591
|
-
|
|
16592
|
-
|
|
16593
|
-
|
|
16594
|
-
] }),
|
|
16595
|
-
activeTab === "skills" && canRemoveSkill && /* @__PURE__ */ jsxs("span", { children: [
|
|
16596
|
-
" · ",
|
|
16597
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
16598
|
-
fg: COLOR.warn,
|
|
16599
|
-
children: "ctrl+x"
|
|
16600
|
-
}),
|
|
16601
|
-
" delete"
|
|
16602
|
-
] }),
|
|
16603
|
-
activeTab === "mcps" && canAddMcp && /* @__PURE__ */ jsxs("span", { children: [
|
|
16604
|
-
" · ",
|
|
16605
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
16606
|
-
fg: COLOR.warn,
|
|
16607
|
-
children: "ctrl+g"
|
|
16608
|
-
}),
|
|
16609
|
-
" add server"
|
|
16610
|
-
] }),
|
|
16611
|
-
activeTab === "mcps" && canRemoveMcp && onServerRow && /* @__PURE__ */ jsxs("span", { children: [
|
|
16612
|
-
" · ",
|
|
16613
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
16614
|
-
fg: COLOR.warn,
|
|
16615
|
-
children: "ctrl+x"
|
|
16616
|
-
}),
|
|
16617
|
-
" remove"
|
|
16618
|
-
] }),
|
|
16619
|
-
showLogin && /* @__PURE__ */ jsxs("span", { children: [
|
|
16620
|
-
" · ",
|
|
16621
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
16622
|
-
fg: COLOR.warn,
|
|
16623
|
-
children: "ctrl+L"
|
|
16624
|
-
}),
|
|
16625
|
-
" login"
|
|
16626
|
-
] }),
|
|
16627
|
-
showLogout && /* @__PURE__ */ jsxs("span", { children: [
|
|
16628
|
-
" · ",
|
|
16629
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
16630
|
-
fg: COLOR.warn,
|
|
16631
|
-
children: "ctrl+O"
|
|
16632
|
-
}),
|
|
16633
|
-
" logout"
|
|
16634
|
-
] }),
|
|
16635
|
-
showRefresh && /* @__PURE__ */ jsxs("span", { children: [
|
|
16636
|
-
" · ",
|
|
16637
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
16638
|
-
fg: COLOR.warn,
|
|
16639
|
-
children: "ctrl+r"
|
|
16640
|
-
}),
|
|
16641
|
-
" refresh"
|
|
16642
|
-
] }),
|
|
16643
|
-
showCancel ? /* @__PURE__ */ jsxs("span", { children: [
|
|
16644
|
-
" · ",
|
|
16645
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
16646
|
-
fg: COLOR.warn,
|
|
16647
|
-
children: "esc"
|
|
16648
|
-
}),
|
|
16649
|
-
" cancel"
|
|
16650
|
-
] }) : /* @__PURE__ */ jsxs("span", { children: [
|
|
16651
|
-
" · ",
|
|
16652
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
16653
|
-
fg: COLOR.warn,
|
|
16654
|
-
children: "esc"
|
|
16655
|
-
}),
|
|
16656
|
-
" close"
|
|
16657
|
-
] })
|
|
16658
|
-
]
|
|
16659
|
-
});
|
|
17175
|
+
return /* @__PURE__ */ jsx$1(HintRow, { hints: [
|
|
17176
|
+
{
|
|
17177
|
+
key: "←→",
|
|
17178
|
+
label: "tabs"
|
|
17179
|
+
},
|
|
17180
|
+
{
|
|
17181
|
+
key: "↑↓",
|
|
17182
|
+
label: activeTab === "keybindings" || activeTab === "logs" ? "scroll" : "navigate"
|
|
17183
|
+
},
|
|
17184
|
+
...activeTab === "logs" ? [{
|
|
17185
|
+
key: "ctrl+l",
|
|
17186
|
+
label: "level"
|
|
17187
|
+
}, {
|
|
17188
|
+
key: "",
|
|
17189
|
+
label: "type to filter"
|
|
17190
|
+
}] : [{
|
|
17191
|
+
key: "↵",
|
|
17192
|
+
label: isCategoryTab(activeTab) ? "toggle/cycle/select" : activeTab === "keybindings" ? "edit file" : activeTab === "authentication" ? "switch / re-authenticate" : "toggle"
|
|
17193
|
+
}],
|
|
17194
|
+
...activeTab === "mcps" && focusedMcpRow ? [{
|
|
17195
|
+
key: "tab",
|
|
17196
|
+
label: focusedMcpRow.kind === "server" ? "expand/collapse" : "collapse"
|
|
17197
|
+
}] : [],
|
|
17198
|
+
...activeTab === "extensions" && focusedExtensionExpandable ? [{
|
|
17199
|
+
key: "tab",
|
|
17200
|
+
label: "settings"
|
|
17201
|
+
}] : [],
|
|
17202
|
+
...activeTab === "extensions" && canEditExtension ? [{
|
|
17203
|
+
key: "ctrl+e",
|
|
17204
|
+
label: "edit"
|
|
17205
|
+
}] : [],
|
|
17206
|
+
...activeTab === "extensions" && canCreateExtension ? [{
|
|
17207
|
+
key: "ctrl+a",
|
|
17208
|
+
label: "create"
|
|
17209
|
+
}] : [],
|
|
17210
|
+
...activeTab === "extensions" && canUpdateExtension ? [{
|
|
17211
|
+
key: "ctrl+u",
|
|
17212
|
+
label: "update"
|
|
17213
|
+
}] : [],
|
|
17214
|
+
...activeTab === "extensions" && canRemoveExtension ? [{
|
|
17215
|
+
key: "ctrl+x",
|
|
17216
|
+
label: "remove"
|
|
17217
|
+
}] : [],
|
|
17218
|
+
...activeTab === "extensions" && canInstallExtension ? [{
|
|
17219
|
+
key: "ctrl+g",
|
|
17220
|
+
label: "install"
|
|
17221
|
+
}] : [],
|
|
17222
|
+
...activeTab === "skills" && canInstallSkill ? [{
|
|
17223
|
+
key: "ctrl+g",
|
|
17224
|
+
label: "install"
|
|
17225
|
+
}] : [],
|
|
17226
|
+
...activeTab === "skills" && canRemoveSkill ? [{
|
|
17227
|
+
key: "ctrl+x",
|
|
17228
|
+
label: "delete"
|
|
17229
|
+
}] : [],
|
|
17230
|
+
...activeTab === "mcps" && canAddMcp ? [{
|
|
17231
|
+
key: "ctrl+g",
|
|
17232
|
+
label: "add server"
|
|
17233
|
+
}] : [],
|
|
17234
|
+
...activeTab === "mcps" && canRemoveMcp && onServerRow ? [{
|
|
17235
|
+
key: "ctrl+x",
|
|
17236
|
+
label: "remove"
|
|
17237
|
+
}] : [],
|
|
17238
|
+
...showLogin ? [{
|
|
17239
|
+
key: "ctrl+L",
|
|
17240
|
+
label: "login"
|
|
17241
|
+
}] : [],
|
|
17242
|
+
...showLogout ? [{
|
|
17243
|
+
key: "ctrl+O",
|
|
17244
|
+
label: "logout"
|
|
17245
|
+
}] : [],
|
|
17246
|
+
...showRefresh ? [{
|
|
17247
|
+
key: "ctrl+r",
|
|
17248
|
+
label: "refresh"
|
|
17249
|
+
}] : [],
|
|
17250
|
+
{
|
|
17251
|
+
key: "esc",
|
|
17252
|
+
label: showCancel ? "cancel" : "close"
|
|
17253
|
+
}
|
|
17254
|
+
].map((h) => ({
|
|
17255
|
+
...h,
|
|
17256
|
+
labelColor: COLOR.mute
|
|
17257
|
+
})) });
|
|
16660
17258
|
}
|
|
16661
17259
|
function generalCorpus(item) {
|
|
16662
17260
|
const parts = [item.label, item.description];
|
|
@@ -16796,7 +17394,10 @@ function composeTerminalTitle(opts) {
|
|
|
16796
17394
|
* bring it back later. No-op when `out` isn't a TTY.
|
|
16797
17395
|
*/
|
|
16798
17396
|
function saveTerminalTitle(out = process.stdout) {
|
|
16799
|
-
if (out.isTTY)
|
|
17397
|
+
if (!out.isTTY) return;
|
|
17398
|
+
try {
|
|
17399
|
+
out.write(TITLE_STACK_PUSH);
|
|
17400
|
+
} catch {}
|
|
16800
17401
|
}
|
|
16801
17402
|
/**
|
|
16802
17403
|
* Clear our title and pop the previously-saved one. No-op when `out`
|
|
@@ -16804,7 +17405,10 @@ function saveTerminalTitle(out = process.stdout) {
|
|
|
16804
17405
|
* otherwise the clear would wipe a title zidane never set.
|
|
16805
17406
|
*/
|
|
16806
17407
|
function restoreTerminalTitle(out = process.stdout) {
|
|
16807
|
-
if (out.isTTY)
|
|
17408
|
+
if (!out.isTTY) return;
|
|
17409
|
+
try {
|
|
17410
|
+
out.write(TITLE_STACK_RESTORE);
|
|
17411
|
+
} catch {}
|
|
16808
17412
|
}
|
|
16809
17413
|
//#endregion
|
|
16810
17414
|
//#region src/tui/todos-modal.tsx
|
|
@@ -17300,26 +17904,23 @@ function TurnDetailsModal({ turn, toolResultTurns = [], searchQuery, index, tota
|
|
|
17300
17904
|
children: "— no previewable content —"
|
|
17301
17905
|
})
|
|
17302
17906
|
}),
|
|
17303
|
-
editing ? /* @__PURE__ */
|
|
17304
|
-
|
|
17305
|
-
|
|
17306
|
-
|
|
17307
|
-
|
|
17308
|
-
|
|
17309
|
-
|
|
17310
|
-
|
|
17311
|
-
|
|
17312
|
-
|
|
17313
|
-
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
|
|
17319
|
-
|
|
17320
|
-
" cancel"
|
|
17321
|
-
]
|
|
17322
|
-
}) : /* @__PURE__ */ jsx$1(ActionRow, {
|
|
17907
|
+
editing ? /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
17908
|
+
{
|
|
17909
|
+
key: "↵",
|
|
17910
|
+
label: "save",
|
|
17911
|
+
labelColor: COLOR.dim
|
|
17912
|
+
},
|
|
17913
|
+
{
|
|
17914
|
+
key: "shift+↵",
|
|
17915
|
+
label: "newline",
|
|
17916
|
+
labelColor: COLOR.dim
|
|
17917
|
+
},
|
|
17918
|
+
{
|
|
17919
|
+
key: "esc",
|
|
17920
|
+
label: "cancel",
|
|
17921
|
+
labelColor: COLOR.dim
|
|
17922
|
+
}
|
|
17923
|
+
] }) : /* @__PURE__ */ jsx$1(ActionRow, {
|
|
17323
17924
|
pending,
|
|
17324
17925
|
copyStatus,
|
|
17325
17926
|
canCopy: fullText.length > 0,
|
|
@@ -17381,81 +17982,72 @@ function ActionRow({ pending, copyStatus, canCopy, canEdit, forkKey, deleteKey,
|
|
|
17381
17982
|
" cancel"
|
|
17382
17983
|
]
|
|
17383
17984
|
});
|
|
17384
|
-
if (copyStatus === "copied") return /* @__PURE__ */
|
|
17385
|
-
|
|
17386
|
-
|
|
17387
|
-
|
|
17388
|
-
|
|
17389
|
-
|
|
17390
|
-
|
|
17391
|
-
|
|
17392
|
-
|
|
17393
|
-
|
|
17394
|
-
|
|
17395
|
-
|
|
17396
|
-
|
|
17397
|
-
|
|
17398
|
-
|
|
17399
|
-
|
|
17400
|
-
|
|
17401
|
-
|
|
17402
|
-
|
|
17403
|
-
|
|
17404
|
-
|
|
17405
|
-
|
|
17406
|
-
|
|
17407
|
-
|
|
17408
|
-
|
|
17409
|
-
|
|
17410
|
-
|
|
17411
|
-
|
|
17412
|
-
|
|
17413
|
-
|
|
17414
|
-
|
|
17415
|
-
|
|
17416
|
-
|
|
17417
|
-
|
|
17418
|
-
|
|
17419
|
-
|
|
17420
|
-
|
|
17421
|
-
|
|
17422
|
-
|
|
17423
|
-
|
|
17424
|
-
|
|
17425
|
-
|
|
17426
|
-
|
|
17427
|
-
|
|
17428
|
-
|
|
17429
|
-
|
|
17430
|
-
|
|
17431
|
-
|
|
17432
|
-
|
|
17433
|
-
|
|
17434
|
-
|
|
17435
|
-
|
|
17436
|
-
|
|
17437
|
-
|
|
17438
|
-
|
|
17439
|
-
|
|
17440
|
-
|
|
17441
|
-
|
|
17442
|
-
|
|
17443
|
-
|
|
17444
|
-
|
|
17445
|
-
|
|
17446
|
-
|
|
17447
|
-
|
|
17448
|
-
|
|
17449
|
-
|
|
17450
|
-
}),
|
|
17451
|
-
canEdit ? " edit · " : " (no text) · ",
|
|
17452
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
17453
|
-
fg: COLOR.warn,
|
|
17454
|
-
children: "esc"
|
|
17455
|
-
}),
|
|
17456
|
-
" close"
|
|
17457
|
-
]
|
|
17458
|
-
});
|
|
17985
|
+
if (copyStatus === "copied") return /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
17986
|
+
{
|
|
17987
|
+
key: "",
|
|
17988
|
+
label: "✓ copied",
|
|
17989
|
+
labelColor: COLOR.accent
|
|
17990
|
+
},
|
|
17991
|
+
{
|
|
17992
|
+
key: forkKey,
|
|
17993
|
+
label: "fork",
|
|
17994
|
+
labelColor: COLOR.dim
|
|
17995
|
+
},
|
|
17996
|
+
{
|
|
17997
|
+
key: deleteKey,
|
|
17998
|
+
label: "delete",
|
|
17999
|
+
labelColor: COLOR.dim
|
|
18000
|
+
},
|
|
18001
|
+
{
|
|
18002
|
+
key: editKey,
|
|
18003
|
+
label: canEdit ? "edit" : "(no text)",
|
|
18004
|
+
keyColor: canEdit ? COLOR.warn : COLOR.mute,
|
|
18005
|
+
labelColor: COLOR.dim
|
|
18006
|
+
},
|
|
18007
|
+
{
|
|
18008
|
+
key: "esc",
|
|
18009
|
+
label: "close",
|
|
18010
|
+
labelColor: COLOR.dim
|
|
18011
|
+
}
|
|
18012
|
+
] });
|
|
18013
|
+
if (copyStatus === "failed") return /* @__PURE__ */ jsx$1(ModalHints, { hints: [{
|
|
18014
|
+
key: "",
|
|
18015
|
+
label: "copy failed (terminal may not support OSC 52)",
|
|
18016
|
+
labelColor: COLOR.error
|
|
18017
|
+
}, {
|
|
18018
|
+
key: "esc",
|
|
18019
|
+
label: "close",
|
|
18020
|
+
labelColor: COLOR.dim
|
|
18021
|
+
}] });
|
|
18022
|
+
return /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
18023
|
+
{
|
|
18024
|
+
key: forkKey,
|
|
18025
|
+
label: "fork",
|
|
18026
|
+
labelColor: COLOR.dim
|
|
18027
|
+
},
|
|
18028
|
+
{
|
|
18029
|
+
key: deleteKey,
|
|
18030
|
+
label: "delete",
|
|
18031
|
+
labelColor: COLOR.dim
|
|
18032
|
+
},
|
|
18033
|
+
{
|
|
18034
|
+
key: copyKey,
|
|
18035
|
+
label: canCopy ? "copy" : "(nothing to copy)",
|
|
18036
|
+
keyColor: canCopy ? COLOR.warn : COLOR.mute,
|
|
18037
|
+
labelColor: COLOR.dim
|
|
18038
|
+
},
|
|
18039
|
+
{
|
|
18040
|
+
key: editKey,
|
|
18041
|
+
label: canEdit ? "edit" : "(no text)",
|
|
18042
|
+
keyColor: canEdit ? COLOR.warn : COLOR.mute,
|
|
18043
|
+
labelColor: COLOR.dim
|
|
18044
|
+
},
|
|
18045
|
+
{
|
|
18046
|
+
key: "esc",
|
|
18047
|
+
label: "close",
|
|
18048
|
+
labelColor: COLOR.dim
|
|
18049
|
+
}
|
|
18050
|
+
] });
|
|
17459
18051
|
}
|
|
17460
18052
|
function buildPreviewEntries(turns, limit) {
|
|
17461
18053
|
const entries = [];
|
|
@@ -17592,10 +18184,20 @@ const BASH_PAINT_INTERVAL_MS = 100;
|
|
|
17592
18184
|
const BASH_RESULT_MAX_BYTES = 32 * 1024;
|
|
17593
18185
|
/** Rolling-tail window while output streams — matches the renderer's bash display cap. */
|
|
17594
18186
|
const BASH_STREAM_TAIL_LINES = 10;
|
|
17595
|
-
/**
|
|
18187
|
+
/**
|
|
18188
|
+
* Last `n` lines of `text` (terminal-style rolling tail for live bash
|
|
18189
|
+
* output). Backward newline scan, not `split` — this runs per output
|
|
18190
|
+
* chunk against the full accumulation (up to 1MB), and re-splitting the
|
|
18191
|
+
* whole snapshot every chunk is O(n²) in total streamed bytes.
|
|
18192
|
+
*/
|
|
17596
18193
|
function lastLines(text, n) {
|
|
17597
|
-
|
|
17598
|
-
|
|
18194
|
+
let idx = text.length;
|
|
18195
|
+
for (let i = 0; i < n; i++) {
|
|
18196
|
+
if (idx === 0) return text;
|
|
18197
|
+
idx = text.lastIndexOf("\n", idx - 1);
|
|
18198
|
+
if (idx === -1) return text;
|
|
18199
|
+
}
|
|
18200
|
+
return text.slice(idx + 1);
|
|
17599
18201
|
}
|
|
17600
18202
|
/**
|
|
17601
18203
|
* Poll cadence for out-of-band extension install detection (see the
|
|
@@ -17606,6 +18208,14 @@ const EXTENSION_WATCH_POLL_MS = 3e3;
|
|
|
17606
18208
|
/** LRU bound for cross-session search indexes (full lowercased text per session). */
|
|
17607
18209
|
const SESSION_SEARCH_INDEX_CACHE_MAX = 64;
|
|
17608
18210
|
/**
|
|
18211
|
+
* Byte budget for the same cache, using each handle's indexed-text size
|
|
18212
|
+
* (reported by the worker build). The count cap alone lets 64 huge
|
|
18213
|
+
* sessions pin hundreds of MB (index copy in the worker, plus any
|
|
18214
|
+
* main-thread fallback indexes); the budget evicts LRU-first once the
|
|
18215
|
+
* summed estimate crosses it, keeping worst-case retention predictable.
|
|
18216
|
+
*/
|
|
18217
|
+
const SESSION_SEARCH_INDEX_CACHE_MAX_BYTES = 64 * 1024 * 1024;
|
|
18218
|
+
/**
|
|
17609
18219
|
* Surface failures that are normally silenced (teardown / save) when the
|
|
17610
18220
|
* `ZIDANE_DEBUG` env var is set. Logging via `console.error` would otherwise
|
|
17611
18221
|
* trigger OpenTUI's error console overlay and clutter the UI for end users.
|
|
@@ -17847,6 +18457,9 @@ function AppShell() {
|
|
|
17847
18457
|
if (renderer.targetFps !== fps) renderer.targetFps = fps;
|
|
17848
18458
|
if (renderer.maxFps !== fps) renderer.maxFps = fps;
|
|
17849
18459
|
}, [renderer, settings.targetFps]);
|
|
18460
|
+
useEffect(() => {
|
|
18461
|
+
if (renderer.useMouse !== settings.mouseInteractions) renderer.useMouse = settings.mouseInteractions;
|
|
18462
|
+
}, [renderer, settings.mouseInteractions]);
|
|
17850
18463
|
const lastCopiedRef = useRef("");
|
|
17851
18464
|
useSelectionHandler((selection) => {
|
|
17852
18465
|
if (selection.isDragging) return;
|
|
@@ -18258,6 +18871,22 @@ function AppShell() {
|
|
|
18258
18871
|
*/
|
|
18259
18872
|
const [compacting, setCompacting] = useState(false);
|
|
18260
18873
|
/**
|
|
18874
|
+
* Live provider-retry indicator — set by `stream:retry` (and the bubbled
|
|
18875
|
+
* `child:stream:retry`, since a stalled subagent stalls the pipeline the
|
|
18876
|
+
* user is watching), cleared when the SAME source streams output again
|
|
18877
|
+
* or the run ends. Keyed by source (`'parent'` / childId) so a parallel
|
|
18878
|
+
* batch can't hide one child's still-active backoff behind a sibling's
|
|
18879
|
+
* output — the motivating /review case runs many children at once.
|
|
18880
|
+
* Drives the footer's `Retrying (n/max)` status; last retry wins the
|
|
18881
|
+
* single slot.
|
|
18882
|
+
*/
|
|
18883
|
+
const [retryInfo, setRetryInfo] = useState(null);
|
|
18884
|
+
/** Source-scoped functional clear — bails re-render when nothing matches (hot path: every stream delta). */
|
|
18885
|
+
const clearRetryInfo = useCallback((source) => setRetryInfo((prev) => prev !== null && prev.source === source ? null : prev), []);
|
|
18886
|
+
useEffect(() => {
|
|
18887
|
+
if (!busy) setRetryInfo((prev) => prev === null ? prev : null);
|
|
18888
|
+
}, [busy]);
|
|
18889
|
+
/**
|
|
18261
18890
|
* Rough token estimate of the in-flight compaction summary, painted
|
|
18262
18891
|
* next to the footer's "Compacting…" label (`null` = no live estimate
|
|
18263
18892
|
* yet). Fed by the loop's throttled `compact:progress` hook and the
|
|
@@ -18577,9 +19206,17 @@ function AppShell() {
|
|
|
18577
19206
|
store,
|
|
18578
19207
|
getAllowedTokens: () => chatReferenceTokensRef.current
|
|
18579
19208
|
}), [store]);
|
|
19209
|
+
const visibleChatCatalogCache = useRef(/* @__PURE__ */ new WeakMap());
|
|
18580
19210
|
const visibleChatCatalog = useCallback((catalog) => {
|
|
18581
|
-
const currentId = currentSessionIdRef.current;
|
|
18582
|
-
|
|
19211
|
+
const currentId = currentSessionIdRef.current ?? null;
|
|
19212
|
+
const hit = visibleChatCatalogCache.current.get(catalog);
|
|
19213
|
+
if (hit && hit.currentId === currentId) return hit.result;
|
|
19214
|
+
const result = currentId ? catalog.filter((entry) => entry.id !== currentId) : [...catalog];
|
|
19215
|
+
visibleChatCatalogCache.current.set(catalog, {
|
|
19216
|
+
currentId,
|
|
19217
|
+
result
|
|
19218
|
+
});
|
|
19219
|
+
return result;
|
|
18583
19220
|
}, []);
|
|
18584
19221
|
const ensureChatCatalog = useCallback(async () => {
|
|
18585
19222
|
const [projectList, allList] = await Promise.all([listSessionMeta(store, { projectRoot: projectDir }), listSessionMeta(store)]);
|
|
@@ -19181,8 +19818,26 @@ function AppShell() {
|
|
|
19181
19818
|
});
|
|
19182
19819
|
if (pendingAutoLoginMcpRef.current === name) pendingAutoLoginMcpRef.current = null;
|
|
19183
19820
|
});
|
|
19184
|
-
agent.hooks.hook("stream:thinking", ({ delta, turnId }) =>
|
|
19185
|
-
|
|
19821
|
+
agent.hooks.hook("stream:thinking", ({ delta, turnId }) => {
|
|
19822
|
+
clearRetryInfo("parent");
|
|
19823
|
+
stream.queueStreamDelta("thinking", delta, { turnId });
|
|
19824
|
+
});
|
|
19825
|
+
agent.hooks.hook("stream:text", ({ delta, turnId }) => {
|
|
19826
|
+
clearRetryInfo("parent");
|
|
19827
|
+
stream.queueStreamDelta("markdown", delta, { turnId });
|
|
19828
|
+
});
|
|
19829
|
+
agent.hooks.hook("stream:retry", ({ nextAttempt, maxAttempts }) => setRetryInfo({
|
|
19830
|
+
attempt: nextAttempt,
|
|
19831
|
+
max: maxAttempts,
|
|
19832
|
+
source: "parent"
|
|
19833
|
+
}));
|
|
19834
|
+
agent.hooks.hook("child:stream:retry", ({ nextAttempt, maxAttempts, childId }) => setRetryInfo({
|
|
19835
|
+
attempt: nextAttempt,
|
|
19836
|
+
max: maxAttempts,
|
|
19837
|
+
source: childId
|
|
19838
|
+
}));
|
|
19839
|
+
agent.hooks.hook("stream:error", () => clearRetryInfo("parent"));
|
|
19840
|
+
agent.hooks.hook("child:stream:error", ({ childId }) => clearRetryInfo(childId));
|
|
19186
19841
|
agent.hooks.hook("stream:server_tool_use", ({ id, name, input, turnId }) => {
|
|
19187
19842
|
stream.appendImmediate({
|
|
19188
19843
|
kind: "tool",
|
|
@@ -19432,6 +20087,7 @@ function AppShell() {
|
|
|
19432
20087
|
});
|
|
19433
20088
|
});
|
|
19434
20089
|
agent.hooks.hook("child:stream:thinking", ({ delta, childId, depth, turnId }) => {
|
|
20090
|
+
clearRetryInfo(childId);
|
|
19435
20091
|
stream.queueStreamDelta("thinking", delta, {
|
|
19436
20092
|
childId,
|
|
19437
20093
|
depth,
|
|
@@ -19439,6 +20095,7 @@ function AppShell() {
|
|
|
19439
20095
|
});
|
|
19440
20096
|
});
|
|
19441
20097
|
agent.hooks.hook("child:stream:text", ({ delta, childId, depth, turnId }) => {
|
|
20098
|
+
clearRetryInfo(childId);
|
|
19442
20099
|
stream.queueStreamDelta("markdown", delta, {
|
|
19443
20100
|
childId,
|
|
19444
20101
|
depth,
|
|
@@ -19512,6 +20169,7 @@ function AppShell() {
|
|
|
19512
20169
|
});
|
|
19513
20170
|
agent.hooks.hook("agent:done", () => {
|
|
19514
20171
|
pendingAnnotationsRef.current.clear();
|
|
20172
|
+
pruneTodosByRun(session);
|
|
19515
20173
|
});
|
|
19516
20174
|
subscribeMcpToolsCache(agent.hooks, { dataDir });
|
|
19517
20175
|
return agent;
|
|
@@ -19578,7 +20236,9 @@ function AppShell() {
|
|
|
19578
20236
|
const cachedLive = liveSessionSearchIndexRef.current;
|
|
19579
20237
|
if (cachedLive?.sessionId === meta.id && cachedLive.updatedAt === meta.updatedAt && cachedLive.turnCount === live.turns.length) index = cachedLive.index;
|
|
19580
20238
|
else {
|
|
20239
|
+
const staleLive = liveSessionSearchIndexRef.current;
|
|
19581
20240
|
index = await (historySearchWorkerRef.current ??= new HistorySearchWorkerClient()).build(live.turns, abortController.signal);
|
|
20241
|
+
if (staleLive) historySearchWorkerRef.current?.release(staleLive.index);
|
|
19582
20242
|
liveSessionSearchIndexRef.current = {
|
|
19583
20243
|
sessionId: meta.id,
|
|
19584
20244
|
updatedAt: meta.updatedAt,
|
|
@@ -19593,15 +20253,25 @@ function AppShell() {
|
|
|
19593
20253
|
} else {
|
|
19594
20254
|
const turns = await store.getTurns(meta.id);
|
|
19595
20255
|
index = await (historySearchWorkerRef.current ??= new HistorySearchWorkerClient()).build(turns, abortController.signal);
|
|
20256
|
+
historySearchWorkerRef.current?.slim(index);
|
|
19596
20257
|
const cache = sessionSearchCacheRef.current;
|
|
20258
|
+
const stale = cache.get(meta.id);
|
|
20259
|
+
if (stale) historySearchWorkerRef.current?.release(stale.index);
|
|
19597
20260
|
cache.set(meta.id, {
|
|
19598
20261
|
updatedAt: meta.updatedAt,
|
|
19599
20262
|
index
|
|
19600
20263
|
});
|
|
19601
|
-
|
|
20264
|
+
let totalBytes = 0;
|
|
20265
|
+
for (const entry of cache.values()) totalBytes += entry.index.bytes;
|
|
20266
|
+
while (cache.size > 1 && (cache.size > SESSION_SEARCH_INDEX_CACHE_MAX || totalBytes > SESSION_SEARCH_INDEX_CACHE_MAX_BYTES)) {
|
|
19602
20267
|
const oldest = cache.keys().next().value;
|
|
19603
20268
|
if (oldest === void 0) break;
|
|
20269
|
+
const evicted = cache.get(oldest);
|
|
19604
20270
|
cache.delete(oldest);
|
|
20271
|
+
if (evicted) {
|
|
20272
|
+
totalBytes -= evicted.index.bytes;
|
|
20273
|
+
historySearchWorkerRef.current?.release(evicted.index);
|
|
20274
|
+
}
|
|
19605
20275
|
}
|
|
19606
20276
|
}
|
|
19607
20277
|
if (generation !== sessionSearchGenerationRef.current) return;
|
|
@@ -19609,7 +20279,24 @@ function AppShell() {
|
|
|
19609
20279
|
if (match) matches.set(meta.id, match);
|
|
19610
20280
|
} catch (error) {
|
|
19611
20281
|
if (abortController.signal.aborted) throw abortController.signal.reason instanceof DOMException ? abortController.signal.reason : error;
|
|
19612
|
-
|
|
20282
|
+
const broken = sessionSearchCacheRef.current.get(meta.id);
|
|
20283
|
+
if (broken) {
|
|
20284
|
+
sessionSearchCacheRef.current.delete(meta.id);
|
|
20285
|
+
historySearchWorkerRef.current?.release(broken.index);
|
|
20286
|
+
try {
|
|
20287
|
+
const turns = await store.getTurns(meta.id);
|
|
20288
|
+
const retry = await (historySearchWorkerRef.current ??= new HistorySearchWorkerClient()).build(turns, abortController.signal);
|
|
20289
|
+
try {
|
|
20290
|
+
const match = await historySearchWorkerRef.current.history(retry, query, 3, abortController.signal);
|
|
20291
|
+
if (match) matches.set(meta.id, match);
|
|
20292
|
+
} finally {
|
|
20293
|
+
historySearchWorkerRef.current?.release(retry);
|
|
20294
|
+
}
|
|
20295
|
+
} catch (retryError) {
|
|
20296
|
+
if (abortController.signal.aborted) throw abortController.signal.reason instanceof DOMException ? abortController.signal.reason : retryError;
|
|
20297
|
+
debugLog("session content search retry failed", retryError);
|
|
20298
|
+
}
|
|
20299
|
+
} else debugLog("session content search skipped a session", error);
|
|
19613
20300
|
}
|
|
19614
20301
|
done++;
|
|
19615
20302
|
if (done === sessions.length || done % 4 === 0) setSessionContentSearchProgress({
|
|
@@ -20759,6 +21446,7 @@ function AppShell() {
|
|
|
20759
21446
|
const ctx = {
|
|
20760
21447
|
args: invocation.args,
|
|
20761
21448
|
argv: invocation.argv,
|
|
21449
|
+
invokedAs: invocation.invokedAs,
|
|
20762
21450
|
...attachments.length > 0 ? { attachments: attachments.map((a) => ({
|
|
20763
21451
|
name: a.name,
|
|
20764
21452
|
mediaType: a.mediaType,
|
|
@@ -21508,6 +22196,10 @@ function AppShell() {
|
|
|
21508
22196
|
const onLoginMcp = useCallback(async (name) => {
|
|
21509
22197
|
const entry = mcpsCatalogRef.current.find((d) => d.config.name === name);
|
|
21510
22198
|
if (!entry) return;
|
|
22199
|
+
for (const [other, ctrl] of mcpLoginAbortsRef.current) if (other !== name && !ctrl.signal.aborted) {
|
|
22200
|
+
debugLog(`mcp-login: refusing concurrent login for "${name}"`, `"${other}" is still authorizing`);
|
|
22201
|
+
return;
|
|
22202
|
+
}
|
|
21511
22203
|
mcpLoginAbortsRef.current.get(name)?.abort();
|
|
21512
22204
|
const ac = new AbortController();
|
|
21513
22205
|
mcpLoginAbortsRef.current.set(name, ac);
|
|
@@ -21519,6 +22211,7 @@ function AppShell() {
|
|
|
21519
22211
|
await loginMcpServer(entry.config, {
|
|
21520
22212
|
store: mcpCredentialStore,
|
|
21521
22213
|
signal: ac.signal,
|
|
22214
|
+
renderCallbackPage: renderDefaultCallbackPage,
|
|
21522
22215
|
hooks: agentRef.current?.hooks,
|
|
21523
22216
|
onAuthorizationUrl: (url) => tryOpenBrowser(url.toString())
|
|
21524
22217
|
});
|
|
@@ -21539,9 +22232,10 @@ function AppShell() {
|
|
|
21539
22232
|
]);
|
|
21540
22233
|
onLoginMcpRef.current = onLoginMcp;
|
|
21541
22234
|
const onLogoutMcp = useCallback((name) => {
|
|
22235
|
+
const hadTokens = !!mcpCredentialStore.load(name)?.tokens;
|
|
21542
22236
|
mcpCredentialStore.delete(name);
|
|
21543
22237
|
const entry = mcpsCatalogRef.current.find((d) => d.config.name === name);
|
|
21544
|
-
dispatchAuth(entry?.config.auth === "oauth" ? {
|
|
22238
|
+
dispatchAuth(entry?.config.auth === "oauth" || hadTokens ? {
|
|
21545
22239
|
type: "auth-required",
|
|
21546
22240
|
name,
|
|
21547
22241
|
reason: "no-tokens"
|
|
@@ -21610,6 +22304,7 @@ function AppShell() {
|
|
|
21610
22304
|
(async () => {
|
|
21611
22305
|
const cached = transcriptSearchIndexRef.current;
|
|
21612
22306
|
const index = cached?.sessionId === session.id && cached.events === events ? cached.index : await (historySearchWorkerRef.current ??= new HistorySearchWorkerClient()).build(turns, abortController.signal);
|
|
22307
|
+
if (cached && cached.index !== index) historySearchWorkerRef.current?.release(cached.index);
|
|
21613
22308
|
transcriptSearchIndexRef.current = {
|
|
21614
22309
|
sessionId: session.id,
|
|
21615
22310
|
events,
|
|
@@ -21737,7 +22432,14 @@ function AppShell() {
|
|
|
21737
22432
|
store,
|
|
21738
22433
|
...source.projectRoot ? { projectRoot: source.projectRoot } : {}
|
|
21739
22434
|
});
|
|
21740
|
-
|
|
22435
|
+
const rehomed = await rehomePersistedStubs(slice, resolvePersistDir({
|
|
22436
|
+
userDir: cacheDir,
|
|
22437
|
+
sessionId: source.id
|
|
22438
|
+
}), resolvePersistDir({
|
|
22439
|
+
userDir: cacheDir,
|
|
22440
|
+
sessionId: fork.id
|
|
22441
|
+
}));
|
|
22442
|
+
fork.setTurns(rehomed);
|
|
21741
22443
|
fork.setRuns(inheritedRuns);
|
|
21742
22444
|
try {
|
|
21743
22445
|
await fork.save();
|
|
@@ -21750,7 +22452,8 @@ function AppShell() {
|
|
|
21750
22452
|
}, [
|
|
21751
22453
|
picked,
|
|
21752
22454
|
store,
|
|
21753
|
-
activateSession
|
|
22455
|
+
activateSession,
|
|
22456
|
+
cacheDir
|
|
21754
22457
|
]);
|
|
21755
22458
|
const onDeleteTurn = useCallback(async (turnId) => {
|
|
21756
22459
|
const session = sessionRef.current;
|
|
@@ -22094,9 +22797,7 @@ function AppShell() {
|
|
|
22094
22797
|
onExportSession,
|
|
22095
22798
|
keybindings
|
|
22096
22799
|
]);
|
|
22097
|
-
const
|
|
22098
|
-
const id = selectedTurnId;
|
|
22099
|
-
if (!id) return;
|
|
22800
|
+
const openTurnDetails = useCallback((id) => {
|
|
22100
22801
|
const session = sessionRef.current;
|
|
22101
22802
|
if (!session) return;
|
|
22102
22803
|
const turn = session.turns.find((t) => t.id === id);
|
|
@@ -22127,7 +22828,6 @@ function AppShell() {
|
|
|
22127
22828
|
}));
|
|
22128
22829
|
}, [
|
|
22129
22830
|
modal,
|
|
22130
|
-
selectedTurnId,
|
|
22131
22831
|
turnIds,
|
|
22132
22832
|
transcriptSearchMode,
|
|
22133
22833
|
transcriptSearchQuery,
|
|
@@ -22137,7 +22837,54 @@ function AppShell() {
|
|
|
22137
22837
|
onEditTurn,
|
|
22138
22838
|
keybindings
|
|
22139
22839
|
]);
|
|
22840
|
+
const openSelectedTurn = useCallback(() => {
|
|
22841
|
+
if (selectedTurnId) openTurnDetails(selectedTurnId);
|
|
22842
|
+
}, [selectedTurnId, openTurnDetails]);
|
|
22843
|
+
const onTranscriptSelectTurn = useCallback((id) => {
|
|
22844
|
+
if (!(transcriptSearchMode ? transcriptSearchTurnIds : turnIds).includes(id)) return false;
|
|
22845
|
+
setSelectedTurnId(id);
|
|
22846
|
+
return true;
|
|
22847
|
+
}, [
|
|
22848
|
+
transcriptSearchMode,
|
|
22849
|
+
transcriptSearchTurnIds,
|
|
22850
|
+
turnIds
|
|
22851
|
+
]);
|
|
22852
|
+
const onTranscriptOpenTurn = useCallback((id) => {
|
|
22853
|
+
if (!(transcriptSearchMode ? transcriptSearchTurnIds : turnIds).includes(id)) return false;
|
|
22854
|
+
setSelectedTurnId(id);
|
|
22855
|
+
openTurnDetails(id);
|
|
22856
|
+
return true;
|
|
22857
|
+
}, [
|
|
22858
|
+
transcriptSearchMode,
|
|
22859
|
+
transcriptSearchTurnIds,
|
|
22860
|
+
turnIds,
|
|
22861
|
+
openTurnDetails
|
|
22862
|
+
]);
|
|
22140
22863
|
useKeyboard((key) => {
|
|
22864
|
+
if (showQuitConfirmRef.current) {
|
|
22865
|
+
if (key.name === "escape") {
|
|
22866
|
+
setShowQuitConfirm(false);
|
|
22867
|
+
setQuitConfirmSelected("cancel");
|
|
22868
|
+
return;
|
|
22869
|
+
}
|
|
22870
|
+
if (key.name === "c" && key.ctrl && !key.shift) {
|
|
22871
|
+
renderer.destroy();
|
|
22872
|
+
return;
|
|
22873
|
+
}
|
|
22874
|
+
if (key.name === "return") {
|
|
22875
|
+
if (quitConfirmSelectedRef.current === "quit") renderer.destroy();
|
|
22876
|
+
else {
|
|
22877
|
+
setShowQuitConfirm(false);
|
|
22878
|
+
setQuitConfirmSelected("cancel");
|
|
22879
|
+
}
|
|
22880
|
+
return;
|
|
22881
|
+
}
|
|
22882
|
+
if (key.name === "tab" || key.name === "left" || key.name === "right") {
|
|
22883
|
+
setQuitConfirmSelected((prev) => prev === "cancel" ? "quit" : "cancel");
|
|
22884
|
+
return;
|
|
22885
|
+
}
|
|
22886
|
+
return;
|
|
22887
|
+
}
|
|
22141
22888
|
if (modal.isOpen) return;
|
|
22142
22889
|
if (transcriptSearchMode && screen === "chat") {
|
|
22143
22890
|
if (key.name === "escape") onTranscriptSearchModeChange(false);
|
|
@@ -22349,7 +23096,7 @@ function AppShell() {
|
|
|
22349
23096
|
}));
|
|
22350
23097
|
return;
|
|
22351
23098
|
}
|
|
22352
|
-
if (key.ctrl && !key.shift && !key.meta && (key.name === "c" || key.name === "x")
|
|
23099
|
+
if (key.ctrl && !key.shift && !key.meta && (key.name === "c" || key.name === "x")) {
|
|
22353
23100
|
const editor = renderer.currentFocusedEditor;
|
|
22354
23101
|
if (editor?.hasSelection()) {
|
|
22355
23102
|
const text = editor.getSelectedText();
|
|
@@ -22358,30 +23105,6 @@ function AppShell() {
|
|
|
22358
23105
|
return;
|
|
22359
23106
|
}
|
|
22360
23107
|
}
|
|
22361
|
-
if (showQuitConfirmRef.current) {
|
|
22362
|
-
if (key.name === "escape") {
|
|
22363
|
-
setShowQuitConfirm(false);
|
|
22364
|
-
setQuitConfirmSelected("cancel");
|
|
22365
|
-
return;
|
|
22366
|
-
}
|
|
22367
|
-
if (key.name === "c" && key.ctrl && !key.shift) {
|
|
22368
|
-
renderer.destroy();
|
|
22369
|
-
return;
|
|
22370
|
-
}
|
|
22371
|
-
if (key.name === "return") {
|
|
22372
|
-
if (quitConfirmSelectedRef.current === "quit") renderer.destroy();
|
|
22373
|
-
else {
|
|
22374
|
-
setShowQuitConfirm(false);
|
|
22375
|
-
setQuitConfirmSelected("cancel");
|
|
22376
|
-
}
|
|
22377
|
-
return;
|
|
22378
|
-
}
|
|
22379
|
-
if (key.name === "tab" || key.name === "left" || key.name === "right") {
|
|
22380
|
-
setQuitConfirmSelected((prev) => prev === "cancel" ? "quit" : "cancel");
|
|
22381
|
-
return;
|
|
22382
|
-
}
|
|
22383
|
-
return;
|
|
22384
|
-
}
|
|
22385
23108
|
if (key.name === "c" && key.ctrl && !key.shift) {
|
|
22386
23109
|
const mode = settingsRef.current.ctrlCBehavior;
|
|
22387
23110
|
if (mode === "quit") {
|
|
@@ -22635,6 +23358,8 @@ function AppShell() {
|
|
|
22635
23358
|
enterSelectsCompletion: (providerId) => providerId === "chats",
|
|
22636
23359
|
onPopupOpenChange,
|
|
22637
23360
|
selectedTurnId,
|
|
23361
|
+
onSelectTurn: onTranscriptSelectTurn,
|
|
23362
|
+
onOpenTurn: onTranscriptOpenTurn,
|
|
22638
23363
|
transcriptSearchMode,
|
|
22639
23364
|
transcriptSearchQuery,
|
|
22640
23365
|
transcriptSearchEvents,
|
|
@@ -22655,17 +23380,19 @@ function AppShell() {
|
|
|
22655
23380
|
hints,
|
|
22656
23381
|
context: contextUsage,
|
|
22657
23382
|
cost: footerCost,
|
|
22658
|
-
status: transcriptSearchMode && transcriptSearchSearching ? "searching" : pendingInteraction?.kind === "question" ? "asking" : compacting ? "compacting" : busy ? "busy" : null,
|
|
23383
|
+
status: transcriptSearchMode && transcriptSearchSearching ? "searching" : pendingInteraction?.kind === "question" ? "asking" : compacting ? "compacting" : retryInfo && busy ? "retrying" : busy ? "busy" : null,
|
|
22659
23384
|
compactionTokens,
|
|
22660
|
-
compactionStartedAt
|
|
23385
|
+
compactionStartedAt,
|
|
23386
|
+
retry: retryInfo,
|
|
23387
|
+
contextKey: keybindings.openContextPanel
|
|
22661
23388
|
}),
|
|
22662
23389
|
showQuitConfirm && /* @__PURE__ */ jsxs("box", {
|
|
22663
23390
|
position: "absolute",
|
|
22664
23391
|
top: "50%",
|
|
22665
23392
|
left: "50%",
|
|
22666
23393
|
marginTop: -3,
|
|
22667
|
-
marginLeft: -
|
|
22668
|
-
width:
|
|
23394
|
+
marginLeft: -21,
|
|
23395
|
+
width: 42,
|
|
22669
23396
|
height: 7,
|
|
22670
23397
|
borderStyle: "rounded",
|
|
22671
23398
|
borderColor: COLOR.warn,
|
|
@@ -22674,23 +23401,52 @@ function AppShell() {
|
|
|
22674
23401
|
alignItems: "center",
|
|
22675
23402
|
justifyContent: "center",
|
|
22676
23403
|
gap: 1,
|
|
22677
|
-
children: [
|
|
22678
|
-
|
|
22679
|
-
|
|
22680
|
-
|
|
22681
|
-
|
|
22682
|
-
children: /* @__PURE__ */ jsx$1("
|
|
22683
|
-
|
|
22684
|
-
|
|
22685
|
-
|
|
22686
|
-
|
|
22687
|
-
|
|
22688
|
-
|
|
22689
|
-
|
|
22690
|
-
children:
|
|
22691
|
-
|
|
22692
|
-
|
|
22693
|
-
|
|
23404
|
+
children: [
|
|
23405
|
+
/* @__PURE__ */ jsx$1("text", { children: "Quit zidane?" }),
|
|
23406
|
+
/* @__PURE__ */ jsxs("box", {
|
|
23407
|
+
flexDirection: "row",
|
|
23408
|
+
gap: 2,
|
|
23409
|
+
children: [/* @__PURE__ */ jsx$1("box", {
|
|
23410
|
+
backgroundColor: quitConfirmSelected === "cancel" ? COLOR.accent : void 0,
|
|
23411
|
+
onMouseDown: (event) => {
|
|
23412
|
+
event.stopPropagation();
|
|
23413
|
+
event.preventDefault();
|
|
23414
|
+
if (quitConfirmSelectedRef.current === "cancel") setShowQuitConfirm(false);
|
|
23415
|
+
else setQuitConfirmSelected("cancel");
|
|
23416
|
+
},
|
|
23417
|
+
children: /* @__PURE__ */ jsx$1("text", {
|
|
23418
|
+
fg: quitConfirmSelected === "cancel" ? SURFACE.modal : COLOR.dim,
|
|
23419
|
+
children: " Cancel "
|
|
23420
|
+
})
|
|
23421
|
+
}), /* @__PURE__ */ jsx$1("box", {
|
|
23422
|
+
backgroundColor: quitConfirmSelected === "quit" ? COLOR.warn : void 0,
|
|
23423
|
+
onMouseDown: (event) => {
|
|
23424
|
+
event.stopPropagation();
|
|
23425
|
+
event.preventDefault();
|
|
23426
|
+
if (quitConfirmSelectedRef.current === "quit") renderer.destroy();
|
|
23427
|
+
else setQuitConfirmSelected("quit");
|
|
23428
|
+
},
|
|
23429
|
+
children: /* @__PURE__ */ jsx$1("text", {
|
|
23430
|
+
fg: quitConfirmSelected === "quit" ? SURFACE.modal : COLOR.dim,
|
|
23431
|
+
children: " Quit "
|
|
23432
|
+
})
|
|
23433
|
+
})]
|
|
23434
|
+
}),
|
|
23435
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
23436
|
+
{
|
|
23437
|
+
key: "tab",
|
|
23438
|
+
label: "switch"
|
|
23439
|
+
},
|
|
23440
|
+
{
|
|
23441
|
+
key: "↵",
|
|
23442
|
+
label: "confirm"
|
|
23443
|
+
},
|
|
23444
|
+
{
|
|
23445
|
+
key: "esc",
|
|
23446
|
+
label: "cancel"
|
|
23447
|
+
}
|
|
23448
|
+
] })
|
|
23449
|
+
]
|
|
22694
23450
|
})
|
|
22695
23451
|
]
|
|
22696
23452
|
});
|
|
@@ -23107,30 +23863,27 @@ function EffortPickerModal({ current, supportsAdaptive, onPick }) {
|
|
|
23107
23863
|
highlightBg: SURFACE.selection
|
|
23108
23864
|
}, level.id))
|
|
23109
23865
|
}),
|
|
23110
|
-
/* @__PURE__ */
|
|
23111
|
-
|
|
23112
|
-
|
|
23113
|
-
|
|
23114
|
-
|
|
23115
|
-
|
|
23116
|
-
|
|
23117
|
-
|
|
23118
|
-
|
|
23119
|
-
|
|
23120
|
-
|
|
23121
|
-
|
|
23122
|
-
|
|
23123
|
-
|
|
23124
|
-
|
|
23125
|
-
|
|
23126
|
-
|
|
23127
|
-
|
|
23128
|
-
|
|
23129
|
-
|
|
23130
|
-
|
|
23131
|
-
})
|
|
23132
|
-
]
|
|
23133
|
-
})
|
|
23866
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
23867
|
+
{
|
|
23868
|
+
key: "↑↓",
|
|
23869
|
+
label: "navigate",
|
|
23870
|
+
labelColor: COLOR.dim
|
|
23871
|
+
},
|
|
23872
|
+
{
|
|
23873
|
+
key: "↵",
|
|
23874
|
+
label: "select",
|
|
23875
|
+
labelColor: COLOR.dim
|
|
23876
|
+
},
|
|
23877
|
+
{
|
|
23878
|
+
key: "esc",
|
|
23879
|
+
label: "close",
|
|
23880
|
+
labelColor: COLOR.dim
|
|
23881
|
+
},
|
|
23882
|
+
{
|
|
23883
|
+
key: "",
|
|
23884
|
+
label: `${filtered.length} / ${levels.length} level${levels.length === 1 ? "" : "s"}`
|
|
23885
|
+
}
|
|
23886
|
+
] })
|
|
23134
23887
|
]
|
|
23135
23888
|
});
|
|
23136
23889
|
}
|
|
@@ -23221,20 +23974,13 @@ function ToggleListModal({ catalog, keyOf, settingKey, gcKeys, title, renderDeta
|
|
|
23221
23974
|
children: [
|
|
23222
23975
|
preamble,
|
|
23223
23976
|
emptyState,
|
|
23224
|
-
/* @__PURE__ */
|
|
23225
|
-
|
|
23226
|
-
|
|
23227
|
-
|
|
23228
|
-
|
|
23229
|
-
|
|
23230
|
-
|
|
23231
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
23232
|
-
fg: COLOR.warn,
|
|
23233
|
-
children: "esc"
|
|
23234
|
-
}),
|
|
23235
|
-
" close"
|
|
23236
|
-
]
|
|
23237
|
-
})
|
|
23977
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [onRefresh && {
|
|
23978
|
+
key: "ctrl+r",
|
|
23979
|
+
label: "refresh"
|
|
23980
|
+
}, {
|
|
23981
|
+
key: "esc",
|
|
23982
|
+
label: "close"
|
|
23983
|
+
}] })
|
|
23238
23984
|
]
|
|
23239
23985
|
});
|
|
23240
23986
|
return /* @__PURE__ */ jsxs(Modal, {
|
|
@@ -23270,30 +24016,24 @@ function ToggleListModal({ catalog, keyOf, settingKey, gcKeys, title, renderDeta
|
|
|
23270
24016
|
}, name);
|
|
23271
24017
|
})
|
|
23272
24018
|
}),
|
|
23273
|
-
/* @__PURE__ */
|
|
23274
|
-
|
|
23275
|
-
|
|
23276
|
-
|
|
23277
|
-
|
|
23278
|
-
|
|
23279
|
-
|
|
23280
|
-
|
|
23281
|
-
|
|
23282
|
-
|
|
23283
|
-
|
|
23284
|
-
|
|
23285
|
-
|
|
23286
|
-
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23290
|
-
|
|
23291
|
-
fg: COLOR.warn,
|
|
23292
|
-
children: "esc"
|
|
23293
|
-
}),
|
|
23294
|
-
" close"
|
|
23295
|
-
]
|
|
23296
|
-
})
|
|
24019
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
24020
|
+
{
|
|
24021
|
+
key: "↑↓",
|
|
24022
|
+
label: "navigate"
|
|
24023
|
+
},
|
|
24024
|
+
{
|
|
24025
|
+
key: "↵",
|
|
24026
|
+
label: "toggle"
|
|
24027
|
+
},
|
|
24028
|
+
onRefresh && {
|
|
24029
|
+
key: "ctrl+r",
|
|
24030
|
+
label: "refresh"
|
|
24031
|
+
},
|
|
24032
|
+
{
|
|
24033
|
+
key: "esc",
|
|
24034
|
+
label: "close"
|
|
24035
|
+
}
|
|
24036
|
+
] })
|
|
23297
24037
|
]
|
|
23298
24038
|
});
|
|
23299
24039
|
}
|
|
@@ -23603,20 +24343,13 @@ function McpsSettingsModal({ catalog, errors, toolsByServer, onLogin, onLogout,
|
|
|
23603
24343
|
children: " { \"mcpServers\": { ... } } "
|
|
23604
24344
|
}), "wrapper from Claude Code / Cursor also works."]
|
|
23605
24345
|
}),
|
|
23606
|
-
/* @__PURE__ */
|
|
23607
|
-
|
|
23608
|
-
|
|
23609
|
-
|
|
23610
|
-
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
23614
|
-
fg: COLOR.warn,
|
|
23615
|
-
children: "esc"
|
|
23616
|
-
}),
|
|
23617
|
-
" close"
|
|
23618
|
-
]
|
|
23619
|
-
})
|
|
24346
|
+
/* @__PURE__ */ jsx$1(ModalHints, { hints: [onRefresh && {
|
|
24347
|
+
key: "r",
|
|
24348
|
+
label: "refresh"
|
|
24349
|
+
}, {
|
|
24350
|
+
key: "esc",
|
|
24351
|
+
label: "close"
|
|
24352
|
+
}] })
|
|
23620
24353
|
]
|
|
23621
24354
|
});
|
|
23622
24355
|
const groups = [];
|
|
@@ -23671,8 +24404,7 @@ function McpsSettingsModal({ catalog, errors, toolsByServer, onLogin, onLogout,
|
|
|
23671
24404
|
focusedEntry,
|
|
23672
24405
|
focusedStatus,
|
|
23673
24406
|
expanded,
|
|
23674
|
-
showRefresh: !!onRefresh
|
|
23675
|
-
COLOR
|
|
24407
|
+
showRefresh: !!onRefresh
|
|
23676
24408
|
})
|
|
23677
24409
|
]
|
|
23678
24410
|
});
|
|
@@ -23903,7 +24635,7 @@ function renderDetailPanel(entry, status, COLOR) {
|
|
|
23903
24635
|
});
|
|
23904
24636
|
return null;
|
|
23905
24637
|
}
|
|
23906
|
-
function renderActionHints({ focusedRow, focusedEntry, focusedStatus, expanded, showRefresh
|
|
24638
|
+
function renderActionHints({ focusedRow, focusedEntry, focusedStatus, expanded, showRefresh }) {
|
|
23907
24639
|
const effectiveStatus = focusedStatus ?? { kind: "idle" };
|
|
23908
24640
|
const onServerRow = focusedRow?.kind === "server";
|
|
23909
24641
|
const canL = onServerRow && focusedEntry ? canLogin(focusedEntry, effectiveStatus) : false;
|
|
@@ -23911,77 +24643,44 @@ function renderActionHints({ focusedRow, focusedEntry, focusedStatus, expanded,
|
|
|
23911
24643
|
const canCancel = effectiveStatus.kind === "authorizing";
|
|
23912
24644
|
const canExpand = onServerRow && focusedEntry ? !expanded.has(focusedEntry.config.name) : false;
|
|
23913
24645
|
const canCollapse = focusedRow?.kind === "tool" || (onServerRow && focusedEntry ? expanded.has(focusedEntry.config.name) : false);
|
|
23914
|
-
return /* @__PURE__ */
|
|
23915
|
-
|
|
23916
|
-
|
|
23917
|
-
|
|
23918
|
-
|
|
23919
|
-
|
|
23920
|
-
|
|
23921
|
-
|
|
23922
|
-
|
|
23923
|
-
|
|
23924
|
-
|
|
23925
|
-
|
|
23926
|
-
|
|
23927
|
-
|
|
23928
|
-
|
|
23929
|
-
|
|
23930
|
-
|
|
23931
|
-
|
|
23932
|
-
|
|
23933
|
-
|
|
23934
|
-
|
|
23935
|
-
|
|
23936
|
-
|
|
23937
|
-
|
|
23938
|
-
|
|
23939
|
-
|
|
23940
|
-
|
|
23941
|
-
|
|
23942
|
-
|
|
23943
|
-
|
|
23944
|
-
|
|
23945
|
-
|
|
23946
|
-
|
|
23947
|
-
|
|
23948
|
-
|
|
23949
|
-
|
|
23950
|
-
|
|
23951
|
-
|
|
23952
|
-
" · ",
|
|
23953
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
23954
|
-
fg: COLOR.warn,
|
|
23955
|
-
children: "o"
|
|
23956
|
-
}),
|
|
23957
|
-
" logout"
|
|
23958
|
-
] }),
|
|
23959
|
-
showRefresh && /* @__PURE__ */ jsxs("span", { children: [
|
|
23960
|
-
" · ",
|
|
23961
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
23962
|
-
fg: COLOR.warn,
|
|
23963
|
-
children: "r"
|
|
23964
|
-
}),
|
|
23965
|
-
" refresh"
|
|
23966
|
-
] }),
|
|
23967
|
-
canCancel && /* @__PURE__ */ jsxs("span", { children: [
|
|
23968
|
-
" · ",
|
|
23969
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
23970
|
-
fg: COLOR.warn,
|
|
23971
|
-
children: "esc"
|
|
23972
|
-
}),
|
|
23973
|
-
" cancel"
|
|
23974
|
-
] }),
|
|
23975
|
-
!canCancel && /* @__PURE__ */ jsxs("span", { children: [
|
|
23976
|
-
" · ",
|
|
23977
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
23978
|
-
fg: COLOR.warn,
|
|
23979
|
-
children: "esc"
|
|
23980
|
-
}),
|
|
23981
|
-
" close"
|
|
23982
|
-
] })
|
|
23983
|
-
]
|
|
23984
|
-
});
|
|
24646
|
+
return /* @__PURE__ */ jsx$1(ModalHints, { hints: [
|
|
24647
|
+
{
|
|
24648
|
+
key: "↑↓",
|
|
24649
|
+
label: "navigate"
|
|
24650
|
+
},
|
|
24651
|
+
{
|
|
24652
|
+
key: "↵",
|
|
24653
|
+
label: "toggle"
|
|
24654
|
+
},
|
|
24655
|
+
canExpand && {
|
|
24656
|
+
key: "→",
|
|
24657
|
+
label: "expand"
|
|
24658
|
+
},
|
|
24659
|
+
canCollapse && {
|
|
24660
|
+
key: "←",
|
|
24661
|
+
label: "collapse"
|
|
24662
|
+
},
|
|
24663
|
+
canL && {
|
|
24664
|
+
key: "l",
|
|
24665
|
+
label: "login"
|
|
24666
|
+
},
|
|
24667
|
+
canO && {
|
|
24668
|
+
key: "o",
|
|
24669
|
+
label: "logout"
|
|
24670
|
+
},
|
|
24671
|
+
showRefresh && {
|
|
24672
|
+
key: "r",
|
|
24673
|
+
label: "refresh"
|
|
24674
|
+
},
|
|
24675
|
+
canCancel && {
|
|
24676
|
+
key: "esc",
|
|
24677
|
+
label: "cancel"
|
|
24678
|
+
},
|
|
24679
|
+
!canCancel && {
|
|
24680
|
+
key: "esc",
|
|
24681
|
+
label: "close"
|
|
24682
|
+
}
|
|
24683
|
+
] });
|
|
23985
24684
|
}
|
|
23986
24685
|
function renderErrors(errors, home, warnColor) {
|
|
23987
24686
|
if (!errors || errors.length === 0) return null;
|
|
@@ -24206,6 +24905,7 @@ async function runTui(options = {}) {
|
|
|
24206
24905
|
debounceDelay: 0,
|
|
24207
24906
|
targetFps: bootFps,
|
|
24208
24907
|
maxFps: bootFps,
|
|
24908
|
+
useMouse: config.initialSettings.mouseInteractions ?? DEFAULT_SETTINGS.mouseInteractions,
|
|
24209
24909
|
gatherStats
|
|
24210
24910
|
});
|
|
24211
24911
|
bootTick("runTui:after-createCliRenderer");
|