zidane 6.2.22 → 6.2.24
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-Cwp_Y78H.js → acp-CTn1kFvP.js} +4 -4
- package/dist/{acp-Cwp_Y78H.js.map → acp-CTn1kFvP.js.map} +1 -1
- package/dist/acp-cli.js +2 -2
- package/dist/acp.d.ts +1 -1
- package/dist/acp.js +1 -1
- package/dist/{agent-IPshmLIF.js → agent-tLfGSSQw.js} +153 -21
- package/dist/agent-tLfGSSQw.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +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 +4 -4
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +2 -2
- package/dist/{index-BDtxt4FY.d.ts → index-8zm_hwdY.d.ts} +87 -3
- package/dist/index-8zm_hwdY.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/{login-BkZ_d5sT.js → login-DfJGuHUj.js} +2 -2
- package/dist/{login-BkZ_d5sT.js.map → login-DfJGuHUj.js.map} +1 -1
- 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/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/session/sqlite.d.ts +1 -1
- package/dist/{session-DzrXKLw-.js → session-jLsc_kMH.js} +23 -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-CMrkqO4q.d.ts → tool-formatters-CZJYzP4x.d.ts} +2 -2
- package/dist/{tool-formatters-CMrkqO4q.d.ts.map → tool-formatters-CZJYzP4x.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-Bvb8iMiY.d.ts → transcript-anchors-CJ2dmpQk.d.ts} +12 -4
- package/dist/{transcript-anchors-Bvb8iMiY.d.ts.map → transcript-anchors-CJ2dmpQk.d.ts.map} +1 -1
- package/dist/{transcript-anchors-DvLIRYLz.js → transcript-anchors-Ded7iJjG.js} +56 -8
- package/dist/transcript-anchors-Ded7iJjG.js.map +1 -0
- package/dist/tui.d.ts +15 -5
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +757 -325
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-CokV32wf.js → turn-operations-ClGa1vnb.js} +6 -2
- package/dist/{turn-operations-CokV32wf.js.map → turn-operations-ClGa1vnb.js.map} +1 -1
- package/dist/{turn-operations-BIw6n_H2.d.ts → turn-operations-DZYpXcU1.d.ts} +3 -3
- package/dist/{turn-operations-BIw6n_H2.d.ts.map → turn-operations-DZYpXcU1.d.ts.map} +1 -1
- package/dist/types-BIarq1qE.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
- package/dist/agent-IPshmLIF.js.map +0 -1
- package/dist/index-BDtxt4FY.d.ts.map +0 -1
- package/dist/resolve-x5mlFtLX.js.map +0 -1
- package/dist/session-DzrXKLw-.js.map +0 -1
- package/dist/transcript-anchors-DvLIRYLz.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 { $ as composeExtensionPreset, B as ExtensionInstallError, Bt as ensureKeybindingsFile, Et as createModelSearchTool, H as installExtensionFromSpec, Ht as groupBindings, J as createExtensionHud, K as removeInstalledExtension, P as summaryToTurn, St as tailTruncate, Ut as keybindingsPath, Vt as formatBindingForDisplay, Wt as matchesBinding, X as discoverAndBuildExtensionRegistry, Y as registerExtensionHostModules, Yt as resolveExtensionKeybindings, _ as buildPostCompactAttachments, c as applyCompactSummaryCutoff, dn as sanitizeExtensionConfigActionPatch, en as inlineLoadedExtension, et as disposeExtensionRegistry, f as cleanupPersistedSession, g as resolveTasksDir, h as resolvePersistDir, hn as effectiveContextWindow, ht as isSpawnTool, it as createExtensionHostRuntimeBridge, lt as basic_default, m as resolveMcpWarningsDir, mn as OUTPUT_RESERVE_TOKENS, nn as parseExtensionScanPathEnv, on as coerceExtensionConfigInput, q as updateInstalledExtension, rn as scanExtensionDirectories, rt as partitionExtensionCatalog, t as createAgent, tt as filterExtensionRegistry, un as resolveExtensionConfigValue, wt as looksBinary, x as compactConversation, y as selectFilesFromSession, z as createExtensionPromptBridge, zt as KEYBINDING_KEY_COL_WIDTH } from "./agent-
|
|
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-Ded7iJjG.js";
|
|
2
|
+
import { $ as composeExtensionPreset, B as ExtensionInstallError, Bt as ensureKeybindingsFile, Et as createModelSearchTool, H as installExtensionFromSpec, Ht as groupBindings, J as createExtensionHud, K as removeInstalledExtension, P as summaryToTurn, St as tailTruncate, Ut as keybindingsPath, Vt as formatBindingForDisplay, Wt as matchesBinding, X as discoverAndBuildExtensionRegistry, Y as registerExtensionHostModules, Yt as resolveExtensionKeybindings, _ as buildPostCompactAttachments, c as applyCompactSummaryCutoff, dn as sanitizeExtensionConfigActionPatch, en as inlineLoadedExtension, et as disposeExtensionRegistry, f as cleanupPersistedSession, g as resolveTasksDir, h as resolvePersistDir, hn as effectiveContextWindow, ht as isSpawnTool, it as createExtensionHostRuntimeBridge, lt as basic_default, m as resolveMcpWarningsDir, mn as OUTPUT_RESERVE_TOKENS, nn as parseExtensionScanPathEnv, on as coerceExtensionConfigInput, q as updateInstalledExtension, rn as scanExtensionDirectories, rt as partitionExtensionCatalog, t as createAgent, tt as filterExtensionRegistry, un as resolveExtensionConfigValue, wt as looksBinary, x as compactConversation, y as selectFilesFromSession, z as createExtensionPromptBridge, zt as KEYBINDING_KEY_COL_WIDTH } from "./agent-tLfGSSQw.js";
|
|
3
3
|
import { a as formatDuration, c as previewLine, i as fmtTokens, l as shortId, n as compactPath, o as formatTaskStatus, r as fmtCost, s as formatTaskSummary, t as ageString } from "./format-BF745pLL.js";
|
|
4
4
|
import { n as appendCapped } from "./output-cap-kBUHBlnq.js";
|
|
5
5
|
import { i as killProcessGroup, n as SUPPORTS_PROCESS_GROUPS, r as createProcessContext } from "./contexts-A4ep-iJs.js";
|
|
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
15
|
import { a as generateStructuredData, c as shouldAutoGenerateTitle, f as commandBlockToEvent, g as parseCommandInvocation, h as executeCommand, n as patchInlineGhost, p as commandBlocksToContent, r as resolveInlineSuggestion, s as generateSessionTitle, t as createPathAutocompleteProvider } from "./inline-autocomplete-BAwBcZtD.js";
|
|
16
16
|
import { s as resolveCompletionSubmit } from "./completion-core-BRo86R_L.js";
|
|
17
|
-
import { i as installSkillFromSpec, r as SkillInstallError } from "./skills-
|
|
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-
|
|
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-DfJGuHUj.js";
|
|
19
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-CpdQebUy.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-ClGa1vnb.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";
|
|
@@ -483,7 +483,12 @@ async function importClaudeSessions(store, opts = {}) {
|
|
|
483
483
|
failed: []
|
|
484
484
|
};
|
|
485
485
|
for (const file of listClaudeSessionFiles(opts)) try {
|
|
486
|
-
const
|
|
486
|
+
const fallbackId = basename(file.path, ".jsonl");
|
|
487
|
+
if (await store.load(fallbackId)) {
|
|
488
|
+
result.skipped++;
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
const converted = convertClaudeSession(readFileSync(file.path, "utf8"), { fallbackId });
|
|
487
492
|
if (!converted) {
|
|
488
493
|
result.empty++;
|
|
489
494
|
continue;
|
|
@@ -1676,6 +1681,200 @@ function segmentDiffStatLine(line) {
|
|
|
1676
1681
|
}];
|
|
1677
1682
|
}
|
|
1678
1683
|
//#endregion
|
|
1684
|
+
//#region src/tui/clickable.tsx
|
|
1685
|
+
/** Glyph / word aliases → OpenTUI key names (`parse.keypress` conventions). */
|
|
1686
|
+
const KEY_NAME_ALIASES = {
|
|
1687
|
+
"esc": "escape",
|
|
1688
|
+
"↵": "return",
|
|
1689
|
+
"enter": "return",
|
|
1690
|
+
"tab": "tab",
|
|
1691
|
+
"space": "space",
|
|
1692
|
+
"⌫": "backspace",
|
|
1693
|
+
"backspace": "backspace",
|
|
1694
|
+
"pgup": "pageup",
|
|
1695
|
+
"pgdn": "pagedown",
|
|
1696
|
+
"↑": "up",
|
|
1697
|
+
"↓": "down",
|
|
1698
|
+
"←": "left",
|
|
1699
|
+
"→": "right",
|
|
1700
|
+
"↑↓": "down",
|
|
1701
|
+
"←→": "right",
|
|
1702
|
+
"del": "delete"
|
|
1703
|
+
};
|
|
1704
|
+
/** Decorative pseudo-keys that must never dispatch (chips, markers). */
|
|
1705
|
+
const NON_KEYS = /* @__PURE__ */ new Set([
|
|
1706
|
+
"✦",
|
|
1707
|
+
"·",
|
|
1708
|
+
"…"
|
|
1709
|
+
]);
|
|
1710
|
+
/**
|
|
1711
|
+
* Parse a hint key spec (`ctrl+g`, `shift+↵`, `esc`, `a`, `↑↓`) into a
|
|
1712
|
+
* dispatchable {@link ParsedKey}, or `null` when the spec is decorative
|
|
1713
|
+
* or ambiguous (the hint then renders non-clickable). Modifier segments
|
|
1714
|
+
* are order-insensitive; the final segment is the key itself.
|
|
1715
|
+
*/
|
|
1716
|
+
function parseHintKeySpec(spec) {
|
|
1717
|
+
const trimmed = spec.trim().toLowerCase();
|
|
1718
|
+
if (!trimmed || NON_KEYS.has(trimmed)) return null;
|
|
1719
|
+
const segments = (trimmed.split("/")[0] ?? "").split("+").map((s) => s.trim()).filter(Boolean);
|
|
1720
|
+
if (segments.length === 0) return null;
|
|
1721
|
+
const keyPart = segments[segments.length - 1] ?? "";
|
|
1722
|
+
const modifiers = segments.slice(0, -1);
|
|
1723
|
+
const mods = {
|
|
1724
|
+
ctrl: false,
|
|
1725
|
+
meta: false,
|
|
1726
|
+
shift: false,
|
|
1727
|
+
option: false
|
|
1728
|
+
};
|
|
1729
|
+
for (const mod of modifiers) if (mod === "ctrl" || mod === "control") mods.ctrl = true;
|
|
1730
|
+
else if (mod === "shift") mods.shift = true;
|
|
1731
|
+
else if (mod === "alt" || mod === "option") mods.option = true;
|
|
1732
|
+
else if (mod === "meta" || mod === "cmd" || mod === "super") mods.meta = true;
|
|
1733
|
+
else return null;
|
|
1734
|
+
const name = KEY_NAME_ALIASES[keyPart] ?? (keyPart.length === 1 ? keyPart : null);
|
|
1735
|
+
if (!name) return null;
|
|
1736
|
+
const sequence = keySequence(name, mods);
|
|
1737
|
+
return {
|
|
1738
|
+
name,
|
|
1739
|
+
...mods,
|
|
1740
|
+
sequence,
|
|
1741
|
+
number: /^\d$/.test(name),
|
|
1742
|
+
raw: sequence,
|
|
1743
|
+
eventType: "press",
|
|
1744
|
+
source: "raw"
|
|
1745
|
+
};
|
|
1746
|
+
}
|
|
1747
|
+
/** Byte sequences real terminals send for the named specials we synthesize. */
|
|
1748
|
+
const NAMED_KEY_SEQUENCES = {
|
|
1749
|
+
return: "\r",
|
|
1750
|
+
tab: " ",
|
|
1751
|
+
escape: "\x1B",
|
|
1752
|
+
space: " ",
|
|
1753
|
+
backspace: "",
|
|
1754
|
+
delete: "\x1B[3~",
|
|
1755
|
+
up: "\x1B[A",
|
|
1756
|
+
down: "\x1B[B",
|
|
1757
|
+
right: "\x1B[C",
|
|
1758
|
+
left: "\x1B[D",
|
|
1759
|
+
pageup: "\x1B[5~",
|
|
1760
|
+
pagedown: "\x1B[6~"
|
|
1761
|
+
};
|
|
1762
|
+
/**
|
|
1763
|
+
* The `sequence`/`raw` a REAL keypress would carry — without it the
|
|
1764
|
+
* synthetic event is second-class: focused inputs insert text from
|
|
1765
|
+
* `key.sequence` (so a clicked `@ files` hint must actually type `@`),
|
|
1766
|
+
* and some handlers match on `sequence` rather than `name`. Modifier
|
|
1767
|
+
* chords return `''`: their handlers dispatch on `name` + flags, and
|
|
1768
|
+
* fabricating control bytes would risk double interpretation.
|
|
1769
|
+
*/
|
|
1770
|
+
function keySequence(name, mods) {
|
|
1771
|
+
if (mods.ctrl || mods.meta || mods.option) return "";
|
|
1772
|
+
if (mods.shift) return name === "tab" ? "\x1B[Z" : "";
|
|
1773
|
+
if (name.length === 1) return name;
|
|
1774
|
+
return NAMED_KEY_SEQUENCES[name] ?? "";
|
|
1775
|
+
}
|
|
1776
|
+
/**
|
|
1777
|
+
* Dispatch a hint key spec through the renderer's key pipeline. Returns
|
|
1778
|
+
* `false` for unparseable specs (no-op). Exposed for non-hint surfaces
|
|
1779
|
+
* that want the same click==keypress contract.
|
|
1780
|
+
*/
|
|
1781
|
+
function dispatchHintKey(renderer, spec) {
|
|
1782
|
+
const parsed = parseHintKeySpec(spec);
|
|
1783
|
+
if (!parsed) return false;
|
|
1784
|
+
renderer.keyInput.processParsedKey(parsed);
|
|
1785
|
+
return true;
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* True when a row click landed on the row's `[✓] ` checkbox cell — the
|
|
1789
|
+
* columns `[startCol, startCol + width)` of the FIRST line of the target
|
|
1790
|
+
* renderable. Rows that must stay single `<text>` renderables (the MCP
|
|
1791
|
+
* list documents an OpenTUI layout regression forbidding box wrappers)
|
|
1792
|
+
* can't make the checkbox its own renderable, so zone-splitting works by
|
|
1793
|
+
* coordinate instead: `event.x/y` are absolute, the target renderable
|
|
1794
|
+
* knows its own absolute origin, and the difference is the glyph column.
|
|
1795
|
+
* The `y` check pins line 0 so wrapped continuation lines can't false-
|
|
1796
|
+
* positive into the checkbox range. Degrades to `false` (row semantics)
|
|
1797
|
+
* when the target's geometry is unavailable.
|
|
1798
|
+
*/
|
|
1799
|
+
function inCheckboxZone(event, startCol, width = 4) {
|
|
1800
|
+
const target = event.target;
|
|
1801
|
+
if (!target || typeof target.x !== "number" || typeof target.y !== "number") return false;
|
|
1802
|
+
if (event.y - target.y !== 0) return false;
|
|
1803
|
+
const col = event.x - target.x;
|
|
1804
|
+
return col >= startCol && col < startCol + width;
|
|
1805
|
+
}
|
|
1806
|
+
/** Spans for one hint's text content — shared by hover and rest states. */
|
|
1807
|
+
function hintSpans(hint, COLOR, hovered) {
|
|
1808
|
+
const keyColor = hovered ? COLOR.accent : hint.keyColor ?? COLOR.warn;
|
|
1809
|
+
const labelColor = hovered ? COLOR.accent : hint.labelColor ?? COLOR.dim;
|
|
1810
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1811
|
+
hint.key !== "" && /* @__PURE__ */ jsx$1("span", {
|
|
1812
|
+
fg: keyColor,
|
|
1813
|
+
children: hint.key
|
|
1814
|
+
}),
|
|
1815
|
+
hint.extra && /* @__PURE__ */ jsx$1("span", {
|
|
1816
|
+
fg: hint.extra.keyColor ?? COLOR.mute,
|
|
1817
|
+
children: hint.extra.key
|
|
1818
|
+
}),
|
|
1819
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
1820
|
+
fg: labelColor,
|
|
1821
|
+
children: hint.key === "" ? hint.label : ` ${hint.label}`
|
|
1822
|
+
}),
|
|
1823
|
+
hint.extra && /* @__PURE__ */ jsx$1("span", {
|
|
1824
|
+
fg: hint.extra.labelColor ?? COLOR.dim,
|
|
1825
|
+
children: ` ${hint.extra.label}`
|
|
1826
|
+
})
|
|
1827
|
+
] });
|
|
1828
|
+
}
|
|
1829
|
+
/**
|
|
1830
|
+
* One hint as its own `<text>` renderable — clickable when its key spec
|
|
1831
|
+
* parses, hover-highlighted in the theme accent. Non-parseable hints
|
|
1832
|
+
* render identically but inert, so decorative chips cost nothing.
|
|
1833
|
+
*/
|
|
1834
|
+
function ClickableHint({ hint }) {
|
|
1835
|
+
const COLOR = useColors();
|
|
1836
|
+
const renderer = useRenderer();
|
|
1837
|
+
const [hovered, setHovered] = useState(false);
|
|
1838
|
+
if (!(parseHintKeySpec(hint.key) !== null)) return /* @__PURE__ */ jsx$1("text", {
|
|
1839
|
+
selectable: false,
|
|
1840
|
+
children: hintSpans(hint, COLOR, false)
|
|
1841
|
+
});
|
|
1842
|
+
return /* @__PURE__ */ jsx$1("text", {
|
|
1843
|
+
selectable: false,
|
|
1844
|
+
onMouseDown: (event) => {
|
|
1845
|
+
event.stopPropagation();
|
|
1846
|
+
event.preventDefault();
|
|
1847
|
+
dispatchHintKey(renderer, hint.key);
|
|
1848
|
+
},
|
|
1849
|
+
onMouseOver: () => setHovered(true),
|
|
1850
|
+
onMouseOut: () => setHovered(false),
|
|
1851
|
+
children: hintSpans(hint, COLOR, hovered)
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
/**
|
|
1855
|
+
* A row of clickable hints with ` · ` separators — the renderable-per-hint
|
|
1856
|
+
* replacement for the span-based `renderHintSpans`. Text content is
|
|
1857
|
+
* byte-identical to the span renderer, so existing `hintsLength` width
|
|
1858
|
+
* math keeps holding.
|
|
1859
|
+
*/
|
|
1860
|
+
function HintRow({ hints }) {
|
|
1861
|
+
const COLOR = useColors();
|
|
1862
|
+
return /* @__PURE__ */ jsx$1("box", {
|
|
1863
|
+
style: {
|
|
1864
|
+
flexDirection: "row",
|
|
1865
|
+
flexWrap: "wrap"
|
|
1866
|
+
},
|
|
1867
|
+
children: hints.map((hint, i) => /* @__PURE__ */ jsxs("box", {
|
|
1868
|
+
style: { flexDirection: "row" },
|
|
1869
|
+
children: [i > 0 && /* @__PURE__ */ jsx$1("text", {
|
|
1870
|
+
selectable: false,
|
|
1871
|
+
fg: COLOR.mute,
|
|
1872
|
+
children: " · "
|
|
1873
|
+
}), /* @__PURE__ */ jsx$1(ClickableHint, { hint })]
|
|
1874
|
+
}, `${hint.key}\u0000${hint.label}\u0000${i}`))
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
//#endregion
|
|
1679
1878
|
//#region src/tui/crush-throbber.tsx
|
|
1680
1879
|
/** @jsxImportSource @opentui/react */
|
|
1681
1880
|
const CRUSH_RUNES = "0123456789abcdefABCDEF~!@#$£€%^&*()+=_";
|
|
@@ -2311,7 +2510,7 @@ function onInputSubmit(handler) {
|
|
|
2311
2510
|
* Width tiering is driven by plain-text length estimates — close enough
|
|
2312
2511
|
* since the segments are ASCII-heavy.
|
|
2313
2512
|
*/
|
|
2314
|
-
function Footer({ hints, context, cost = null, status = null, compactionTokens = null, compactionStartedAt = null }) {
|
|
2513
|
+
function Footer({ hints, context, cost = null, status = null, compactionTokens = null, compactionStartedAt = null, retry = null }) {
|
|
2315
2514
|
const { width } = useTerminalDimensions();
|
|
2316
2515
|
const showCost = typeof cost === "number" && cost > 0;
|
|
2317
2516
|
const inner = Math.max(0, width - 2);
|
|
@@ -2325,8 +2524,8 @@ function Footer({ hints, context, cost = null, status = null, compactionTokens =
|
|
|
2325
2524
|
const timer = setInterval(() => setCompactTick((t) => t + 1), 1e3);
|
|
2326
2525
|
return () => clearInterval(timer);
|
|
2327
2526
|
}, [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;
|
|
2527
|
+
const statusLabel = status === "compacting" ? compactingLabel(compactionTokens, compactionStartedAt) : status === "searching" ? " Searching messages…" : status === "retrying" ? retryingLabel(retry) : "";
|
|
2528
|
+
const sW = status === "compacting" || status === "searching" || status === "retrying" ? 2 + statusLabel.length : status === "asking" ? 3 : status ? 2 : 0;
|
|
2330
2529
|
if (hW + sW + (rightW > 0 ? rightW + 1 : 0) <= inner) return /* @__PURE__ */ jsxs("box", {
|
|
2331
2530
|
style: {
|
|
2332
2531
|
flexDirection: "row",
|
|
@@ -2395,17 +2594,25 @@ function RightStatus({ cost, context }) {
|
|
|
2395
2594
|
function FooterStatusIcon({ status, label = "" }) {
|
|
2396
2595
|
const COLOR = useColors();
|
|
2397
2596
|
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 });
|
|
2597
|
+
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
2598
|
return /* @__PURE__ */ jsxs("text", { children: [
|
|
2400
2599
|
/* @__PURE__ */ jsx$1("span", { children: " " }),
|
|
2401
2600
|
glyph,
|
|
2402
2601
|
label && /* @__PURE__ */ jsx$1("span", {
|
|
2403
|
-
fg: COLOR.accent,
|
|
2602
|
+
fg: status === "retrying" ? COLOR.warn : COLOR.accent,
|
|
2404
2603
|
children: label
|
|
2405
2604
|
})
|
|
2406
2605
|
] });
|
|
2407
2606
|
}
|
|
2408
2607
|
/**
|
|
2608
|
+
* Footer label for the retrying state — ` Retrying (n/max)...` where `n`
|
|
2609
|
+
* is the attempt about to be issued. Plain string for the same width-math
|
|
2610
|
+
* reason as {@link compactingLabel}.
|
|
2611
|
+
*/
|
|
2612
|
+
function retryingLabel(retry) {
|
|
2613
|
+
return retry ? ` Retrying (${retry.attempt}/${retry.max})...` : " Retrying...";
|
|
2614
|
+
}
|
|
2615
|
+
/**
|
|
2409
2616
|
* Footer label for the compacting state — ` Compacting...` plus liveness:
|
|
2410
2617
|
* a `~2.1k` output-token estimate once the summary streams, and an elapsed
|
|
2411
2618
|
* suffix while it doesn't (prompt ingestion is minutes of silence on
|
|
@@ -2419,11 +2626,7 @@ function compactingLabel(estTokens, startedAt) {
|
|
|
2419
2626
|
return typeof estTokens === "number" && estTokens > 0 ? `${base} ~${fmtTokens(estTokens)}${elapsed}` : `${base}${elapsed}`;
|
|
2420
2627
|
}
|
|
2421
2628
|
function HintsText({ hints }) {
|
|
2422
|
-
|
|
2423
|
-
return /* @__PURE__ */ jsx$1("text", {
|
|
2424
|
-
fg: COLOR.dim,
|
|
2425
|
-
children: renderHintSpans(hints, COLOR)
|
|
2426
|
-
});
|
|
2629
|
+
return /* @__PURE__ */ jsx$1(HintRow, { hints });
|
|
2427
2630
|
}
|
|
2428
2631
|
/**
|
|
2429
2632
|
* Pure renderer for a list of {@link Hint}s as colored spans —
|
|
@@ -7851,7 +8054,7 @@ const BULK_ACTIONS = [
|
|
|
7851
8054
|
destructive: true
|
|
7852
8055
|
}
|
|
7853
8056
|
];
|
|
7854
|
-
function ActionBar({ actions, selected, customLabel }) {
|
|
8057
|
+
function ActionBar({ actions, selected, customLabel, onActivate, onHover }) {
|
|
7855
8058
|
const COLOR = useColors();
|
|
7856
8059
|
const SURFACE = useSurfaces();
|
|
7857
8060
|
return /* @__PURE__ */ jsx$1("box", {
|
|
@@ -7869,6 +8072,12 @@ function ActionBar({ actions, selected, customLabel }) {
|
|
|
7869
8072
|
marginRight: 2,
|
|
7870
8073
|
flexShrink: 0
|
|
7871
8074
|
},
|
|
8075
|
+
onMouseDown: (event) => {
|
|
8076
|
+
event.stopPropagation();
|
|
8077
|
+
event.preventDefault();
|
|
8078
|
+
onActivate?.(action, i);
|
|
8079
|
+
},
|
|
8080
|
+
onMouseOver: () => onHover?.(i),
|
|
7872
8081
|
children: isSelected ? /* @__PURE__ */ jsx$1("text", {
|
|
7873
8082
|
bg: tint,
|
|
7874
8083
|
fg: SURFACE.background,
|
|
@@ -8030,7 +8239,9 @@ function SingleEditApprovalModal({ request, payload, priorContent, priorError, t
|
|
|
8030
8239
|
})]
|
|
8031
8240
|
}), /* @__PURE__ */ jsx$1(ActionBar, {
|
|
8032
8241
|
actions: BULK_ACTIONS,
|
|
8033
|
-
selected
|
|
8242
|
+
selected,
|
|
8243
|
+
onActivate: (action) => decide(action.decision),
|
|
8244
|
+
onHover: setSelected
|
|
8034
8245
|
})]
|
|
8035
8246
|
}), /* @__PURE__ */ jsxs("text", {
|
|
8036
8247
|
style: {
|
|
@@ -8355,6 +8566,10 @@ function MultiEditApprovalModal({ request, payload, priorContent, priorError, ta
|
|
|
8355
8566
|
customLabel: {
|
|
8356
8567
|
idx: 0,
|
|
8357
8568
|
label: applyLabel
|
|
8569
|
+
},
|
|
8570
|
+
onActivate: (action) => decide(resolveDecision(action.decision)),
|
|
8571
|
+
onHover: (i) => {
|
|
8572
|
+
if (zone === "actions") setActionIdx(i);
|
|
8358
8573
|
}
|
|
8359
8574
|
})
|
|
8360
8575
|
]
|
|
@@ -9341,6 +9556,19 @@ function MultiSelectQuestionInput({ question, initialChoiceIds, onSubmit }) {
|
|
|
9341
9556
|
const isPicked = picked.has(choice.id);
|
|
9342
9557
|
return /* @__PURE__ */ jsxs("text", {
|
|
9343
9558
|
wrapMode: "word",
|
|
9559
|
+
onMouseDown: (event) => {
|
|
9560
|
+
event.stopPropagation();
|
|
9561
|
+
event.preventDefault();
|
|
9562
|
+
setCursor(i);
|
|
9563
|
+
if (!inCheckboxZone(event, 5)) return;
|
|
9564
|
+
setPicked((prev) => {
|
|
9565
|
+
const next = new Set(prev);
|
|
9566
|
+
if (next.has(choice.id)) next.delete(choice.id);
|
|
9567
|
+
else next.add(choice.id);
|
|
9568
|
+
return next;
|
|
9569
|
+
});
|
|
9570
|
+
},
|
|
9571
|
+
onMouseOver: () => setCursor(i),
|
|
9344
9572
|
children: [
|
|
9345
9573
|
/* @__PURE__ */ jsx$1("span", {
|
|
9346
9574
|
fg: COLOR.mute,
|
|
@@ -9364,25 +9592,28 @@ function MultiSelectQuestionInput({ question, initialChoiceIds, onSubmit }) {
|
|
|
9364
9592
|
})
|
|
9365
9593
|
]
|
|
9366
9594
|
}, choice.id);
|
|
9367
|
-
}), /* @__PURE__ */ jsxs("
|
|
9368
|
-
|
|
9369
|
-
children: [
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
9378
|
-
|
|
9379
|
-
|
|
9380
|
-
|
|
9381
|
-
|
|
9382
|
-
|
|
9383
|
-
|
|
9384
|
-
|
|
9385
|
-
|
|
9595
|
+
}), /* @__PURE__ */ jsxs("box", {
|
|
9596
|
+
style: { flexDirection: "row" },
|
|
9597
|
+
children: [/* @__PURE__ */ jsx$1("text", {
|
|
9598
|
+
fg: COLOR.mute,
|
|
9599
|
+
children: " "
|
|
9600
|
+
}), /* @__PURE__ */ jsx$1(HintRow, { hints: [
|
|
9601
|
+
{
|
|
9602
|
+
key: "space",
|
|
9603
|
+
label: "toggle",
|
|
9604
|
+
labelColor: COLOR.mute
|
|
9605
|
+
},
|
|
9606
|
+
{
|
|
9607
|
+
key: "↵",
|
|
9608
|
+
label: "submit",
|
|
9609
|
+
labelColor: COLOR.mute
|
|
9610
|
+
},
|
|
9611
|
+
...required ? [{
|
|
9612
|
+
key: "",
|
|
9613
|
+
label: "required",
|
|
9614
|
+
labelColor: COLOR.warn
|
|
9615
|
+
}] : []
|
|
9616
|
+
] })]
|
|
9386
9617
|
})]
|
|
9387
9618
|
});
|
|
9388
9619
|
}
|
|
@@ -9407,7 +9638,9 @@ function OptionList({ items, initialCursor, onPick }) {
|
|
|
9407
9638
|
if (typeof initialCursor !== "number" || items.length === 0) return 0;
|
|
9408
9639
|
return Math.max(0, Math.min(items.length - 1, initialCursor));
|
|
9409
9640
|
});
|
|
9641
|
+
const [clickArmed, setClickArmed] = useState(false);
|
|
9410
9642
|
const moveCursor = useCallback((delta) => {
|
|
9643
|
+
setClickArmed(true);
|
|
9411
9644
|
setCursor((c) => {
|
|
9412
9645
|
if (items.length === 0) return c;
|
|
9413
9646
|
return ((c + delta) % items.length + items.length) % items.length;
|
|
@@ -9438,6 +9671,16 @@ function OptionList({ items, initialCursor, onPick }) {
|
|
|
9438
9671
|
const isCursor = i === cursor;
|
|
9439
9672
|
return /* @__PURE__ */ jsxs("text", {
|
|
9440
9673
|
wrapMode: "word",
|
|
9674
|
+
onMouseDown: (event) => {
|
|
9675
|
+
event.stopPropagation();
|
|
9676
|
+
event.preventDefault();
|
|
9677
|
+
if (isCursor && clickArmed) {
|
|
9678
|
+
onPick(item.id);
|
|
9679
|
+
return;
|
|
9680
|
+
}
|
|
9681
|
+
setCursor(i);
|
|
9682
|
+
setClickArmed(true);
|
|
9683
|
+
},
|
|
9441
9684
|
children: [
|
|
9442
9685
|
/* @__PURE__ */ jsx$1("span", {
|
|
9443
9686
|
fg: COLOR.mute,
|
|
@@ -9680,6 +9923,7 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
|
|
|
9680
9923
|
const COLOR = useColors();
|
|
9681
9924
|
const inputRef = useRef(null);
|
|
9682
9925
|
const [hint, setHint] = useState(null);
|
|
9926
|
+
const status = hint && hint.tone !== "error" ? hint.text : "complete the login in your browser — waiting for the callback…";
|
|
9683
9927
|
const onSubmit = useCallback(() => {
|
|
9684
9928
|
const value = inputRef.current?.value?.trim() ?? "";
|
|
9685
9929
|
if (!value) return;
|
|
@@ -9709,32 +9953,36 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
|
|
|
9709
9953
|
return /* @__PURE__ */ jsxs("box", {
|
|
9710
9954
|
style: {
|
|
9711
9955
|
flexDirection: "column",
|
|
9712
|
-
|
|
9713
|
-
borderColor: COLOR.border,
|
|
9714
|
-
paddingTop: 1
|
|
9956
|
+
flexShrink: 0
|
|
9715
9957
|
},
|
|
9716
|
-
children: [
|
|
9717
|
-
|
|
9718
|
-
|
|
9719
|
-
|
|
9720
|
-
|
|
9721
|
-
|
|
9722
|
-
|
|
9723
|
-
|
|
9724
|
-
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
|
|
9728
|
-
|
|
9729
|
-
|
|
9730
|
-
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9958
|
+
children: [/* @__PURE__ */ jsxs("box", {
|
|
9959
|
+
style: {
|
|
9960
|
+
flexDirection: "column",
|
|
9961
|
+
border: true,
|
|
9962
|
+
borderColor: COLOR.border,
|
|
9963
|
+
padding: 1,
|
|
9964
|
+
gap: 1
|
|
9965
|
+
},
|
|
9966
|
+
children: [
|
|
9967
|
+
/* @__PURE__ */ jsx$1(Spinner, { label: status }),
|
|
9968
|
+
/* @__PURE__ */ jsx$1(OAuthAuthBlock, {
|
|
9969
|
+
authUrl,
|
|
9970
|
+
maxLineWidth,
|
|
9971
|
+
chromeWidth: (chromeWidth ?? 14) + 4,
|
|
9972
|
+
paste: {
|
|
9973
|
+
inputRef,
|
|
9974
|
+
focused: inputFocused,
|
|
9975
|
+
onSubmit,
|
|
9976
|
+
placeholder: "paste redirect URL and press enter…",
|
|
9977
|
+
hint: hint?.tone === "error" ? hint : void 0
|
|
9978
|
+
}
|
|
9979
|
+
}),
|
|
9980
|
+
/* @__PURE__ */ jsx$1("text", {
|
|
9981
|
+
fg: COLOR.dim,
|
|
9982
|
+
children: "esc cancel — the server stays signed out until you retry"
|
|
9983
|
+
})
|
|
9984
|
+
]
|
|
9985
|
+
}), /* @__PURE__ */ jsx$1(TitleOverlay, { title: `authorizing ${serverName} — OAuth` })]
|
|
9738
9986
|
});
|
|
9739
9987
|
}
|
|
9740
9988
|
//#endregion
|
|
@@ -10796,7 +11044,13 @@ function SessionsScreen({ sessions, currentId, focusedSessionId, onPick, onCreat
|
|
|
10796
11044
|
focused: idx === cursorIndex && focused,
|
|
10797
11045
|
isCurrent: row.kind === "session" && row.rowId === currentId,
|
|
10798
11046
|
showProject: showAllProjects,
|
|
10799
|
-
currentProjectRoot
|
|
11047
|
+
currentProjectRoot,
|
|
11048
|
+
onHover: focused ? () => moveCursor(idx) : void 0,
|
|
11049
|
+
onClick: focused ? () => {
|
|
11050
|
+
moveCursor(idx);
|
|
11051
|
+
if (row.kind === "new") onCreate();
|
|
11052
|
+
else onPick(row.rowId);
|
|
11053
|
+
} : void 0
|
|
10800
11054
|
}, row.rowId)), filteredSessions.length === 0 && query.trim().length > 0 && /* @__PURE__ */ jsxs("text", {
|
|
10801
11055
|
wrapMode: "none",
|
|
10802
11056
|
children: [
|
|
@@ -10838,7 +11092,7 @@ function SessionsScreen({ sessions, currentId, focusedSessionId, onPick, onCreat
|
|
|
10838
11092
|
* exactly the width of the focus + current markers above — so the first
|
|
10839
11093
|
* stat (the turn count) sits flush under the title's first letter.
|
|
10840
11094
|
*/
|
|
10841
|
-
function SessionRow({ row, anchorId, focused, isCurrent, separator = false, showProject = false, currentProjectRoot }) {
|
|
11095
|
+
function SessionRow({ row, anchorId, focused, isCurrent, separator = false, showProject = false, currentProjectRoot, onClick, onHover }) {
|
|
10842
11096
|
const COLOR = useColors();
|
|
10843
11097
|
const SURFACE = useSurfaces();
|
|
10844
11098
|
const STATS_INDENT = " ";
|
|
@@ -10854,9 +11108,18 @@ function SessionRow({ row, anchorId, focused, isCurrent, separator = false, show
|
|
|
10854
11108
|
borderColor: COLOR.border
|
|
10855
11109
|
} : {}
|
|
10856
11110
|
};
|
|
11111
|
+
const mouseProps = {
|
|
11112
|
+
...onClick ? { onMouseDown: (event) => {
|
|
11113
|
+
event.stopPropagation();
|
|
11114
|
+
event.preventDefault();
|
|
11115
|
+
onClick();
|
|
11116
|
+
} } : {},
|
|
11117
|
+
...onHover ? { onMouseOver: () => onHover() } : {}
|
|
11118
|
+
};
|
|
10857
11119
|
if (row.kind === "new") return /* @__PURE__ */ jsxs("box", {
|
|
10858
11120
|
id: anchorId,
|
|
10859
11121
|
style: rowStyle,
|
|
11122
|
+
...mouseProps,
|
|
10860
11123
|
children: [/* @__PURE__ */ jsxs("text", {
|
|
10861
11124
|
wrapMode: "none",
|
|
10862
11125
|
children: [
|
|
@@ -10890,6 +11153,7 @@ function SessionRow({ row, anchorId, focused, isCurrent, separator = false, show
|
|
|
10890
11153
|
return /* @__PURE__ */ jsxs("box", {
|
|
10891
11154
|
id: anchorId,
|
|
10892
11155
|
style: rowStyle,
|
|
11156
|
+
...mouseProps,
|
|
10893
11157
|
children: [
|
|
10894
11158
|
/* @__PURE__ */ jsxs("text", {
|
|
10895
11159
|
wrapMode: "none",
|
|
@@ -12302,7 +12566,6 @@ const PROMPT_HINTS_SELECT_QUEUE = [{
|
|
|
12302
12566
|
* shortcuts that actually do something in the active mode.
|
|
12303
12567
|
*/
|
|
12304
12568
|
function PromptHints({ selectMode, searchMode = false, triggerHints, busy = false }) {
|
|
12305
|
-
const COLOR = useColors();
|
|
12306
12569
|
const { settings } = useSettings();
|
|
12307
12570
|
const { width: termWidth } = useTerminalDimensions();
|
|
12308
12571
|
const minimalResting = !selectMode && !searchMode && !busy && settings.uiMode === "minimal";
|
|
@@ -12319,21 +12582,21 @@ function PromptHints({ selectMode, searchMode = false, triggerHints, busy = fals
|
|
|
12319
12582
|
termWidth
|
|
12320
12583
|
]);
|
|
12321
12584
|
if (hints.length === 0) return null;
|
|
12322
|
-
return /* @__PURE__ */ jsxs("
|
|
12585
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
12323
12586
|
style: {
|
|
12324
12587
|
position: "absolute",
|
|
12325
12588
|
top: 0,
|
|
12326
|
-
right: 1
|
|
12589
|
+
right: 1,
|
|
12590
|
+
flexDirection: "row"
|
|
12327
12591
|
},
|
|
12328
|
-
fg: COLOR.dim,
|
|
12329
12592
|
children: [
|
|
12330
|
-
/* @__PURE__ */ jsx$1("
|
|
12331
|
-
|
|
12593
|
+
/* @__PURE__ */ jsx$1("text", {
|
|
12594
|
+
selectable: false,
|
|
12332
12595
|
children: " "
|
|
12333
12596
|
}),
|
|
12334
|
-
|
|
12335
|
-
/* @__PURE__ */ jsx$1("
|
|
12336
|
-
|
|
12597
|
+
/* @__PURE__ */ jsx$1(HintRow, { hints }),
|
|
12598
|
+
/* @__PURE__ */ jsx$1("text", {
|
|
12599
|
+
selectable: false,
|
|
12337
12600
|
children: " "
|
|
12338
12601
|
})
|
|
12339
12602
|
]
|
|
@@ -14434,8 +14697,8 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14434
14697
|
[activeTab]: 0
|
|
14435
14698
|
}));
|
|
14436
14699
|
}, [activeTab]);
|
|
14437
|
-
const
|
|
14438
|
-
const row = mcpVisibleRows[
|
|
14700
|
+
const expandMcpRowAt = useCallback((index) => {
|
|
14701
|
+
const row = mcpVisibleRows[index];
|
|
14439
14702
|
if (!row || row.kind !== "server") return;
|
|
14440
14703
|
const name = row.entry.config.name;
|
|
14441
14704
|
if ((mcpToolsByServer[name]?.length ?? 0) === 0) fireMcpToolsRefresh();
|
|
@@ -14447,12 +14710,11 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14447
14710
|
});
|
|
14448
14711
|
}, [
|
|
14449
14712
|
mcpVisibleRows,
|
|
14450
|
-
cursor,
|
|
14451
14713
|
mcpToolsByServer,
|
|
14452
14714
|
fireMcpToolsRefresh
|
|
14453
14715
|
]);
|
|
14454
|
-
const
|
|
14455
|
-
const row = mcpVisibleRows[
|
|
14716
|
+
const collapseMcpRowAt = useCallback((index) => {
|
|
14717
|
+
const row = mcpVisibleRows[index];
|
|
14456
14718
|
if (!row) return;
|
|
14457
14719
|
const parentName = parentServerName(row);
|
|
14458
14720
|
if (row.kind !== "server") {
|
|
@@ -14468,7 +14730,18 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14468
14730
|
next.delete(parentName);
|
|
14469
14731
|
return next;
|
|
14470
14732
|
});
|
|
14471
|
-
}, [mcpVisibleRows
|
|
14733
|
+
}, [mcpVisibleRows]);
|
|
14734
|
+
const toggleExpandMcpRowAt = useCallback((index) => {
|
|
14735
|
+
const row = mcpVisibleRows[index];
|
|
14736
|
+
if (!row) return;
|
|
14737
|
+
if (expandedMcps.has(parentServerName(row))) collapseMcpRowAt(index);
|
|
14738
|
+
else expandMcpRowAt(index);
|
|
14739
|
+
}, [
|
|
14740
|
+
mcpVisibleRows,
|
|
14741
|
+
expandedMcps,
|
|
14742
|
+
collapseMcpRowAt,
|
|
14743
|
+
expandMcpRowAt
|
|
14744
|
+
]);
|
|
14472
14745
|
/**
|
|
14473
14746
|
* Single `tab` press toggles between expanded / collapsed based on
|
|
14474
14747
|
* the focused row's current state. The split helpers above remain
|
|
@@ -14476,21 +14749,9 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14476
14749
|
* users expect — expand-only / collapse-only). Toggle is the
|
|
14477
14750
|
* default that the footer hint advertises.
|
|
14478
14751
|
*/
|
|
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];
|
|
14752
|
+
const toggleExpandFocusedMcpRow = useCallback(() => toggleExpandMcpRowAt(cursor), [toggleExpandMcpRowAt, cursor]);
|
|
14753
|
+
const toggleExpandExtensionRowAt = useCallback((index) => {
|
|
14754
|
+
const row = extensionVisibleRows[index];
|
|
14494
14755
|
const parentName = parentExtensionName(row);
|
|
14495
14756
|
if (!parentName) return;
|
|
14496
14757
|
setExpandedExtensions((prev) => {
|
|
@@ -14507,7 +14768,8 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14507
14768
|
} else next.add(parentName);
|
|
14508
14769
|
return next;
|
|
14509
14770
|
});
|
|
14510
|
-
}, [extensionVisibleRows
|
|
14771
|
+
}, [extensionVisibleRows]);
|
|
14772
|
+
const toggleExpandFocusedExtensionRow = useCallback(() => toggleExpandExtensionRowAt(cursor), [toggleExpandExtensionRowAt, cursor]);
|
|
14511
14773
|
const mcpRowCount = mcpVisibleRows.length;
|
|
14512
14774
|
const extensionRowCount = extensionVisibleRows.length;
|
|
14513
14775
|
useEffect(() => {
|
|
@@ -14597,6 +14859,148 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14597
14859
|
useEffect(() => {
|
|
14598
14860
|
if (editingInputKey) editInputRef.current?.focus();
|
|
14599
14861
|
}, [editingInputKey]);
|
|
14862
|
+
/**
|
|
14863
|
+
* Activate the row at `index` on the ACTIVE tab — the ↵ semantics
|
|
14864
|
+
* (toggle / cycle / open editor / run action), extracted so row
|
|
14865
|
+
* CLICKS can activate the clicked row directly. Cursor-based
|
|
14866
|
+
* callers (the keyboard handler) pass `cursor`.
|
|
14867
|
+
*/
|
|
14868
|
+
const activateRowAt = useCallback((index) => {
|
|
14869
|
+
if (isCategoryTab(activeTab)) {
|
|
14870
|
+
const it = filteredByCategory[activeTab][index];
|
|
14871
|
+
if (!it) return;
|
|
14872
|
+
if (it.kind === "toggle") toggleBoolean(it.key);
|
|
14873
|
+
else if (it.kind === "choice") {
|
|
14874
|
+
const current = settings[it.key];
|
|
14875
|
+
const idx = it.options.findIndex((o) => o.value === current);
|
|
14876
|
+
const next = it.options[(idx + 1) % it.options.length];
|
|
14877
|
+
if (next) setSetting(it.key, next.value);
|
|
14878
|
+
} else if (it.kind === "input") setEditingInputKey(it.key);
|
|
14879
|
+
else it.onPick();
|
|
14880
|
+
return;
|
|
14881
|
+
}
|
|
14882
|
+
if (activeTab === "skills") {
|
|
14883
|
+
const s = filteredSkills[index];
|
|
14884
|
+
if (s) skillsToggle.toggle(s.name);
|
|
14885
|
+
return;
|
|
14886
|
+
}
|
|
14887
|
+
if (activeTab === "extensions") {
|
|
14888
|
+
const row = extensionVisibleRows[index];
|
|
14889
|
+
if (!row) return;
|
|
14890
|
+
if (row.kind === "extension") extensionsToggle.toggle(row.ext.name);
|
|
14891
|
+
else if (row.kind === "config") activateConfigRow(row.extName, row.item);
|
|
14892
|
+
return;
|
|
14893
|
+
}
|
|
14894
|
+
if (activeTab === "mcps") {
|
|
14895
|
+
const row = mcpVisibleRows[index];
|
|
14896
|
+
if (!row) return;
|
|
14897
|
+
if (row.kind === "server") {
|
|
14898
|
+
const name = row.entry.config.name;
|
|
14899
|
+
const enabling = !mcpsToggle.enabledSet.has(name);
|
|
14900
|
+
mcpsToggle.toggle(name);
|
|
14901
|
+
if (enabling && (mcpToolsByServer[name]?.length ?? 0) === 0) fireMcpToolsRefresh();
|
|
14902
|
+
} else if (row.kind === "tool") mcpToolToggleMap[row.serverName]?.toggle(row.tool.name);
|
|
14903
|
+
return;
|
|
14904
|
+
}
|
|
14905
|
+
if (activeTab === "keybindings") {
|
|
14906
|
+
actions?.onOpenKeybindings?.();
|
|
14907
|
+
return;
|
|
14908
|
+
}
|
|
14909
|
+
if (activeTab === "authentication") {
|
|
14910
|
+
const provider = filteredProviders[index];
|
|
14911
|
+
if (provider) actions?.onConfigureProvider?.(provider);
|
|
14912
|
+
}
|
|
14913
|
+
}, [
|
|
14914
|
+
activeTab,
|
|
14915
|
+
filteredByCategory,
|
|
14916
|
+
settings,
|
|
14917
|
+
setSetting,
|
|
14918
|
+
toggleBoolean,
|
|
14919
|
+
filteredSkills,
|
|
14920
|
+
skillsToggle,
|
|
14921
|
+
extensionVisibleRows,
|
|
14922
|
+
extensionsToggle,
|
|
14923
|
+
activateConfigRow,
|
|
14924
|
+
mcpVisibleRows,
|
|
14925
|
+
mcpsToggle,
|
|
14926
|
+
mcpToolsByServer,
|
|
14927
|
+
fireMcpToolsRefresh,
|
|
14928
|
+
mcpToolToggleMap,
|
|
14929
|
+
actions,
|
|
14930
|
+
filteredProviders
|
|
14931
|
+
]);
|
|
14932
|
+
/**
|
|
14933
|
+
* True while an inline editor or overlay dialog owns the modal's input
|
|
14934
|
+
* — the same states the keyboard handler early-returns on. Mouse paths
|
|
14935
|
+
* (`clickRowAt`, tab-strip clicks) must honor it too: a click on a row
|
|
14936
|
+
* or tab underneath an open dialog would otherwise toggle settings or
|
|
14937
|
+
* switch tabs behind the user's back. Also drives the lists' `focused`
|
|
14938
|
+
* prop, so "list looks focused" and "list accepts input" cannot drift.
|
|
14939
|
+
*/
|
|
14940
|
+
const modalInputCaptured = oauthPasteActive || configEditActive || editingInputKey !== null || extInstallActive || skillInstallActive || skillImportAllActive || mcpAddActive;
|
|
14941
|
+
/**
|
|
14942
|
+
* Row CLICK dispatch: focus the clicked row, then act on it. Expandable
|
|
14943
|
+
* headers (MCP servers, extensions with config) expand/collapse — the
|
|
14944
|
+
* disclosure is the row's primary affordance; everything else gets the
|
|
14945
|
+
* ↵ semantics (toggle / cycle / edit / action). Rows stay single
|
|
14946
|
+
* renderables (the MCP list documents an OpenTUI layout regression that
|
|
14947
|
+
* forbids box wrappers there), so the whole row is one click target —
|
|
14948
|
+
* the enable checkbox on expandable headers remains ↵.
|
|
14949
|
+
*/
|
|
14950
|
+
/**
|
|
14951
|
+
* Row CLICK dispatch, by ZONE:
|
|
14952
|
+
*
|
|
14953
|
+
* - `checkbox` — the click landed on the row's `[✓] ` cell (rows
|
|
14954
|
+
* compute this by glyph column — see `inCheckboxZone`): flip the
|
|
14955
|
+
* toggle (↵ semantics). The checkbox is a SOLO target, including
|
|
14956
|
+
* the enable checkbox on MCP server / extension header rows.
|
|
14957
|
+
* - `row` — anywhere else: expandable headers expand/collapse;
|
|
14958
|
+
* checkbox-bearing rows only FOCUS (a body click must never flip
|
|
14959
|
+
* state the user didn't aim at); rows whose whole body is one
|
|
14960
|
+
* action (choices, inputs, actions, auth) activate.
|
|
14961
|
+
*/
|
|
14962
|
+
const clickRowAt = useCallback((index, zone = "row") => {
|
|
14963
|
+
if (modalInputCaptured) return;
|
|
14964
|
+
setCursorByTab((prev) => ({
|
|
14965
|
+
...prev,
|
|
14966
|
+
[activeTab]: index
|
|
14967
|
+
}));
|
|
14968
|
+
if (zone === "checkbox") {
|
|
14969
|
+
activateRowAt(index);
|
|
14970
|
+
return;
|
|
14971
|
+
}
|
|
14972
|
+
if (activeTab === "mcps") {
|
|
14973
|
+
if (mcpVisibleRows[index]?.kind === "server") toggleExpandMcpRowAt(index);
|
|
14974
|
+
return;
|
|
14975
|
+
}
|
|
14976
|
+
if (activeTab === "extensions") {
|
|
14977
|
+
const row = extensionVisibleRows[index];
|
|
14978
|
+
if (row?.kind === "extension") {
|
|
14979
|
+
if (row.hasConfig) toggleExpandExtensionRowAt(index);
|
|
14980
|
+
return;
|
|
14981
|
+
}
|
|
14982
|
+
if (row?.kind === "config" && row.item.type === "boolean") return;
|
|
14983
|
+
activateRowAt(index);
|
|
14984
|
+
return;
|
|
14985
|
+
}
|
|
14986
|
+
if (activeTab === "skills") return;
|
|
14987
|
+
if (isCategoryTab(activeTab) && filteredByCategory[activeTab][index]?.kind === "toggle") return;
|
|
14988
|
+
activateRowAt(index);
|
|
14989
|
+
}, [
|
|
14990
|
+
activeTab,
|
|
14991
|
+
modalInputCaptured,
|
|
14992
|
+
mcpVisibleRows,
|
|
14993
|
+
extensionVisibleRows,
|
|
14994
|
+
filteredByCategory,
|
|
14995
|
+
toggleExpandMcpRowAt,
|
|
14996
|
+
toggleExpandExtensionRowAt,
|
|
14997
|
+
activateRowAt
|
|
14998
|
+
]);
|
|
14999
|
+
/** Tab-strip clicks — same input-capture guard as row clicks. */
|
|
15000
|
+
const clickTab = useCallback((id) => {
|
|
15001
|
+
if (modalInputCaptured) return;
|
|
15002
|
+
setActiveTab(id);
|
|
15003
|
+
}, [modalInputCaptured]);
|
|
14600
15004
|
useKeyboard((key) => {
|
|
14601
15005
|
if (configEditActive) {
|
|
14602
15006
|
if (key.name === "escape" && configEdit?.kind !== "model") setConfigEdit(null);
|
|
@@ -14659,51 +15063,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14659
15063
|
return;
|
|
14660
15064
|
}
|
|
14661
15065
|
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
|
-
}
|
|
15066
|
+
activateRowAt(cursor);
|
|
14707
15067
|
return;
|
|
14708
15068
|
}
|
|
14709
15069
|
if (activeTab === "extensions") {
|
|
@@ -14908,7 +15268,8 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14908
15268
|
children: /* @__PURE__ */ jsx$1(TabStrip, {
|
|
14909
15269
|
order: tabOrder,
|
|
14910
15270
|
active: activeTab,
|
|
14911
|
-
counts: tabCounts
|
|
15271
|
+
counts: tabCounts,
|
|
15272
|
+
onSelect: clickTab
|
|
14912
15273
|
})
|
|
14913
15274
|
}),
|
|
14914
15275
|
/* @__PURE__ */ jsx$1("box", {
|
|
@@ -14922,7 +15283,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14922
15283
|
},
|
|
14923
15284
|
children: /* @__PURE__ */ jsx$1("input", {
|
|
14924
15285
|
ref: inputRef,
|
|
14925
|
-
focused: !
|
|
15286
|
+
focused: !modalInputCaptured,
|
|
14926
15287
|
placeholder: searchPlaceholder(activeTab),
|
|
14927
15288
|
onInput: handleQueryChange,
|
|
14928
15289
|
onSubmit: () => {},
|
|
@@ -14941,6 +15302,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14941
15302
|
viewportCulling: false,
|
|
14942
15303
|
children: [
|
|
14943
15304
|
isCategoryTab(activeTab) && /* @__PURE__ */ jsx$1(GeneralList, {
|
|
15305
|
+
onRowClick: clickRowAt,
|
|
14944
15306
|
items: filteredByCategory[activeTab],
|
|
14945
15307
|
cursor,
|
|
14946
15308
|
highlightBg: SURFACE.selection,
|
|
@@ -14949,6 +15311,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14949
15311
|
editingKey: editingInputKey
|
|
14950
15312
|
}),
|
|
14951
15313
|
activeTab === "skills" && /* @__PURE__ */ jsx$1(SkillsList, {
|
|
15314
|
+
onRowClick: clickRowAt,
|
|
14952
15315
|
items: filteredSkills,
|
|
14953
15316
|
enabledSet: skillsToggle.enabledSet,
|
|
14954
15317
|
totalCount: skillsCatalog.length,
|
|
@@ -14958,6 +15321,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14958
15321
|
contentCols
|
|
14959
15322
|
}),
|
|
14960
15323
|
activeTab === "extensions" && /* @__PURE__ */ jsx$1(ExtensionsList, {
|
|
15324
|
+
onRowClick: clickRowAt,
|
|
14961
15325
|
rows: extensionVisibleRows,
|
|
14962
15326
|
enabledSet: extensionsToggle.enabledSet,
|
|
14963
15327
|
extensionConfig: settings.extensionConfig,
|
|
@@ -14977,6 +15341,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
14977
15341
|
actionProbes
|
|
14978
15342
|
}),
|
|
14979
15343
|
activeTab === "mcps" && /* @__PURE__ */ jsx$1(McpsList, {
|
|
15344
|
+
onRowClick: clickRowAt,
|
|
14980
15345
|
rows: mcpVisibleRows,
|
|
14981
15346
|
filteredCount: filteredMcps.length,
|
|
14982
15347
|
enabledSet: mcpsToggle.enabledSet,
|
|
@@ -15183,9 +15548,10 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
15183
15548
|
]
|
|
15184
15549
|
});
|
|
15185
15550
|
}
|
|
15186
|
-
function TabStrip({ order, active, counts }) {
|
|
15551
|
+
function TabStrip({ order, active, counts, onSelect }) {
|
|
15187
15552
|
const COLOR = useColors();
|
|
15188
15553
|
const SURFACE = useSurfaces();
|
|
15554
|
+
const [hoveredTab, setHoveredTab] = useState(null);
|
|
15189
15555
|
return /* @__PURE__ */ jsx$1("box", {
|
|
15190
15556
|
style: {
|
|
15191
15557
|
flexDirection: "row",
|
|
@@ -15193,11 +15559,19 @@ function TabStrip({ order, active, counts }) {
|
|
|
15193
15559
|
},
|
|
15194
15560
|
children: order.map((id, i) => {
|
|
15195
15561
|
const isActive = id === active;
|
|
15562
|
+
const hovered = hoveredTab === id && !isActive;
|
|
15196
15563
|
const label = TAB_LABELS[id];
|
|
15197
15564
|
const tabCounts = counts[id];
|
|
15198
15565
|
const showBadge = !!tabCounts;
|
|
15199
15566
|
const badge = tabCounts ? tabCounts.current !== tabCounts.total ? `${tabCounts.current}/${tabCounts.total}` : `${tabCounts.total}` : "";
|
|
15200
15567
|
return /* @__PURE__ */ jsx$1("box", {
|
|
15568
|
+
onMouseDown: (event) => {
|
|
15569
|
+
event.stopPropagation();
|
|
15570
|
+
event.preventDefault();
|
|
15571
|
+
onSelect(id);
|
|
15572
|
+
},
|
|
15573
|
+
onMouseOver: () => setHoveredTab(id),
|
|
15574
|
+
onMouseOut: () => setHoveredTab((current) => current === id ? null : current),
|
|
15201
15575
|
style: {
|
|
15202
15576
|
paddingLeft: 1,
|
|
15203
15577
|
paddingRight: 1,
|
|
@@ -15207,10 +15581,10 @@ function TabStrip({ order, active, counts }) {
|
|
|
15207
15581
|
children: /* @__PURE__ */ jsxs("text", {
|
|
15208
15582
|
wrapMode: "none",
|
|
15209
15583
|
children: [/* @__PURE__ */ jsx$1("span", {
|
|
15210
|
-
fg: isActive ? COLOR.brand : COLOR.dim,
|
|
15584
|
+
fg: isActive ? COLOR.brand : hovered ? COLOR.accent : COLOR.dim,
|
|
15211
15585
|
children: label
|
|
15212
15586
|
}), showBadge && /* @__PURE__ */ jsx$1("span", {
|
|
15213
|
-
fg: isActive ? COLOR.brand : COLOR.mute,
|
|
15587
|
+
fg: isActive ? COLOR.brand : hovered ? COLOR.accent : COLOR.mute,
|
|
15214
15588
|
children: ` ${badge}`
|
|
15215
15589
|
})]
|
|
15216
15590
|
})
|
|
@@ -15218,7 +15592,7 @@ function TabStrip({ order, active, counts }) {
|
|
|
15218
15592
|
})
|
|
15219
15593
|
});
|
|
15220
15594
|
}
|
|
15221
|
-
function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKey }) {
|
|
15595
|
+
function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKey, onRowClick }) {
|
|
15222
15596
|
const { settings } = useSettings();
|
|
15223
15597
|
if (items.length === 0) return /* @__PURE__ */ jsx$1(EmptyRow, { label: query ? `no settings match "${query}"` : "no settings" });
|
|
15224
15598
|
const descCols = Math.max(0, contentCols - 1 - 1 - 6);
|
|
@@ -15229,6 +15603,7 @@ function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKe
|
|
|
15229
15603
|
const bg = focused ? highlightBg : void 0;
|
|
15230
15604
|
const id = anchorIdFor(i);
|
|
15231
15605
|
if (item.kind === "toggle") return /* @__PURE__ */ jsx$1(ToggleRow, {
|
|
15606
|
+
onClick: (zone) => onRowClick?.(i, zone),
|
|
15232
15607
|
id,
|
|
15233
15608
|
label: item.label,
|
|
15234
15609
|
description: truncateToCols(item.description, descCols),
|
|
@@ -15240,6 +15615,7 @@ function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKe
|
|
|
15240
15615
|
const current = settings[item.key];
|
|
15241
15616
|
const opt = item.options.find((o) => o.value === current);
|
|
15242
15617
|
return /* @__PURE__ */ jsx$1(ChoiceRow, {
|
|
15618
|
+
onClick: () => onRowClick?.(i),
|
|
15243
15619
|
id,
|
|
15244
15620
|
label: item.label,
|
|
15245
15621
|
description: truncateToCols(item.description, descCols),
|
|
@@ -15250,6 +15626,7 @@ function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKe
|
|
|
15250
15626
|
}, item.key);
|
|
15251
15627
|
}
|
|
15252
15628
|
if (item.kind === "input") return /* @__PURE__ */ jsx$1(InputRow, {
|
|
15629
|
+
onClick: () => onRowClick?.(i),
|
|
15253
15630
|
id,
|
|
15254
15631
|
label: item.label,
|
|
15255
15632
|
description: truncateToCols(item.description, descCols),
|
|
@@ -15270,7 +15647,7 @@ function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKe
|
|
|
15270
15647
|
});
|
|
15271
15648
|
}
|
|
15272
15649
|
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 }) {
|
|
15650
|
+
function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCount, cursor, highlightBg, query, contentCols, editing, inputRef, onCommitEdit, modelCatalog, onApplyModelEdit, onCancelEdit, actionStatus, actionProbes, onRowClick }) {
|
|
15274
15651
|
const COLOR = useColors();
|
|
15275
15652
|
const home = homedir();
|
|
15276
15653
|
if (totalCount === 0) return /* @__PURE__ */ jsxs("box", {
|
|
@@ -15420,6 +15797,7 @@ function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCo
|
|
|
15420
15797
|
if (item.type === "action") {
|
|
15421
15798
|
const status = actionStatus && actionStatus.extName === group.ext.name && actionStatus.key === item.key ? actionStatus : null;
|
|
15422
15799
|
childEls.push(/* @__PURE__ */ jsx$1(ConfigActionRow, {
|
|
15800
|
+
onClick: () => onRowClick?.(index),
|
|
15423
15801
|
id: anchorIdFor(index),
|
|
15424
15802
|
indent: EXTENSION_CONFIG_INDENT,
|
|
15425
15803
|
label: item.label,
|
|
@@ -15430,6 +15808,7 @@ function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCo
|
|
|
15430
15808
|
bg: childBg
|
|
15431
15809
|
}, item.key));
|
|
15432
15810
|
} else if (item.type === "boolean") childEls.push(/* @__PURE__ */ jsx$1(ToggleRow, {
|
|
15811
|
+
onClick: (zone) => onRowClick?.(index, zone),
|
|
15433
15812
|
id: anchorIdFor(index),
|
|
15434
15813
|
indent: EXTENSION_CONFIG_INDENT,
|
|
15435
15814
|
label: item.label,
|
|
@@ -15441,6 +15820,7 @@ function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCo
|
|
|
15441
15820
|
else if (item.type === "enum") {
|
|
15442
15821
|
const opt = item.options.find((o) => o.value === value);
|
|
15443
15822
|
childEls.push(/* @__PURE__ */ jsx$1(ChoiceRow, {
|
|
15823
|
+
onClick: () => onRowClick?.(index),
|
|
15444
15824
|
id: anchorIdFor(index),
|
|
15445
15825
|
indent: EXTENSION_CONFIG_INDENT,
|
|
15446
15826
|
label: item.label,
|
|
@@ -15489,6 +15869,11 @@ function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCo
|
|
|
15489
15869
|
id: anchorIdFor(group.index),
|
|
15490
15870
|
wrapMode: "none",
|
|
15491
15871
|
bg,
|
|
15872
|
+
onMouseDown: onRowClick && ((event) => {
|
|
15873
|
+
event.stopPropagation();
|
|
15874
|
+
event.preventDefault();
|
|
15875
|
+
onRowClick(group.index, inCheckboxZone(event, 4) ? "checkbox" : "row");
|
|
15876
|
+
}),
|
|
15492
15877
|
children: [
|
|
15493
15878
|
/* @__PURE__ */ jsx$1("span", {
|
|
15494
15879
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -15568,11 +15953,16 @@ function CreateExtensionButton() {
|
|
|
15568
15953
|
})]
|
|
15569
15954
|
});
|
|
15570
15955
|
}
|
|
15571
|
-
function ConfigActionRow({ id, label, description, status, probe, focused, bg, indent = 0 }) {
|
|
15956
|
+
function ConfigActionRow({ id, label, description, status, probe, focused, bg, indent = 0, onClick }) {
|
|
15572
15957
|
const COLOR = useColors();
|
|
15573
15958
|
const statusText = (status?.state === "busy" ? "running…" : status?.text) ?? probe?.message;
|
|
15574
15959
|
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
15960
|
return /* @__PURE__ */ jsxs("box", {
|
|
15961
|
+
onMouseDown: onClick && ((event) => {
|
|
15962
|
+
event.stopPropagation();
|
|
15963
|
+
event.preventDefault();
|
|
15964
|
+
onClick();
|
|
15965
|
+
}),
|
|
15576
15966
|
id,
|
|
15577
15967
|
style: {
|
|
15578
15968
|
flexDirection: "column",
|
|
@@ -15745,7 +16135,7 @@ function ConfigModelPickerRow({ id, label, description, catalog, multi, initial,
|
|
|
15745
16135
|
]
|
|
15746
16136
|
});
|
|
15747
16137
|
}
|
|
15748
|
-
function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query, contentCols }) {
|
|
16138
|
+
function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query, contentCols, onRowClick }) {
|
|
15749
16139
|
const COLOR = useColors();
|
|
15750
16140
|
if (totalCount === 0) return /* @__PURE__ */ jsxs("box", {
|
|
15751
16141
|
style: { flexDirection: "column" },
|
|
@@ -15790,6 +16180,11 @@ function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query,
|
|
|
15790
16180
|
const description = truncateToCols(entry.description ?? "", descCols);
|
|
15791
16181
|
const origin = skillOriginLabel(entry);
|
|
15792
16182
|
return /* @__PURE__ */ jsxs("box", {
|
|
16183
|
+
onMouseDown: onRowClick && ((event) => {
|
|
16184
|
+
event.stopPropagation();
|
|
16185
|
+
event.preventDefault();
|
|
16186
|
+
onRowClick(i, "row");
|
|
16187
|
+
}),
|
|
15793
16188
|
id: anchorIdFor(i),
|
|
15794
16189
|
style: {
|
|
15795
16190
|
flexDirection: "column",
|
|
@@ -15800,6 +16195,11 @@ function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query,
|
|
|
15800
16195
|
},
|
|
15801
16196
|
children: [/* @__PURE__ */ jsxs("text", {
|
|
15802
16197
|
wrapMode: "none",
|
|
16198
|
+
onMouseDown: onRowClick && ((event) => {
|
|
16199
|
+
event.stopPropagation();
|
|
16200
|
+
event.preventDefault();
|
|
16201
|
+
onRowClick(i, inCheckboxZone(event, 2) ? "checkbox" : "row");
|
|
16202
|
+
}),
|
|
15803
16203
|
children: [
|
|
15804
16204
|
/* @__PURE__ */ jsx$1("span", {
|
|
15805
16205
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -15827,13 +16227,13 @@ function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query,
|
|
|
15827
16227
|
})
|
|
15828
16228
|
});
|
|
15829
16229
|
}
|
|
15830
|
-
function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServer, toolsRefreshing, expanded, totalCount, cursor, highlightBg, query, errors, authState, contentCols }) {
|
|
16230
|
+
function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServer, toolsRefreshing, expanded, totalCount, cursor, highlightBg, query, errors, authState, contentCols, onRowClick }) {
|
|
15831
16231
|
const COLOR = useColors();
|
|
15832
16232
|
const home = homedir();
|
|
15833
16233
|
if (totalCount === 0) return /* @__PURE__ */ jsxs("box", {
|
|
15834
16234
|
style: { flexDirection: "column" },
|
|
15835
16235
|
children: [
|
|
15836
|
-
renderMcpErrors(errors, home, COLOR.warn),
|
|
16236
|
+
renderMcpErrors(errors, home, COLOR.warn, COLOR.dim),
|
|
15837
16237
|
/* @__PURE__ */ jsx$1("text", {
|
|
15838
16238
|
fg: COLOR.dim,
|
|
15839
16239
|
children: "No MCP servers discovered."
|
|
@@ -15873,7 +16273,7 @@ function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServe
|
|
|
15873
16273
|
});
|
|
15874
16274
|
if (filteredCount === 0) return /* @__PURE__ */ jsxs("box", {
|
|
15875
16275
|
style: { flexDirection: "column" },
|
|
15876
|
-
children: [renderMcpErrors(errors, home, COLOR.warn), /* @__PURE__ */ jsx$1(EmptyRow, { label: `no servers match "${query}"` })]
|
|
16276
|
+
children: [renderMcpErrors(errors, home, COLOR.warn, COLOR.dim), /* @__PURE__ */ jsx$1(EmptyRow, { label: `no servers match "${query}"` })]
|
|
15877
16277
|
});
|
|
15878
16278
|
const groups = [];
|
|
15879
16279
|
for (let i = 0; i < rows.length; i++) {
|
|
@@ -15894,9 +16294,10 @@ function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServe
|
|
|
15894
16294
|
}
|
|
15895
16295
|
return /* @__PURE__ */ jsxs("box", {
|
|
15896
16296
|
style: { flexDirection: "column" },
|
|
15897
|
-
children: [renderMcpErrors(errors, home, COLOR.warn), groups.map((group) => /* @__PURE__ */ jsxs("box", {
|
|
16297
|
+
children: [renderMcpErrors(errors, home, COLOR.warn, COLOR.dim), groups.map((group) => /* @__PURE__ */ jsxs("box", {
|
|
15898
16298
|
style: { flexDirection: "column" },
|
|
15899
16299
|
children: [renderServerListRow({
|
|
16300
|
+
onClick: onRowClick ? (zone) => onRowClick(group.serverIndex, zone) : void 0,
|
|
15900
16301
|
entry: group.server.entry,
|
|
15901
16302
|
focused: group.serverIndex === cursor,
|
|
15902
16303
|
bg: group.serverIndex === cursor ? highlightBg : void 0,
|
|
@@ -15912,6 +16313,7 @@ function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServe
|
|
|
15912
16313
|
const focused = index === cursor;
|
|
15913
16314
|
const bg = focused ? highlightBg : void 0;
|
|
15914
16315
|
if (row.kind === "tool") return renderToolListRow({
|
|
16316
|
+
onClick: onRowClick ? (zone) => onRowClick(index, zone) : void 0,
|
|
15915
16317
|
serverName: row.serverName,
|
|
15916
16318
|
tool: row.tool,
|
|
15917
16319
|
focused,
|
|
@@ -15933,7 +16335,7 @@ function McpsList({ rows, filteredCount, enabledSet, toolToggleMap, toolsByServe
|
|
|
15933
16335
|
}, `group:${group.server.entry.config.name}`))]
|
|
15934
16336
|
});
|
|
15935
16337
|
}
|
|
15936
|
-
function renderServerListRow({ entry, focused, bg, enabled, expanded, toolEnabledSet, toolTotal, anchorId, status, COLOR, contentCols }) {
|
|
16338
|
+
function renderServerListRow({ onClick, entry, focused, bg, enabled, expanded, toolEnabledSet, toolTotal, anchorId, status, COLOR, contentCols }) {
|
|
15937
16339
|
const name = entry.config.name;
|
|
15938
16340
|
const chevron = expanded ? "▾" : "▸";
|
|
15939
16341
|
const toolCountChip = toolEnabledSet && typeof toolTotal === "number" ? ` (${toolEnabledSet.size}/${toolTotal})` : "";
|
|
@@ -15944,6 +16346,11 @@ function renderServerListRow({ entry, focused, bg, enabled, expanded, toolEnable
|
|
|
15944
16346
|
id: anchorId,
|
|
15945
16347
|
wrapMode: "none",
|
|
15946
16348
|
bg,
|
|
16349
|
+
onMouseDown: onClick && ((event) => {
|
|
16350
|
+
event.stopPropagation();
|
|
16351
|
+
event.preventDefault();
|
|
16352
|
+
onClick(inCheckboxZone(event, 4) ? "checkbox" : "row");
|
|
16353
|
+
}),
|
|
15947
16354
|
children: [
|
|
15948
16355
|
/* @__PURE__ */ jsx$1("span", {
|
|
15949
16356
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -15975,13 +16382,18 @@ function renderServerListRow({ entry, focused, bg, enabled, expanded, toolEnable
|
|
|
15975
16382
|
}
|
|
15976
16383
|
const TOOL_ROW_INDENT$1 = " ";
|
|
15977
16384
|
const TOOL_ROW_FOCUS_INDENT$1 = " ▶ ";
|
|
15978
|
-
function renderToolListRow({ serverName, tool, focused, bg, enabled, anchorId, COLOR, contentCols }) {
|
|
16385
|
+
function renderToolListRow({ onClick, serverName, tool, focused, bg, enabled, anchorId, COLOR, contentCols }) {
|
|
15979
16386
|
const descBudget = Math.max(0, contentCols - 6 - 4 - tool.name.length - 2);
|
|
15980
16387
|
const description = truncateToCols(tool.description ?? "", descBudget);
|
|
15981
16388
|
return /* @__PURE__ */ jsxs("text", {
|
|
15982
16389
|
id: anchorId,
|
|
15983
16390
|
wrapMode: "none",
|
|
15984
16391
|
bg,
|
|
16392
|
+
onMouseDown: onClick && ((event) => {
|
|
16393
|
+
event.stopPropagation();
|
|
16394
|
+
event.preventDefault();
|
|
16395
|
+
onClick(inCheckboxZone(event, 6) ? "checkbox" : "row");
|
|
16396
|
+
}),
|
|
15985
16397
|
children: [
|
|
15986
16398
|
/* @__PURE__ */ jsx$1("span", {
|
|
15987
16399
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -16204,9 +16616,14 @@ function AuthenticationList({ view, providers, cursor, highlightBg, query }) {
|
|
|
16204
16616
|
]
|
|
16205
16617
|
});
|
|
16206
16618
|
}
|
|
16207
|
-
function ToggleRow({ id, label, description, enabled, focused, bg, indent = 0 }) {
|
|
16619
|
+
function ToggleRow({ id, label, description, enabled, focused, bg, indent = 0, onClick }) {
|
|
16208
16620
|
const COLOR = useColors();
|
|
16209
16621
|
return /* @__PURE__ */ jsxs("box", {
|
|
16622
|
+
onMouseDown: onClick && ((event) => {
|
|
16623
|
+
event.stopPropagation();
|
|
16624
|
+
event.preventDefault();
|
|
16625
|
+
onClick("row");
|
|
16626
|
+
}),
|
|
16210
16627
|
id,
|
|
16211
16628
|
style: {
|
|
16212
16629
|
flexDirection: "column",
|
|
@@ -16217,6 +16634,11 @@ function ToggleRow({ id, label, description, enabled, focused, bg, indent = 0 })
|
|
|
16217
16634
|
},
|
|
16218
16635
|
children: [/* @__PURE__ */ jsxs("text", {
|
|
16219
16636
|
wrapMode: "none",
|
|
16637
|
+
onMouseDown: onClick && ((event) => {
|
|
16638
|
+
event.stopPropagation();
|
|
16639
|
+
event.preventDefault();
|
|
16640
|
+
onClick(inCheckboxZone(event, 2) ? "checkbox" : "row");
|
|
16641
|
+
}),
|
|
16220
16642
|
children: [
|
|
16221
16643
|
/* @__PURE__ */ jsx$1("span", {
|
|
16222
16644
|
fg: focused ? COLOR.brand : COLOR.mute,
|
|
@@ -16238,9 +16660,14 @@ function ToggleRow({ id, label, description, enabled, focused, bg, indent = 0 })
|
|
|
16238
16660
|
})]
|
|
16239
16661
|
});
|
|
16240
16662
|
}
|
|
16241
|
-
function ChoiceRow({ id, label, description, value, cyclable, focused, bg, indent = 0 }) {
|
|
16663
|
+
function ChoiceRow({ id, label, description, value, cyclable, focused, bg, indent = 0, onClick }) {
|
|
16242
16664
|
const COLOR = useColors();
|
|
16243
16665
|
return /* @__PURE__ */ jsxs("box", {
|
|
16666
|
+
onMouseDown: onClick && ((event) => {
|
|
16667
|
+
event.stopPropagation();
|
|
16668
|
+
event.preventDefault();
|
|
16669
|
+
onClick();
|
|
16670
|
+
}),
|
|
16244
16671
|
id,
|
|
16245
16672
|
style: {
|
|
16246
16673
|
flexDirection: "column",
|
|
@@ -16284,9 +16711,14 @@ function ChoiceRow({ id, label, description, value, cyclable, focused, bg, inden
|
|
|
16284
16711
|
})]
|
|
16285
16712
|
});
|
|
16286
16713
|
}
|
|
16287
|
-
function ActionRow$1({ id, label, description, focused, bg }) {
|
|
16714
|
+
function ActionRow$1({ id, label, description, focused, bg, onClick }) {
|
|
16288
16715
|
const COLOR = useColors();
|
|
16289
16716
|
return /* @__PURE__ */ jsxs("box", {
|
|
16717
|
+
onMouseDown: onClick && ((event) => {
|
|
16718
|
+
event.stopPropagation();
|
|
16719
|
+
event.preventDefault();
|
|
16720
|
+
onClick();
|
|
16721
|
+
}),
|
|
16290
16722
|
id,
|
|
16291
16723
|
style: {
|
|
16292
16724
|
flexDirection: "column",
|
|
@@ -16322,10 +16754,15 @@ function ActionRow$1({ id, label, description, focused, bg }) {
|
|
|
16322
16754
|
})]
|
|
16323
16755
|
});
|
|
16324
16756
|
}
|
|
16325
|
-
function InputRow({ id, label, description, value, placeholder, editing, focused, bg }) {
|
|
16757
|
+
function InputRow({ id, label, description, value, placeholder, editing, focused, bg, onClick }) {
|
|
16326
16758
|
const COLOR = useColors();
|
|
16327
16759
|
const hasValue = value.length > 0;
|
|
16328
16760
|
return /* @__PURE__ */ jsxs("box", {
|
|
16761
|
+
onMouseDown: onClick && ((event) => {
|
|
16762
|
+
event.stopPropagation();
|
|
16763
|
+
event.preventDefault();
|
|
16764
|
+
onClick();
|
|
16765
|
+
}),
|
|
16329
16766
|
id,
|
|
16330
16767
|
style: {
|
|
16331
16768
|
flexDirection: "column",
|
|
@@ -16491,13 +16928,13 @@ function renderInlineMcpBadge(status, COLOR) {
|
|
|
16491
16928
|
});
|
|
16492
16929
|
}
|
|
16493
16930
|
}
|
|
16494
|
-
function renderMcpErrors(errors, home, warnColor) {
|
|
16931
|
+
function renderMcpErrors(errors, home, warnColor, dimColor) {
|
|
16495
16932
|
if (!errors || errors.length === 0) return null;
|
|
16496
16933
|
return /* @__PURE__ */ jsx$1("box", {
|
|
16497
16934
|
style: { flexDirection: "column" },
|
|
16498
16935
|
children: errors.map((err) => /* @__PURE__ */ jsx$1("text", {
|
|
16499
|
-
fg: warnColor,
|
|
16500
|
-
children:
|
|
16936
|
+
fg: err.informational ? dimColor : warnColor,
|
|
16937
|
+
children: `${err.informational ? "i" : "!"} ${displayPath$1(err.path, home)}: ${err.message}`
|
|
16501
16938
|
}, err.path))
|
|
16502
16939
|
});
|
|
16503
16940
|
}
|
|
@@ -16508,155 +16945,89 @@ function Hints({ activeTab, focusedMcp, focusedMcpRow, focusedMcpStatus, canRefr
|
|
|
16508
16945
|
const showLogout = activeTab === "mcps" && onServerRow && !!focusedMcpStatus && canLogout$1(focusedMcpStatus);
|
|
16509
16946
|
const showCancel = activeTab === "mcps" && focusedMcpStatus?.kind === "authorizing";
|
|
16510
16947
|
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
|
-
});
|
|
16948
|
+
return /* @__PURE__ */ jsx$1(HintRow, { hints: [
|
|
16949
|
+
{
|
|
16950
|
+
key: "←→",
|
|
16951
|
+
label: "tabs"
|
|
16952
|
+
},
|
|
16953
|
+
{
|
|
16954
|
+
key: "↑↓",
|
|
16955
|
+
label: activeTab === "keybindings" || activeTab === "logs" ? "scroll" : "navigate"
|
|
16956
|
+
},
|
|
16957
|
+
...activeTab === "logs" ? [{
|
|
16958
|
+
key: "ctrl+l",
|
|
16959
|
+
label: "level"
|
|
16960
|
+
}, {
|
|
16961
|
+
key: "",
|
|
16962
|
+
label: "type to filter"
|
|
16963
|
+
}] : [{
|
|
16964
|
+
key: "↵",
|
|
16965
|
+
label: isCategoryTab(activeTab) ? "toggle/cycle/select" : activeTab === "keybindings" ? "edit file" : activeTab === "authentication" ? "switch / re-authenticate" : "toggle"
|
|
16966
|
+
}],
|
|
16967
|
+
...activeTab === "mcps" && focusedMcpRow ? [{
|
|
16968
|
+
key: "tab",
|
|
16969
|
+
label: focusedMcpRow.kind === "server" ? "expand/collapse" : "collapse"
|
|
16970
|
+
}] : [],
|
|
16971
|
+
...activeTab === "extensions" && focusedExtensionExpandable ? [{
|
|
16972
|
+
key: "tab",
|
|
16973
|
+
label: "settings"
|
|
16974
|
+
}] : [],
|
|
16975
|
+
...activeTab === "extensions" && canEditExtension ? [{
|
|
16976
|
+
key: "ctrl+e",
|
|
16977
|
+
label: "edit"
|
|
16978
|
+
}] : [],
|
|
16979
|
+
...activeTab === "extensions" && canCreateExtension ? [{
|
|
16980
|
+
key: "ctrl+a",
|
|
16981
|
+
label: "create"
|
|
16982
|
+
}] : [],
|
|
16983
|
+
...activeTab === "extensions" && canUpdateExtension ? [{
|
|
16984
|
+
key: "ctrl+u",
|
|
16985
|
+
label: "update"
|
|
16986
|
+
}] : [],
|
|
16987
|
+
...activeTab === "extensions" && canRemoveExtension ? [{
|
|
16988
|
+
key: "ctrl+x",
|
|
16989
|
+
label: "remove"
|
|
16990
|
+
}] : [],
|
|
16991
|
+
...activeTab === "extensions" && canInstallExtension ? [{
|
|
16992
|
+
key: "ctrl+g",
|
|
16993
|
+
label: "install"
|
|
16994
|
+
}] : [],
|
|
16995
|
+
...activeTab === "skills" && canInstallSkill ? [{
|
|
16996
|
+
key: "ctrl+g",
|
|
16997
|
+
label: "install"
|
|
16998
|
+
}] : [],
|
|
16999
|
+
...activeTab === "skills" && canRemoveSkill ? [{
|
|
17000
|
+
key: "ctrl+x",
|
|
17001
|
+
label: "delete"
|
|
17002
|
+
}] : [],
|
|
17003
|
+
...activeTab === "mcps" && canAddMcp ? [{
|
|
17004
|
+
key: "ctrl+g",
|
|
17005
|
+
label: "add server"
|
|
17006
|
+
}] : [],
|
|
17007
|
+
...activeTab === "mcps" && canRemoveMcp && onServerRow ? [{
|
|
17008
|
+
key: "ctrl+x",
|
|
17009
|
+
label: "remove"
|
|
17010
|
+
}] : [],
|
|
17011
|
+
...showLogin ? [{
|
|
17012
|
+
key: "ctrl+L",
|
|
17013
|
+
label: "login"
|
|
17014
|
+
}] : [],
|
|
17015
|
+
...showLogout ? [{
|
|
17016
|
+
key: "ctrl+O",
|
|
17017
|
+
label: "logout"
|
|
17018
|
+
}] : [],
|
|
17019
|
+
...showRefresh ? [{
|
|
17020
|
+
key: "ctrl+r",
|
|
17021
|
+
label: "refresh"
|
|
17022
|
+
}] : [],
|
|
17023
|
+
{
|
|
17024
|
+
key: "esc",
|
|
17025
|
+
label: showCancel ? "cancel" : "close"
|
|
17026
|
+
}
|
|
17027
|
+
].map((h) => ({
|
|
17028
|
+
...h,
|
|
17029
|
+
labelColor: COLOR.mute
|
|
17030
|
+
})) });
|
|
16660
17031
|
}
|
|
16661
17032
|
function generalCorpus(item) {
|
|
16662
17033
|
const parts = [item.label, item.description];
|
|
@@ -16796,7 +17167,10 @@ function composeTerminalTitle(opts) {
|
|
|
16796
17167
|
* bring it back later. No-op when `out` isn't a TTY.
|
|
16797
17168
|
*/
|
|
16798
17169
|
function saveTerminalTitle(out = process.stdout) {
|
|
16799
|
-
if (out.isTTY)
|
|
17170
|
+
if (!out.isTTY) return;
|
|
17171
|
+
try {
|
|
17172
|
+
out.write(TITLE_STACK_PUSH);
|
|
17173
|
+
} catch {}
|
|
16800
17174
|
}
|
|
16801
17175
|
/**
|
|
16802
17176
|
* Clear our title and pop the previously-saved one. No-op when `out`
|
|
@@ -16804,7 +17178,10 @@ function saveTerminalTitle(out = process.stdout) {
|
|
|
16804
17178
|
* otherwise the clear would wipe a title zidane never set.
|
|
16805
17179
|
*/
|
|
16806
17180
|
function restoreTerminalTitle(out = process.stdout) {
|
|
16807
|
-
if (out.isTTY)
|
|
17181
|
+
if (!out.isTTY) return;
|
|
17182
|
+
try {
|
|
17183
|
+
out.write(TITLE_STACK_RESTORE);
|
|
17184
|
+
} catch {}
|
|
16808
17185
|
}
|
|
16809
17186
|
//#endregion
|
|
16810
17187
|
//#region src/tui/todos-modal.tsx
|
|
@@ -17891,6 +18268,7 @@ function AppShell() {
|
|
|
17891
18268
|
if (settings.maxCostUsd > 0) caps.maxCostUsd = settings.maxCostUsd;
|
|
17892
18269
|
if (settings.maxTotalTokens > 0) caps.maxTotalTokens = settings.maxTotalTokens;
|
|
17893
18270
|
if (settings.maxWallMinutes > 0) caps.maxWallMs = settings.maxWallMinutes * 6e4;
|
|
18271
|
+
if (settings.retryMaxAttempts > 0) caps.retry = { maxAttempts: settings.retryMaxAttempts };
|
|
17894
18272
|
return caps;
|
|
17895
18273
|
}, [
|
|
17896
18274
|
settings.resumeOnMaxTokens,
|
|
@@ -17898,7 +18276,8 @@ function AppShell() {
|
|
|
17898
18276
|
settings.maxTurns,
|
|
17899
18277
|
settings.maxCostUsd,
|
|
17900
18278
|
settings.maxTotalTokens,
|
|
17901
|
-
settings.maxWallMinutes
|
|
18279
|
+
settings.maxWallMinutes,
|
|
18280
|
+
settings.retryMaxAttempts
|
|
17902
18281
|
]);
|
|
17903
18282
|
const runCapsRef = useRef(runCaps);
|
|
17904
18283
|
runCapsRef.current = runCaps;
|
|
@@ -18256,6 +18635,22 @@ function AppShell() {
|
|
|
18256
18635
|
*/
|
|
18257
18636
|
const [compacting, setCompacting] = useState(false);
|
|
18258
18637
|
/**
|
|
18638
|
+
* Live provider-retry indicator — set by `stream:retry` (and the bubbled
|
|
18639
|
+
* `child:stream:retry`, since a stalled subagent stalls the pipeline the
|
|
18640
|
+
* user is watching), cleared when the SAME source streams output again
|
|
18641
|
+
* or the run ends. Keyed by source (`'parent'` / childId) so a parallel
|
|
18642
|
+
* batch can't hide one child's still-active backoff behind a sibling's
|
|
18643
|
+
* output — the motivating /review case runs many children at once.
|
|
18644
|
+
* Drives the footer's `Retrying (n/max)` status; last retry wins the
|
|
18645
|
+
* single slot.
|
|
18646
|
+
*/
|
|
18647
|
+
const [retryInfo, setRetryInfo] = useState(null);
|
|
18648
|
+
/** Source-scoped functional clear — bails re-render when nothing matches (hot path: every stream delta). */
|
|
18649
|
+
const clearRetryInfo = useCallback((source) => setRetryInfo((prev) => prev !== null && prev.source === source ? null : prev), []);
|
|
18650
|
+
useEffect(() => {
|
|
18651
|
+
if (!busy) setRetryInfo((prev) => prev === null ? prev : null);
|
|
18652
|
+
}, [busy]);
|
|
18653
|
+
/**
|
|
18259
18654
|
* Rough token estimate of the in-flight compaction summary, painted
|
|
18260
18655
|
* next to the footer's "Compacting…" label (`null` = no live estimate
|
|
18261
18656
|
* yet). Fed by the loop's throttled `compact:progress` hook and the
|
|
@@ -19179,8 +19574,26 @@ function AppShell() {
|
|
|
19179
19574
|
});
|
|
19180
19575
|
if (pendingAutoLoginMcpRef.current === name) pendingAutoLoginMcpRef.current = null;
|
|
19181
19576
|
});
|
|
19182
|
-
agent.hooks.hook("stream:thinking", ({ delta, turnId }) =>
|
|
19183
|
-
|
|
19577
|
+
agent.hooks.hook("stream:thinking", ({ delta, turnId }) => {
|
|
19578
|
+
clearRetryInfo("parent");
|
|
19579
|
+
stream.queueStreamDelta("thinking", delta, { turnId });
|
|
19580
|
+
});
|
|
19581
|
+
agent.hooks.hook("stream:text", ({ delta, turnId }) => {
|
|
19582
|
+
clearRetryInfo("parent");
|
|
19583
|
+
stream.queueStreamDelta("markdown", delta, { turnId });
|
|
19584
|
+
});
|
|
19585
|
+
agent.hooks.hook("stream:retry", ({ nextAttempt, maxAttempts }) => setRetryInfo({
|
|
19586
|
+
attempt: nextAttempt,
|
|
19587
|
+
max: maxAttempts,
|
|
19588
|
+
source: "parent"
|
|
19589
|
+
}));
|
|
19590
|
+
agent.hooks.hook("child:stream:retry", ({ nextAttempt, maxAttempts, childId }) => setRetryInfo({
|
|
19591
|
+
attempt: nextAttempt,
|
|
19592
|
+
max: maxAttempts,
|
|
19593
|
+
source: childId
|
|
19594
|
+
}));
|
|
19595
|
+
agent.hooks.hook("stream:error", () => clearRetryInfo("parent"));
|
|
19596
|
+
agent.hooks.hook("child:stream:error", ({ childId }) => clearRetryInfo(childId));
|
|
19184
19597
|
agent.hooks.hook("stream:server_tool_use", ({ id, name, input, turnId }) => {
|
|
19185
19598
|
stream.appendImmediate({
|
|
19186
19599
|
kind: "tool",
|
|
@@ -19383,7 +19796,7 @@ function AppShell() {
|
|
|
19383
19796
|
lastInputTokensRef.current = ctx.effectiveTokens;
|
|
19384
19797
|
});
|
|
19385
19798
|
const spawnStartedAt = /* @__PURE__ */ new Map();
|
|
19386
|
-
agent.hooks.hook("spawn:before", ({ id, task, depth, model }) => {
|
|
19799
|
+
agent.hooks.hook("spawn:before", ({ id, task, depth, model, resumesChildId }) => {
|
|
19387
19800
|
const startedAt = Date.now();
|
|
19388
19801
|
const taskPreview = previewLine(task, 80);
|
|
19389
19802
|
spawnStartedAt.set(id, {
|
|
@@ -19393,7 +19806,7 @@ function AppShell() {
|
|
|
19393
19806
|
});
|
|
19394
19807
|
stream.appendImmediate({
|
|
19395
19808
|
kind: "spawn-start",
|
|
19396
|
-
text: taskPreview,
|
|
19809
|
+
text: resumesChildId ? `resumes ${resumesChildId} · ${taskPreview}` : taskPreview,
|
|
19397
19810
|
childId: id,
|
|
19398
19811
|
depth: depth ?? 1,
|
|
19399
19812
|
spawn: { startedAt },
|
|
@@ -19430,6 +19843,7 @@ function AppShell() {
|
|
|
19430
19843
|
});
|
|
19431
19844
|
});
|
|
19432
19845
|
agent.hooks.hook("child:stream:thinking", ({ delta, childId, depth, turnId }) => {
|
|
19846
|
+
clearRetryInfo(childId);
|
|
19433
19847
|
stream.queueStreamDelta("thinking", delta, {
|
|
19434
19848
|
childId,
|
|
19435
19849
|
depth,
|
|
@@ -19437,6 +19851,7 @@ function AppShell() {
|
|
|
19437
19851
|
});
|
|
19438
19852
|
});
|
|
19439
19853
|
agent.hooks.hook("child:stream:text", ({ delta, childId, depth, turnId }) => {
|
|
19854
|
+
clearRetryInfo(childId);
|
|
19440
19855
|
stream.queueStreamDelta("markdown", delta, {
|
|
19441
19856
|
childId,
|
|
19442
19857
|
depth,
|
|
@@ -20952,7 +21367,10 @@ function AppShell() {
|
|
|
20952
21367
|
mcpServers: [...agent.mcpServers],
|
|
20953
21368
|
...parentMcp ? { mcpConnection: nonOwningMcpView(parentMcp) } : {},
|
|
20954
21369
|
skills: seam.skills,
|
|
20955
|
-
behavior:
|
|
21370
|
+
behavior: {
|
|
21371
|
+
...seam.behavior,
|
|
21372
|
+
...runCapsRef.current
|
|
21373
|
+
},
|
|
20956
21374
|
turnId: `command_${invocation.name}`,
|
|
20957
21375
|
callId: `command_spawn_${crypto.randomUUID()}`,
|
|
20958
21376
|
session
|
|
@@ -21534,9 +21952,10 @@ function AppShell() {
|
|
|
21534
21952
|
]);
|
|
21535
21953
|
onLoginMcpRef.current = onLoginMcp;
|
|
21536
21954
|
const onLogoutMcp = useCallback((name) => {
|
|
21955
|
+
const hadTokens = !!mcpCredentialStore.load(name)?.tokens;
|
|
21537
21956
|
mcpCredentialStore.delete(name);
|
|
21538
21957
|
const entry = mcpsCatalogRef.current.find((d) => d.config.name === name);
|
|
21539
|
-
dispatchAuth(entry?.config.auth === "oauth" ? {
|
|
21958
|
+
dispatchAuth(entry?.config.auth === "oauth" || hadTokens ? {
|
|
21540
21959
|
type: "auth-required",
|
|
21541
21960
|
name,
|
|
21542
21961
|
reason: "no-tokens"
|
|
@@ -22650,9 +23069,10 @@ function AppShell() {
|
|
|
22650
23069
|
hints,
|
|
22651
23070
|
context: contextUsage,
|
|
22652
23071
|
cost: footerCost,
|
|
22653
|
-
status: transcriptSearchMode && transcriptSearchSearching ? "searching" : pendingInteraction?.kind === "question" ? "asking" : compacting ? "compacting" : busy ? "busy" : null,
|
|
23072
|
+
status: transcriptSearchMode && transcriptSearchSearching ? "searching" : pendingInteraction?.kind === "question" ? "asking" : compacting ? "compacting" : retryInfo && busy ? "retrying" : busy ? "busy" : null,
|
|
22654
23073
|
compactionTokens,
|
|
22655
|
-
compactionStartedAt
|
|
23074
|
+
compactionStartedAt,
|
|
23075
|
+
retry: retryInfo
|
|
22656
23076
|
}),
|
|
22657
23077
|
showQuitConfirm && /* @__PURE__ */ jsxs("box", {
|
|
22658
23078
|
position: "absolute",
|
|
@@ -22674,12 +23094,24 @@ function AppShell() {
|
|
|
22674
23094
|
gap: 2,
|
|
22675
23095
|
children: [/* @__PURE__ */ jsx$1("box", {
|
|
22676
23096
|
backgroundColor: quitConfirmSelected === "cancel" ? COLOR.accent : void 0,
|
|
23097
|
+
onMouseDown: (event) => {
|
|
23098
|
+
event.stopPropagation();
|
|
23099
|
+
event.preventDefault();
|
|
23100
|
+
if (quitConfirmSelectedRef.current === "cancel") setShowQuitConfirm(false);
|
|
23101
|
+
else setQuitConfirmSelected("cancel");
|
|
23102
|
+
},
|
|
22677
23103
|
children: /* @__PURE__ */ jsx$1("text", {
|
|
22678
23104
|
fg: quitConfirmSelected === "cancel" ? SURFACE.modal : COLOR.dim,
|
|
22679
23105
|
children: " Cancel "
|
|
22680
23106
|
})
|
|
22681
23107
|
}), /* @__PURE__ */ jsx$1("box", {
|
|
22682
23108
|
backgroundColor: quitConfirmSelected === "quit" ? COLOR.warn : void 0,
|
|
23109
|
+
onMouseDown: (event) => {
|
|
23110
|
+
event.stopPropagation();
|
|
23111
|
+
event.preventDefault();
|
|
23112
|
+
if (quitConfirmSelectedRef.current === "quit") renderer.destroy();
|
|
23113
|
+
else setQuitConfirmSelected("quit");
|
|
23114
|
+
},
|
|
22683
23115
|
children: /* @__PURE__ */ jsx$1("text", {
|
|
22684
23116
|
fg: quitConfirmSelected === "quit" ? SURFACE.modal : COLOR.dim,
|
|
22685
23117
|
children: " Quit "
|