dexto 1.6.0 → 1.6.1
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/agents/coding-agent/coding-agent.yml +3 -1
- package/dist/cli/assets/sounds/SOURCES.md +35 -0
- package/dist/cli/assets/sounds/boot.wav +0 -0
- package/dist/cli/assets/sounds/chime.wav +0 -0
- package/dist/cli/assets/sounds/coin.wav +0 -0
- package/dist/cli/assets/sounds/confirm.wav +0 -0
- package/dist/cli/assets/sounds/levelup.wav +0 -0
- package/dist/cli/assets/sounds/ping.wav +0 -0
- package/dist/cli/assets/sounds/powerup.wav +0 -0
- package/dist/cli/assets/sounds/startup.wav +0 -0
- package/dist/cli/assets/sounds/success.wav +0 -0
- package/dist/cli/assets/sounds/treasure.wav +0 -0
- package/dist/cli/assets/sounds/win.wav +0 -0
- package/dist/cli/commands/interactive-commands/exit-handler.d.ts +12 -0
- package/dist/cli/commands/interactive-commands/exit-handler.d.ts.map +1 -0
- package/dist/cli/commands/interactive-commands/exit-handler.js +20 -0
- package/dist/cli/commands/interactive-commands/exit-stats.d.ts +24 -0
- package/dist/cli/commands/interactive-commands/exit-stats.d.ts.map +1 -0
- package/dist/cli/commands/interactive-commands/exit-stats.js +17 -0
- package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/general-commands.js +53 -3
- package/dist/cli/commands/interactive-commands/prompt-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/prompt-commands.js +12 -67
- package/dist/cli/commands/interactive-commands/session/session-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/session/session-commands.js +0 -2
- package/dist/cli/commands/interactive-commands/system/system-commands.d.ts +1 -13
- package/dist/cli/commands/interactive-commands/system/system-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/system/system-commands.js +45 -54
- package/dist/cli/ink-cli/InkCLIRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/InkCLIRefactored.js +132 -21
- package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ApprovalPrompt.js +74 -20
- package/dist/cli/ink-cli/components/ElicitationForm.d.ts +5 -3
- package/dist/cli/ink-cli/components/ElicitationForm.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ElicitationForm.js +414 -180
- package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ResourceAutocomplete.js +20 -11
- package/dist/cli/ink-cli/components/SlashCommandAutocomplete.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/SlashCommandAutocomplete.js +47 -67
- package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/StatusBar.js +10 -4
- package/dist/cli/ink-cli/components/base/BaseSelector.d.ts +2 -1
- package/dist/cli/ink-cli/components/base/BaseSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/base/BaseSelector.js +37 -27
- package/dist/cli/ink-cli/components/chat/Header.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/Header.js +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.js +3 -1
- package/dist/cli/ink-cli/components/chat/ToolIcon.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/ToolIcon.js +5 -15
- package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +1 -1
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +4 -2
- package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.js +9 -2
- package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.d.ts +13 -0
- package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.js +60 -0
- package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +213 -100
- package/dist/cli/ink-cli/components/overlays/PromptList.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/PromptList.js +12 -16
- package/dist/cli/ink-cli/components/overlays/SoundsSelector.d.ts +21 -0
- package/dist/cli/ink-cli/components/overlays/SoundsSelector.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/SoundsSelector.js +566 -0
- package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/ToolBrowser.js +94 -39
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.js +8 -13
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts +3 -3
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.js +6 -5
- package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts +3 -1
- package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/FileRenderer.js +18 -7
- package/dist/cli/ink-cli/components/renderers/ShellRenderer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/ShellRenderer.js +7 -17
- package/dist/cli/ink-cli/components/renderers/index.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/index.js +1 -1
- package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.d.ts +7 -0
- package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.js +8 -0
- package/dist/cli/ink-cli/components/shared/HintBar.d.ts +6 -0
- package/dist/cli/ink-cli/components/shared/HintBar.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/shared/HintBar.js +6 -0
- package/dist/cli/ink-cli/constants/spinnerFrames.d.ts +2 -0
- package/dist/cli/ink-cli/constants/spinnerFrames.d.ts.map +1 -0
- package/dist/cli/ink-cli/constants/spinnerFrames.js +1 -0
- package/dist/cli/ink-cli/constants/tips.d.ts.map +1 -1
- package/dist/cli/ink-cli/constants/tips.js +1 -0
- package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/InputContainer.js +19 -15
- package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/OverlayContainer.js +21 -5
- package/dist/cli/ink-cli/hooks/useAnimationTick.d.ts +11 -0
- package/dist/cli/ink-cli/hooks/useAnimationTick.d.ts.map +1 -0
- package/dist/cli/ink-cli/hooks/useAnimationTick.js +54 -0
- package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useCLIState.js +1 -0
- package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
- package/dist/cli/ink-cli/services/processStream.js +17 -8
- package/dist/cli/ink-cli/state/initialState.d.ts.map +1 -1
- package/dist/cli/ink-cli/state/initialState.js +1 -0
- package/dist/cli/ink-cli/state/types.d.ts +13 -1
- package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/commandOverlays.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/commandOverlays.js +1 -0
- package/dist/cli/ink-cli/utils/elicitationSchema.d.ts +11 -0
- package/dist/cli/ink-cli/utils/elicitationSchema.d.ts.map +1 -0
- package/dist/cli/ink-cli/utils/elicitationSchema.js +80 -0
- package/dist/cli/ink-cli/utils/index.d.ts +1 -1
- package/dist/cli/ink-cli/utils/index.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/index.js +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts +2 -17
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.js +22 -128
- package/dist/cli/ink-cli/utils/overlayPresentation.d.ts +19 -0
- package/dist/cli/ink-cli/utils/overlayPresentation.d.ts.map +1 -0
- package/dist/cli/ink-cli/utils/overlayPresentation.js +33 -0
- package/dist/cli/ink-cli/utils/overlaySizing.d.ts +19 -0
- package/dist/cli/ink-cli/utils/overlaySizing.d.ts.map +1 -0
- package/dist/cli/ink-cli/utils/overlaySizing.js +11 -0
- package/dist/cli/ink-cli/utils/soundNotification.d.ts +19 -13
- package/dist/cli/ink-cli/utils/soundNotification.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/soundNotification.js +120 -97
- package/dist/utils/session-logger-factory.d.ts.map +1 -1
- package/dist/utils/session-logger-factory.js +17 -2
- package/dist/webui/assets/{index-DwtueA8l.js → index-CKhumsZA.js} +135 -135
- package/dist/webui/index.html +1 -1
- package/package.json +11 -11
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* AlternateBufferCLI - VirtualizedList rendering mode
|
|
4
4
|
*
|
|
@@ -30,6 +30,7 @@ import { VirtualizedList, SCROLL_TO_ITEM_END, } from '../shared/VirtualizedList.
|
|
|
30
30
|
// Containers
|
|
31
31
|
import { InputContainer } from '../../containers/InputContainer.js';
|
|
32
32
|
import { OverlayContainer } from '../../containers/OverlayContainer.js';
|
|
33
|
+
import { shouldHideStatusChrome } from '../../utils/overlayPresentation.js';
|
|
33
34
|
export function AlternateBufferCLI({ agent, initialSessionId, initialPrompt, startupInfo, configFilePath, onSelectionAttempt, useStreaming = true, }) {
|
|
34
35
|
// Refs for VirtualizedList
|
|
35
36
|
const listRef = useRef(null);
|
|
@@ -176,5 +177,6 @@ export function AlternateBufferCLI({ agent, initialSessionId, initialPrompt, sta
|
|
|
176
177
|
return 'header';
|
|
177
178
|
return item.message.id;
|
|
178
179
|
}, []);
|
|
179
|
-
|
|
180
|
+
const hideChrome = shouldHideStatusChrome(ui.activeOverlay, approval);
|
|
181
|
+
return (_jsxs(Box, { flexDirection: "column", height: terminalHeight, children: [_jsx(Box, { ref: listContainerRef, flexGrow: 1, flexShrink: 1, minHeight: 0, children: _jsx(VirtualizedList, { ref: listRef, data: listData, renderItem: renderListItem, estimatedItemHeight: estimateItemHeight, keyExtractor: getItemKey, initialScrollIndex: SCROLL_TO_ITEM_END, initialScrollOffsetInIndex: SCROLL_TO_ITEM_END }) }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [!hideChrome && (_jsxs(_Fragment, { children: [_jsx(StatusBar, { agent: agent, isProcessing: ui.isProcessing, isThinking: ui.isThinking, isCompacting: ui.isCompacting, approvalQueueCount: approvalQueue.length, copyModeEnabled: ui.copyModeEnabled, isAwaitingApproval: approval !== null, todoExpanded: ui.todoExpanded, hasTodos: todos.some((t) => t.status !== 'completed'), planModeActive: ui.planModeActive, autoApproveEdits: ui.autoApproveEdits, backgroundTasksRunning: ui.backgroundTasksRunning }), _jsx(BackgroundTasksPanel, { tasks: ui.backgroundTasks, isExpanded: ui.backgroundTasksExpanded, isProcessing: ui.isProcessing }), _jsx(TodoPanel, { todos: todos, isExpanded: ui.todoExpanded, isProcessing: ui.isProcessing }), selectionHintVisible && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "yellowBright", children: "\uD83D\uDCA1 Tip: Hold Option (\u2325) and click to select text, or press Ctrl+S to toggle copy mode" }) })), _jsx(QueuedMessagesDisplay, { messages: queuedMessages })] })), _jsx(InputContainer, { ref: inputContainerRef, buffer: buffer, input: input, ui: ui, session: session, initialPrompt: initialPrompt, approval: approval, queuedMessages: queuedMessages, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setPendingMessages: setPendingMessages, setDequeuedBuffer: setDequeuedBuffer, setQueuedMessages: setQueuedMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, setTodos: setTodos, agent: agent, inputService: inputService, onKeyboardScroll: handleKeyboardScroll, useStreaming: useStreaming, configFilePath: configFilePath }), _jsx(OverlayContainer, { ref: overlayContainerRef, ui: ui, input: input, session: session, approval: approval, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, agent: agent, inputService: inputService, buffer: buffer, onSubmitPromptCommand: handleSubmitPromptCommand, configFilePath: configFilePath }), !hideChrome && ui.exitWarningShown && (_jsxs(Box, { paddingX: 1, children: [_jsx(Text, { color: "yellowBright", bold: true, children: "\u26A0 Press Ctrl+C again to exit" }), _jsx(Text, { color: "gray", children: " (or press any key to cancel)" })] })), !hideChrome && (_jsx(Footer, { agent: agent, sessionId: session.id, modelName: session.modelName, cwd: process.cwd(), ...(branchName ? { branchName } : {}), autoApproveEdits: ui.autoApproveEdits, planModeActive: ui.planModeActive, isShellMode: buffer.text.startsWith('!') })), !hideChrome && ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
|
|
180
182
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StaticCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/StaticCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"StaticCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/StaticCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAsBxD,UAAU,cAAc;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,gBAAgB,EAChB,aAAa,EACb,WAAW,EACX,cAAc,EACd,YAAmB,GACtB,EAAE,cAAc,2CA+PhB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* StaticCLI - Static pattern rendering mode
|
|
4
4
|
*
|
|
@@ -34,6 +34,7 @@ import { BackgroundTasksPanel } from '../BackgroundTasksPanel.js';
|
|
|
34
34
|
// Containers
|
|
35
35
|
import { InputContainer } from '../../containers/InputContainer.js';
|
|
36
36
|
import { OverlayContainer } from '../../containers/OverlayContainer.js';
|
|
37
|
+
import { shouldHideStatusChrome } from '../../utils/overlayPresentation.js';
|
|
37
38
|
export function StaticCLI({ agent, initialSessionId, initialPrompt, startupInfo, configFilePath, useStreaming = true, }) {
|
|
38
39
|
// Use shared CLI state (no keyboard scroll in Static mode)
|
|
39
40
|
const { messages, setMessages, pendingMessages, setPendingMessages, dequeuedBuffer, setDequeuedBuffer, queuedMessages, setQueuedMessages, todos, setTodos, ui, setUi, input, setInput, session, setSession, approval, setApproval, approvalQueue, setApprovalQueue, inputService, buffer, overlayContainerRef, visibleMessages, } = useCLIState({
|
|
@@ -103,5 +104,11 @@ export function StaticCLI({ agent, initialSessionId, initialPrompt, startupInfo,
|
|
|
103
104
|
startupInfo,
|
|
104
105
|
terminalWidth,
|
|
105
106
|
]);
|
|
106
|
-
return (_jsxs(Box, { flexDirection: "column", width: terminalWidth, children: [_jsx(Static, { items: staticItems, children: (item) => item }, staticRemountKey), pendingMessages.map((message) => (_jsx(MessageItem, { message: message, terminalWidth: terminalWidth }, message.id))), dequeuedBuffer.map((message) => (_jsx(MessageItem, { message: message, terminalWidth: terminalWidth }, message.id))), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [
|
|
107
|
+
return (_jsxs(Box, { flexDirection: "column", width: terminalWidth, children: [_jsx(Static, { items: staticItems, children: (item) => item }, staticRemountKey), pendingMessages.map((message) => (_jsx(MessageItem, { message: message, terminalWidth: terminalWidth }, message.id))), dequeuedBuffer.map((message) => (_jsx(MessageItem, { message: message, terminalWidth: terminalWidth }, message.id))), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [(() => {
|
|
108
|
+
const hideChrome = shouldHideStatusChrome(ui.activeOverlay, approval);
|
|
109
|
+
if (hideChrome)
|
|
110
|
+
return null;
|
|
111
|
+
return (_jsxs(_Fragment, { children: [_jsx(StatusBar, { agent: agent, isProcessing: ui.isProcessing, isThinking: ui.isThinking, isCompacting: ui.isCompacting, approvalQueueCount: approvalQueue.length, copyModeEnabled: ui.copyModeEnabled, isAwaitingApproval: approval !== null, todoExpanded: ui.todoExpanded, hasTodos: todos.some((t) => t.status !== 'completed'), planModeActive: ui.planModeActive, autoApproveEdits: ui.autoApproveEdits, backgroundTasksRunning: ui.backgroundTasksRunning }), _jsx(BackgroundTasksPanel, { tasks: ui.backgroundTasks, isExpanded: ui.backgroundTasksExpanded, isProcessing: ui.isProcessing }), _jsx(TodoPanel, { todos: todos, isExpanded: ui.todoExpanded, isProcessing: ui.isProcessing }), _jsx(QueuedMessagesDisplay, { messages: queuedMessages })] }));
|
|
112
|
+
})(), _jsx(InputContainer, { ref: inputContainerRef, buffer: buffer, input: input, ui: ui, session: session, initialPrompt: initialPrompt, approval: approval, queuedMessages: queuedMessages, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setPendingMessages: setPendingMessages, setDequeuedBuffer: setDequeuedBuffer, setQueuedMessages: setQueuedMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, setTodos: setTodos, agent: agent, inputService: inputService, useStreaming: useStreaming, configFilePath: configFilePath }), _jsx(OverlayContainer, { ref: overlayContainerRef, ui: ui, input: input, session: session, approval: approval, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, agent: agent, inputService: inputService, buffer: buffer, refreshStatic: refreshStatic, onSubmitPromptCommand: handleSubmitPromptCommand, configFilePath: configFilePath }), !shouldHideStatusChrome(ui.activeOverlay, approval) && ui.exitWarningShown && (_jsxs(Box, { paddingX: 1, children: [_jsx(Text, { color: "yellowBright", bold: true, children: "\u26A0 Press Ctrl+C again to exit" }), _jsx(Text, { color: "gray", children: " (or press any key to cancel)" })] })), !shouldHideStatusChrome(ui.activeOverlay, approval) && (_jsx(Footer, { agent: agent, sessionId: session.id, modelName: session.modelName, cwd: process.cwd(), ...(branchName ? { branchName } : {}), autoApproveEdits: ui.autoApproveEdits, planModeActive: ui.planModeActive, isShellMode: buffer.text.startsWith('!') })), !shouldHideStatusChrome(ui.activeOverlay, approval) &&
|
|
113
|
+
ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
|
|
107
114
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { Key } from '../../hooks/useInputOrchestrator.js';
|
|
3
|
+
export interface CommandOutputOverlayProps {
|
|
4
|
+
isVisible: boolean;
|
|
5
|
+
title: string;
|
|
6
|
+
content: string;
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
}
|
|
9
|
+
export interface CommandOutputOverlayHandle {
|
|
10
|
+
handleInput: (input: string, key: Key) => boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare const CommandOutputOverlay: React.ForwardRefExoticComponent<CommandOutputOverlayProps & React.RefAttributes<CommandOutputOverlayHandle>>;
|
|
13
|
+
//# sourceMappingURL=CommandOutputOverlay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommandOutputOverlay.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/CommandOutputOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAG7F,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAK/D,MAAM,WAAW,yBAAyB;IACtC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACvC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED,eAAO,MAAM,oBAAoB,8GAuF/B,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import wrapAnsi from 'wrap-ansi';
|
|
5
|
+
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
|
|
6
|
+
import { getMaxVisibleItemsForTerminalRows } from '../../utils/overlaySizing.js';
|
|
7
|
+
import { HintBar } from '../shared/HintBar.js';
|
|
8
|
+
export const CommandOutputOverlay = forwardRef(function CommandOutputOverlay({ isVisible, title, content, onClose }, ref) {
|
|
9
|
+
const { columns, rows } = useTerminalSize();
|
|
10
|
+
const viewportLines = useMemo(() => {
|
|
11
|
+
return getMaxVisibleItemsForTerminalRows({
|
|
12
|
+
rows,
|
|
13
|
+
hardCap: 20,
|
|
14
|
+
reservedRows: 10,
|
|
15
|
+
});
|
|
16
|
+
}, [rows]);
|
|
17
|
+
const [scrollOffset, setScrollOffset] = useState(0);
|
|
18
|
+
const wrappedLines = useMemo(() => {
|
|
19
|
+
const width = Math.max(20, columns - 2);
|
|
20
|
+
const wrapped = wrapAnsi(content || '', width, {
|
|
21
|
+
hard: true,
|
|
22
|
+
wordWrap: true,
|
|
23
|
+
trim: false,
|
|
24
|
+
});
|
|
25
|
+
return wrapped.length > 0 ? wrapped.split('\n') : [];
|
|
26
|
+
}, [content, columns]);
|
|
27
|
+
const maxScrollOffset = useMemo(() => {
|
|
28
|
+
return Math.max(0, wrappedLines.length - viewportLines);
|
|
29
|
+
}, [wrappedLines.length, viewportLines]);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
setScrollOffset((prev) => Math.min(maxScrollOffset, Math.max(0, prev)));
|
|
32
|
+
}, [maxScrollOffset]);
|
|
33
|
+
useImperativeHandle(ref, () => ({
|
|
34
|
+
handleInput: (_input, key) => {
|
|
35
|
+
if (!isVisible)
|
|
36
|
+
return false;
|
|
37
|
+
if (key.escape) {
|
|
38
|
+
onClose();
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
if (key.upArrow) {
|
|
42
|
+
setScrollOffset((prev) => Math.max(0, prev - 1));
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (key.downArrow) {
|
|
46
|
+
setScrollOffset((prev) => Math.min(maxScrollOffset, prev + 1));
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
},
|
|
51
|
+
}), [isVisible, maxScrollOffset, onClose]);
|
|
52
|
+
if (!isVisible)
|
|
53
|
+
return null;
|
|
54
|
+
const visible = wrappedLines.slice(scrollOffset, scrollOffset + viewportLines);
|
|
55
|
+
const hint = wrappedLines.length > viewportLines ? ['↑↓ scroll', 'Esc close'] : ['Esc close'];
|
|
56
|
+
return (_jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { color: "cyan", bold: true, wrap: "truncate-end", children: title }) }), _jsx(Box, { flexDirection: "column", height: viewportLines, marginTop: 1, children: Array.from({ length: viewportLines }, (_, rowIndex) => {
|
|
57
|
+
const line = visible[rowIndex];
|
|
58
|
+
return (_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { wrap: "truncate-end", children: line ?? ' ' }) }, `line-${rowIndex}`));
|
|
59
|
+
}) }), _jsx(Box, { paddingX: 0, paddingY: 0, marginTop: 1, children: _jsx(HintBar, { hints: hint }) })] }));
|
|
60
|
+
});
|
|
@@ -65,6 +65,6 @@ const LogLevelSelector = forwardRef(function LogLevelSelector({ isVisible, onSel
|
|
|
65
65
|
const handleSelect = (option) => {
|
|
66
66
|
onSelect(option.level);
|
|
67
67
|
};
|
|
68
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(BaseSelector, { ref: baseSelectorRef, items: levels, isVisible: isVisible, isLoading: false, selectedIndex: selectedIndex, onSelectIndex: setSelectedIndex, onSelect: handleSelect, onClose: onClose, formatItem: formatItem, title: "Select Log Level", borderColor: "yellowBright", emptyMessage: "No log levels available" })
|
|
68
|
+
return (_jsxs(Box, { flexDirection: "column", children: [logFilePath && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "gray", children: ["\uD83D\uDCC1 Log file: ", logFilePath] }) })), _jsx(BaseSelector, { ref: baseSelectorRef, items: levels, isVisible: isVisible, isLoading: false, selectedIndex: selectedIndex, onSelectIndex: setSelectedIndex, onSelect: handleSelect, onClose: onClose, formatItem: formatItem, title: "Select Log Level", borderColor: "yellowBright", emptyMessage: "No log levels available" })] }));
|
|
69
69
|
});
|
|
70
70
|
export default LogLevelSelector;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModelSelectorRefactored.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/ModelSelectorRefactored.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"ModelSelectorRefactored.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/ModelSelectorRefactored.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAE/D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO3D,OAAO,EAMH,KAAK,WAAW,EACnB,MAAM,yBAAyB,CAAC;AAKjC,KAAK,eAAe,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhF,UAAU,kBAAkB;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,CACX,QAAQ,EAAE,WAAW,EACrB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,EAChB,eAAe,CAAC,EAAE,eAAe,KAChC,IAAI,CAAC;IACV,iBAAiB,EAAE,CACf,QAAQ,EAAE,WAAW,EACrB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,MAAM,EAChB,eAAe,CAAC,EAAE,eAAe,KAChC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,iBAAiB,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IAChD,KAAK,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AA8FD;;GAEG;AACH,QAAA,MAAM,aAAa,oHAo8BjB,CAAC;AAEH,eAAe,aAAa,CAAC"}
|
|
@@ -7,13 +7,38 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
7
7
|
*/
|
|
8
8
|
import { useState, useEffect, forwardRef, useRef, useImperativeHandle, useMemo, useCallback, } from 'react';
|
|
9
9
|
import { Box, Text } from 'ink';
|
|
10
|
+
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
|
|
10
11
|
import { listOllamaModels, DEFAULT_OLLAMA_URL, getLocalModelById, isReasoningCapableModel, } from '@dexto/core';
|
|
11
12
|
import { loadCustomModels, deleteCustomModel, getAllInstalledModels, loadGlobalPreferences, isDextoAuthEnabled, } from '@dexto/agent-management';
|
|
12
13
|
import { getLLMProviderDisplayName } from '../../utils/llm-provider-display.js';
|
|
14
|
+
import { getMaxVisibleItemsForTerminalRows } from '../../utils/overlaySizing.js';
|
|
15
|
+
import { HintBar } from '../shared/HintBar.js';
|
|
13
16
|
function isAddCustomOption(item) {
|
|
14
17
|
return 'type' in item && item.type === 'add-custom';
|
|
15
18
|
}
|
|
16
|
-
|
|
19
|
+
function asModelOption(item) {
|
|
20
|
+
return item;
|
|
21
|
+
}
|
|
22
|
+
function getRowPrefix({ isSelected, isDefault, isCurrent, isCustom, }) {
|
|
23
|
+
return `${isSelected ? '›' : ' '} ${isDefault ? '✓' : ' '} ${isCurrent ? '●' : ' '} ${isCustom ? '★' : ' '}`;
|
|
24
|
+
}
|
|
25
|
+
function computeNextSelection(currentIndex, itemsLength, viewportItems) {
|
|
26
|
+
const nextIndex = currentIndex;
|
|
27
|
+
let nextOffset = 0;
|
|
28
|
+
const modelsLength = Math.max(0, itemsLength - 1);
|
|
29
|
+
if (nextIndex > 0) {
|
|
30
|
+
const modelIndex = nextIndex - 1;
|
|
31
|
+
if (modelIndex < nextOffset) {
|
|
32
|
+
nextOffset = modelIndex;
|
|
33
|
+
}
|
|
34
|
+
else if (modelIndex >= nextOffset + viewportItems) {
|
|
35
|
+
nextOffset = Math.max(0, modelIndex - viewportItems + 1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const maxOffset = Math.max(0, modelsLength - viewportItems);
|
|
39
|
+
nextOffset = Math.min(maxOffset, Math.max(0, nextOffset));
|
|
40
|
+
return { index: nextIndex, offset: nextOffset };
|
|
41
|
+
}
|
|
17
42
|
// Reasoning effort options - defined at module scope to avoid recreation on each render
|
|
18
43
|
const REASONING_EFFORT_OPTIONS = [
|
|
19
44
|
{
|
|
@@ -36,23 +61,33 @@ const REASONING_EFFORT_OPTIONS = [
|
|
|
36
61
|
* Model selector with search and custom model support
|
|
37
62
|
*/
|
|
38
63
|
const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectModel, onSetDefaultModel, onClose, onAddCustomModel, onEditCustomModel, agent, }, ref) {
|
|
64
|
+
const { rows: terminalRows } = useTerminalSize();
|
|
65
|
+
const maxVisibleItems = useMemo(() => {
|
|
66
|
+
return getMaxVisibleItemsForTerminalRows({
|
|
67
|
+
rows: terminalRows,
|
|
68
|
+
hardCap: 8,
|
|
69
|
+
reservedRows: 14,
|
|
70
|
+
});
|
|
71
|
+
}, [terminalRows]);
|
|
39
72
|
const [models, setModels] = useState([]);
|
|
40
73
|
const [customModels, setCustomModels] = useState([]);
|
|
41
74
|
const [isLoading, setIsLoading] = useState(false);
|
|
42
|
-
const [
|
|
75
|
+
const [selection, setSelection] = useState({ index: 0, offset: 0 });
|
|
43
76
|
const [searchQuery, setSearchQuery] = useState('');
|
|
44
|
-
const [scrollOffset, setScrollOffset] = useState(0);
|
|
45
77
|
const [customModelAction, setCustomModelAction] = useState(null);
|
|
46
78
|
const [pendingDeleteConfirm, setPendingDeleteConfirm] = useState(false);
|
|
47
|
-
const selectedIndexRef = useRef(
|
|
79
|
+
const selectedIndexRef = useRef(0);
|
|
48
80
|
const deleteTimeoutRef = useRef(null);
|
|
81
|
+
const maxVisibleItemsRef = useRef(maxVisibleItems);
|
|
49
82
|
// Reasoning effort sub-step state
|
|
50
83
|
const [pendingReasoningModel, setPendingReasoningModel] = useState(null);
|
|
51
84
|
const [reasoningEffortIndex, setReasoningEffortIndex] = useState(0); // Default to 'Auto' (index 0)
|
|
52
85
|
const [isSettingDefault, setIsSettingDefault] = useState(false); // Track if setting as default vs normal selection
|
|
53
86
|
const [refreshVersion, setRefreshVersion] = useState(0);
|
|
54
87
|
// Keep ref in sync
|
|
55
|
-
selectedIndexRef.current =
|
|
88
|
+
selectedIndexRef.current = selection.index;
|
|
89
|
+
maxVisibleItemsRef.current = maxVisibleItems;
|
|
90
|
+
const modelsViewportItems = Math.max(1, maxVisibleItems - 1);
|
|
56
91
|
// Clear delete confirmation timeout on unmount
|
|
57
92
|
useEffect(() => {
|
|
58
93
|
return () => {
|
|
@@ -67,9 +102,10 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
67
102
|
return;
|
|
68
103
|
let cancelled = false;
|
|
69
104
|
setIsLoading(true);
|
|
105
|
+
setModels([]);
|
|
106
|
+
setCustomModels([]);
|
|
70
107
|
setSearchQuery('');
|
|
71
|
-
|
|
72
|
-
setScrollOffset(0);
|
|
108
|
+
setSelection({ index: 0, offset: 0 });
|
|
73
109
|
setCustomModelAction(null);
|
|
74
110
|
setPendingDeleteConfirm(false);
|
|
75
111
|
setPendingReasoningModel(null);
|
|
@@ -237,7 +273,13 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
237
273
|
// Set initial selection to current model (offset by 1 for "Add custom" option)
|
|
238
274
|
const currentIndex = modelList.findIndex((m) => m.isCurrent);
|
|
239
275
|
if (currentIndex >= 0) {
|
|
240
|
-
|
|
276
|
+
const nextIndex = currentIndex + 1; // +1 for "Add custom" at top
|
|
277
|
+
const nextMaxVisibleItems = maxVisibleItemsRef.current;
|
|
278
|
+
const nextModelsViewportItems = Math.max(1, nextMaxVisibleItems - 1);
|
|
279
|
+
const maxOffset = Math.max(0, modelList.length - nextModelsViewportItems);
|
|
280
|
+
const nextOffset = Math.min(maxOffset, Math.max(0, currentIndex - nextModelsViewportItems + 1));
|
|
281
|
+
selectedIndexRef.current = nextIndex;
|
|
282
|
+
setSelection({ index: nextIndex, offset: nextOffset });
|
|
241
283
|
}
|
|
242
284
|
}
|
|
243
285
|
}
|
|
@@ -260,31 +302,41 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
260
302
|
if (!searchQuery.trim()) {
|
|
261
303
|
return [addCustomOption, ...models];
|
|
262
304
|
}
|
|
263
|
-
const query = searchQuery.toLowerCase();
|
|
305
|
+
const query = searchQuery.toLowerCase().replace(/[\s-]+/g, '');
|
|
264
306
|
const filtered = models.filter((model) => {
|
|
265
|
-
const name = model.name.toLowerCase();
|
|
266
|
-
const displayName = (model.displayName || '').toLowerCase();
|
|
267
|
-
const provider = model.provider.toLowerCase();
|
|
307
|
+
const name = model.name.toLowerCase().replace(/[\s-]+/g, '');
|
|
308
|
+
const displayName = (model.displayName || '').toLowerCase().replace(/[\s-]+/g, '');
|
|
309
|
+
const provider = model.provider.toLowerCase().replace(/[\s-]+/g, '');
|
|
268
310
|
return name.includes(query) || displayName.includes(query) || provider.includes(query);
|
|
269
311
|
});
|
|
270
312
|
// Always show "Add custom" when searching (user might want to add what they're searching for)
|
|
271
313
|
return [addCustomOption, ...filtered];
|
|
272
314
|
}, [models, searchQuery]);
|
|
273
|
-
//
|
|
274
|
-
useEffect(() => {
|
|
275
|
-
if (selectedIndex >= filteredItems.length) {
|
|
276
|
-
setSelectedIndex(Math.max(0, filteredItems.length - 1));
|
|
277
|
-
}
|
|
278
|
-
}, [filteredItems.length, selectedIndex]);
|
|
279
|
-
// Calculate scroll offset
|
|
315
|
+
// Keep selection valid and visible when filtering or terminal height changes.
|
|
280
316
|
useEffect(() => {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
317
|
+
setSelection((prev) => {
|
|
318
|
+
const maxIndex = Math.max(0, filteredItems.length - 1);
|
|
319
|
+
const nextIndex = Math.min(prev.index, maxIndex);
|
|
320
|
+
let nextOffset = prev.offset;
|
|
321
|
+
const nextModelsLength = Math.max(0, filteredItems.length - 1);
|
|
322
|
+
if (nextIndex > 0) {
|
|
323
|
+
const modelIndex = nextIndex - 1;
|
|
324
|
+
if (modelIndex < nextOffset) {
|
|
325
|
+
nextOffset = modelIndex;
|
|
326
|
+
}
|
|
327
|
+
else if (modelIndex >= nextOffset + modelsViewportItems) {
|
|
328
|
+
nextOffset = Math.max(0, modelIndex - modelsViewportItems + 1);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const maxOffset = Math.max(0, nextModelsLength - modelsViewportItems);
|
|
332
|
+
nextOffset = Math.min(maxOffset, Math.max(0, nextOffset));
|
|
333
|
+
if (nextIndex === prev.index && nextOffset === prev.offset) {
|
|
334
|
+
return prev;
|
|
335
|
+
}
|
|
336
|
+
selectedIndexRef.current = nextIndex;
|
|
337
|
+
return { index: nextIndex, offset: nextOffset };
|
|
338
|
+
});
|
|
339
|
+
}, [filteredItems.length, modelsViewportItems]);
|
|
288
340
|
// Handle delete custom model
|
|
289
341
|
const handleDeleteCustomModel = useCallback(async (model) => {
|
|
290
342
|
if (!model.isCustom)
|
|
@@ -315,6 +367,13 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
315
367
|
handleInput: (input, key) => {
|
|
316
368
|
if (!isVisible)
|
|
317
369
|
return false;
|
|
370
|
+
// While loading, allow closing but ignore all other input.
|
|
371
|
+
if (isLoading) {
|
|
372
|
+
if (key.escape) {
|
|
373
|
+
onClose();
|
|
374
|
+
}
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
318
377
|
// Handle reasoning effort sub-step
|
|
319
378
|
if (pendingReasoningModel) {
|
|
320
379
|
if (key.escape) {
|
|
@@ -391,41 +450,10 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
391
450
|
setPendingDeleteConfirm(false);
|
|
392
451
|
return true;
|
|
393
452
|
}
|
|
394
|
-
const actionItem = currentItem;
|
|
395
|
-
// Check if reasoning-capable, show reasoning effort selection
|
|
396
|
-
if (isReasoningCapableModel(actionItem.name)) {
|
|
397
|
-
setPendingReasoningModel(actionItem);
|
|
398
|
-
setIsSettingDefault(true);
|
|
399
|
-
setReasoningEffortIndex(0); // Default to 'Auto'
|
|
400
|
-
return true;
|
|
401
|
-
}
|
|
402
|
-
clearActionState();
|
|
403
|
-
void (async () => {
|
|
404
|
-
await onSetDefaultModel(actionItem.provider, actionItem.name, actionItem.displayName, actionItem.baseURL, actionItem.reasoningEffort);
|
|
405
|
-
setRefreshVersion((prev) => prev + 1);
|
|
406
|
-
onClose(); // Close overlay after setting default
|
|
407
|
-
})();
|
|
408
453
|
return true;
|
|
409
454
|
}
|
|
410
455
|
if (customModelAction === 'delete') {
|
|
411
|
-
|
|
412
|
-
if (deleteTimeoutRef.current) {
|
|
413
|
-
clearTimeout(deleteTimeoutRef.current);
|
|
414
|
-
deleteTimeoutRef.current = null;
|
|
415
|
-
}
|
|
416
|
-
clearActionState();
|
|
417
|
-
void handleDeleteCustomModel(currentItem);
|
|
418
|
-
}
|
|
419
|
-
else {
|
|
420
|
-
setPendingDeleteConfirm(true);
|
|
421
|
-
if (deleteTimeoutRef.current) {
|
|
422
|
-
clearTimeout(deleteTimeoutRef.current);
|
|
423
|
-
}
|
|
424
|
-
deleteTimeoutRef.current = setTimeout(() => {
|
|
425
|
-
setPendingDeleteConfirm(false);
|
|
426
|
-
deleteTimeoutRef.current = null;
|
|
427
|
-
}, 3000);
|
|
428
|
-
}
|
|
456
|
+
// Use Enter for delete confirmation/execution to avoid accidental deletes.
|
|
429
457
|
return true;
|
|
430
458
|
}
|
|
431
459
|
}
|
|
@@ -469,8 +497,8 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
469
497
|
// Regular character - add to search
|
|
470
498
|
if (input.length === 1 && input.charCodeAt(0) >= 32) {
|
|
471
499
|
setSearchQuery((prev) => prev + input);
|
|
472
|
-
|
|
473
|
-
|
|
500
|
+
selectedIndexRef.current = 0;
|
|
501
|
+
setSelection({ index: 0, offset: 0 });
|
|
474
502
|
return true;
|
|
475
503
|
}
|
|
476
504
|
}
|
|
@@ -487,8 +515,23 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
487
515
|
clearActionState();
|
|
488
516
|
}
|
|
489
517
|
const nextIndex = (selectedIndexRef.current - 1 + itemsLength) % itemsLength;
|
|
490
|
-
setSelectedIndex(nextIndex);
|
|
491
518
|
selectedIndexRef.current = nextIndex;
|
|
519
|
+
setSelection((prev) => {
|
|
520
|
+
let nextOffset = prev.offset;
|
|
521
|
+
const nextModelsLength = Math.max(0, itemsLength - 1);
|
|
522
|
+
if (nextIndex > 0) {
|
|
523
|
+
const modelIndex = nextIndex - 1;
|
|
524
|
+
if (modelIndex < prev.offset) {
|
|
525
|
+
nextOffset = modelIndex;
|
|
526
|
+
}
|
|
527
|
+
else if (modelIndex >= prev.offset + modelsViewportItems) {
|
|
528
|
+
nextOffset = Math.max(0, modelIndex - modelsViewportItems + 1);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
const maxOffset = Math.max(0, nextModelsLength - modelsViewportItems);
|
|
532
|
+
nextOffset = Math.min(maxOffset, Math.max(0, nextOffset));
|
|
533
|
+
return { index: nextIndex, offset: nextOffset };
|
|
534
|
+
});
|
|
492
535
|
return true;
|
|
493
536
|
}
|
|
494
537
|
if (key.downArrow) {
|
|
@@ -497,8 +540,23 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
497
540
|
clearActionState();
|
|
498
541
|
}
|
|
499
542
|
const nextIndex = (selectedIndexRef.current + 1) % itemsLength;
|
|
500
|
-
setSelectedIndex(nextIndex);
|
|
501
543
|
selectedIndexRef.current = nextIndex;
|
|
544
|
+
setSelection((prev) => {
|
|
545
|
+
let nextOffset = prev.offset;
|
|
546
|
+
const nextModelsLength = Math.max(0, itemsLength - 1);
|
|
547
|
+
if (nextIndex > 0) {
|
|
548
|
+
const modelIndex = nextIndex - 1;
|
|
549
|
+
if (modelIndex < prev.offset) {
|
|
550
|
+
nextOffset = modelIndex;
|
|
551
|
+
}
|
|
552
|
+
else if (modelIndex >= prev.offset + modelsViewportItems) {
|
|
553
|
+
nextOffset = Math.max(0, modelIndex - modelsViewportItems + 1);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
const maxOffset = Math.max(0, nextModelsLength - modelsViewportItems);
|
|
557
|
+
nextOffset = Math.min(maxOffset, Math.max(0, nextOffset));
|
|
558
|
+
return { index: nextIndex, offset: nextOffset };
|
|
559
|
+
});
|
|
502
560
|
return true;
|
|
503
561
|
}
|
|
504
562
|
if (key.return && itemsLength > 0) {
|
|
@@ -568,7 +626,10 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
568
626
|
},
|
|
569
627
|
}), [
|
|
570
628
|
isVisible,
|
|
629
|
+
isLoading,
|
|
571
630
|
filteredItems,
|
|
631
|
+
maxVisibleItems,
|
|
632
|
+
modelsViewportItems,
|
|
572
633
|
onClose,
|
|
573
634
|
onSelectModel,
|
|
574
635
|
onSetDefaultModel,
|
|
@@ -584,47 +645,99 @@ const ModelSelector = forwardRef(function ModelSelector({ isVisible, onSelectMod
|
|
|
584
645
|
]);
|
|
585
646
|
if (!isVisible)
|
|
586
647
|
return null;
|
|
587
|
-
if (isLoading) {
|
|
588
|
-
return (_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { color: "gray", children: "Loading models..." }) }));
|
|
589
|
-
}
|
|
590
648
|
// Reasoning effort sub-step UI
|
|
591
649
|
if (pendingReasoningModel) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
650
|
+
const reasoningVisibleItems = Math.min(maxVisibleItems, REASONING_EFFORT_OPTIONS.length);
|
|
651
|
+
const reasoningOffset = Math.min(Math.max(0, reasoningEffortIndex - reasoningVisibleItems + 1), Math.max(0, REASONING_EFFORT_OPTIONS.length - reasoningVisibleItems));
|
|
652
|
+
const visibleReasoningOptions = REASONING_EFFORT_OPTIONS.slice(reasoningOffset, reasoningOffset + reasoningVisibleItems);
|
|
653
|
+
const selectedReasoningOption = REASONING_EFFORT_OPTIONS[reasoningEffortIndex];
|
|
654
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsxs(Text, { color: "cyan", bold: true, children: ["Reasoning Effort", isSettingDefault ? _jsx(Text, { color: "gray", children: " (default)" }) : null] }) }), _jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { color: "gray", wrap: "truncate-end", children: pendingReasoningModel.displayName || pendingReasoningModel.name }) }), _jsx(Box, { flexDirection: "column", height: maxVisibleItems, marginTop: 1, children: Array.from({ length: maxVisibleItems }, (_, rowIndex) => {
|
|
655
|
+
const option = visibleReasoningOptions[rowIndex];
|
|
656
|
+
if (!option) {
|
|
657
|
+
return (_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { children: " " }) }, `reasoning-empty-${rowIndex}`));
|
|
658
|
+
}
|
|
659
|
+
const actualIndex = reasoningOffset + rowIndex;
|
|
660
|
+
const isSelected = actualIndex === reasoningEffortIndex;
|
|
661
|
+
return (_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsxs(Text, { color: isSelected ? 'cyan' : 'gray', bold: isSelected, wrap: "truncate-end", children: [isSelected ? '›' : ' ', " ", option.label] }) }, option.value));
|
|
662
|
+
}) }), _jsx(Box, { paddingX: 0, paddingY: 0, marginTop: 1, children: _jsx(Text, { color: "gray", wrap: "truncate-end", children: selectedReasoningOption?.description ?? '' }) }), _jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(HintBar, { hints: ['↑↓ navigate', 'Enter select', 'Esc back'] }) })] }));
|
|
596
663
|
}
|
|
597
|
-
const
|
|
598
|
-
const
|
|
599
|
-
const
|
|
664
|
+
const selectedIndex = selection.index;
|
|
665
|
+
const scrollOffset = selection.offset;
|
|
666
|
+
const modelsOnly = filteredItems.slice(1);
|
|
667
|
+
const visibleModels = modelsOnly.slice(scrollOffset, scrollOffset + modelsViewportItems);
|
|
600
668
|
const selectedItem = filteredItems[selectedIndex];
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
669
|
+
const hasActionableItems = selectedItem && !isAddCustomOption(selectedItem);
|
|
670
|
+
let detailLine = '';
|
|
671
|
+
if (isLoading) {
|
|
672
|
+
detailLine = 'Loading models…';
|
|
673
|
+
}
|
|
674
|
+
else if (customModelAction === 'delete' && pendingDeleteConfirm) {
|
|
675
|
+
detailLine = 'Confirm delete: press Enter again';
|
|
676
|
+
}
|
|
677
|
+
else if (customModelAction) {
|
|
678
|
+
const label = customModelAction === 'edit'
|
|
679
|
+
? 'Edit'
|
|
680
|
+
: customModelAction === 'default'
|
|
681
|
+
? 'Set as default'
|
|
682
|
+
: 'Delete';
|
|
683
|
+
detailLine = `Action: ${label}`;
|
|
684
|
+
}
|
|
685
|
+
else if (searchQuery.trim() && filteredItems.length <= 1) {
|
|
686
|
+
detailLine = 'No models match your search';
|
|
687
|
+
}
|
|
688
|
+
else if (!selectedItem) {
|
|
689
|
+
detailLine = '';
|
|
690
|
+
}
|
|
691
|
+
else if (isAddCustomOption(selectedItem)) {
|
|
692
|
+
detailLine = 'Enter to add a custom model';
|
|
693
|
+
}
|
|
694
|
+
else {
|
|
695
|
+
const provider = getLLMProviderDisplayName(selectedItem.provider);
|
|
696
|
+
const name = selectedItem.displayName || selectedItem.name;
|
|
697
|
+
const flags = [];
|
|
698
|
+
if (selectedItem.isDefault)
|
|
699
|
+
flags.push('default');
|
|
700
|
+
if (selectedItem.isCurrent)
|
|
701
|
+
flags.push('current');
|
|
702
|
+
detailLine =
|
|
703
|
+
flags.length > 0
|
|
704
|
+
? `${name} (${provider}) • ${flags.join(', ')}`
|
|
705
|
+
: `${name} (${provider})`;
|
|
706
|
+
}
|
|
707
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { color: "cyan", bold: true, children: "Models" }) }), _jsxs(Box, { paddingX: 0, paddingY: 0, marginTop: 1, children: [_jsx(Text, { color: "gray", children: "Search: " }), _jsx(Text, { color: searchQuery ? 'white' : 'gray', wrap: "truncate-end", children: searchQuery || 'Type to filter models…' })] }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsxs(Text, { color: selectedIndex === 0 ? 'green' : 'gray', bold: selectedIndex === 0, wrap: "truncate-end", children: [getRowPrefix({
|
|
708
|
+
isSelected: selectedIndex === 0,
|
|
709
|
+
isDefault: false,
|
|
710
|
+
isCurrent: false,
|
|
711
|
+
isCustom: false,
|
|
712
|
+
}), ' ', "Add custom model\u2026"] }) }), _jsx(Box, { flexDirection: "column", height: modelsViewportItems, children: isLoading || modelsOnly.length === 0
|
|
713
|
+
? Array.from({ length: modelsViewportItems }, (_, index) => (_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { children: " " }) }, `model-empty-${index}`)))
|
|
714
|
+
: Array.from({ length: modelsViewportItems }, (_, rowIndex) => {
|
|
715
|
+
const item = visibleModels[rowIndex];
|
|
716
|
+
if (!item) {
|
|
717
|
+
return (_jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(Text, { children: " " }) }, `model-empty-${rowIndex}`));
|
|
718
|
+
}
|
|
719
|
+
const actualIndex = 1 + scrollOffset + rowIndex;
|
|
720
|
+
const isSelected = actualIndex === selectedIndex;
|
|
721
|
+
const providerDisplay = getLLMProviderDisplayName(item.provider);
|
|
722
|
+
const name = item.displayName || item.name;
|
|
723
|
+
const prefix = getRowPrefix({
|
|
724
|
+
isSelected,
|
|
725
|
+
isDefault: item.isDefault,
|
|
726
|
+
isCurrent: item.isCurrent,
|
|
727
|
+
isCustom: item.isCustom,
|
|
728
|
+
});
|
|
729
|
+
return (_jsxs(Box, { flexDirection: "row", paddingX: 0, paddingY: 0, children: [_jsx(Box, { flexGrow: 1, children: _jsxs(Text, { color: isSelected ? 'cyan' : 'gray', bold: isSelected, wrap: "truncate-end", children: [prefix, " ", name, " (", providerDisplay, ")"] }) }), isSelected && (_jsxs(Box, { flexDirection: "row", marginLeft: 1, children: [item.isCustom && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: customModelAction === 'edit'
|
|
730
|
+
? 'green'
|
|
731
|
+
: 'gray', bold: customModelAction === 'edit', inverse: customModelAction === 'edit', children: [' ', "Edit", ' '] }), _jsx(Text, { children: " " })] })), _jsxs(Text, { color: customModelAction === 'default'
|
|
732
|
+
? 'cyan'
|
|
733
|
+
: 'gray', bold: customModelAction === 'default', inverse: customModelAction === 'default', children: [' ', "Set as Default", ' '] }), item.isCustom && (_jsxs(_Fragment, { children: [_jsx(Text, { children: " " }), _jsxs(Text, { color: customModelAction === 'delete'
|
|
734
|
+
? 'red'
|
|
735
|
+
: 'gray', bold: customModelAction === 'delete', inverse: customModelAction === 'delete', children: [' ', "Delete", ' '] })] }))] }))] }, `${item.provider}-${item.name}-${item.isCustom ? 'custom' : 'registry'}`));
|
|
736
|
+
}) })] }), _jsx(Box, { paddingX: 0, paddingY: 0, marginTop: 1, children: _jsx(Text, { color: "gray", wrap: "truncate-end", children: detailLine }) }), _jsx(Box, { paddingX: 0, paddingY: 0, children: _jsx(HintBar, { hints: [
|
|
737
|
+
'↑↓ navigate',
|
|
738
|
+
'Enter select',
|
|
739
|
+
'Esc close',
|
|
740
|
+
hasActionableItems ? '←→ actions' : '',
|
|
741
|
+
] }) })] }));
|
|
629
742
|
});
|
|
630
743
|
export default ModelSelector;
|