dexto 1.5.5 → 1.5.7
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/README.md +13 -0
- package/dist/agents/agent-template.yml +1 -1
- package/dist/agents/coding-agent/coding-agent.yml +17 -2
- package/dist/agents/coding-agent/skills/code-review.md +46 -0
- package/dist/agents/explore-agent/explore-agent.yml +2 -0
- package/dist/agents/podcast-agent/podcast-agent.yml +1 -1
- package/dist/analytics/events.d.ts +1 -1
- package/dist/analytics/events.d.ts.map +1 -1
- package/dist/api/server-hono.d.ts.map +1 -1
- package/dist/api/server-hono.js +55 -10
- package/dist/cli/assets/dexto-logo.svg +31 -0
- package/dist/cli/auth/api-client.d.ts +49 -0
- package/dist/cli/auth/api-client.d.ts.map +1 -0
- package/dist/cli/auth/api-client.js +127 -0
- package/dist/cli/auth/constants.d.ts +23 -0
- package/dist/cli/auth/constants.d.ts.map +1 -0
- package/dist/cli/auth/constants.js +24 -0
- package/dist/cli/auth/index.d.ts +5 -0
- package/dist/cli/auth/index.d.ts.map +1 -0
- package/dist/cli/auth/index.js +6 -0
- package/dist/cli/auth/oauth.d.ts +26 -0
- package/dist/cli/auth/oauth.d.ts.map +1 -0
- package/dist/cli/auth/oauth.js +327 -0
- package/dist/cli/auth/service.d.ts +20 -0
- package/dist/cli/auth/service.d.ts.map +1 -0
- package/dist/cli/auth/service.js +147 -0
- package/dist/cli/commands/auth/index.d.ts +4 -0
- package/dist/cli/commands/auth/index.d.ts.map +1 -0
- package/dist/cli/commands/auth/index.js +4 -0
- package/dist/cli/commands/auth/login.d.ts +9 -0
- package/dist/cli/commands/auth/login.d.ts.map +1 -0
- package/dist/cli/commands/auth/login.js +255 -0
- package/dist/cli/commands/auth/logout.d.ts +5 -0
- package/dist/cli/commands/auth/logout.d.ts.map +1 -0
- package/dist/cli/commands/auth/logout.js +51 -0
- package/dist/cli/commands/auth/status.d.ts +2 -0
- package/dist/cli/commands/auth/status.d.ts.map +1 -0
- package/dist/cli/commands/auth/status.js +22 -0
- package/dist/cli/commands/billing/index.d.ts +2 -0
- package/dist/cli/commands/billing/index.d.ts.map +1 -0
- package/dist/cli/commands/billing/index.js +2 -0
- package/dist/cli/commands/billing/status.d.ts +6 -0
- package/dist/cli/commands/billing/status.d.ts.map +1 -0
- package/dist/cli/commands/billing/status.js +60 -0
- package/dist/cli/commands/index.d.ts +4 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +9 -0
- package/dist/cli/commands/interactive-commands/auth/index.d.ts +12 -0
- package/dist/cli/commands/interactive-commands/auth/index.d.ts.map +1 -0
- package/dist/cli/commands/interactive-commands/auth/index.js +20 -0
- package/dist/cli/commands/interactive-commands/command-parser.d.ts +5 -0
- package/dist/cli/commands/interactive-commands/command-parser.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/command-parser.js +6 -0
- package/dist/cli/commands/interactive-commands/commands.d.ts +1 -0
- package/dist/cli/commands/interactive-commands/commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/commands.js +10 -0
- package/dist/cli/commands/interactive-commands/export/index.d.ts +13 -0
- package/dist/cli/commands/interactive-commands/export/index.d.ts.map +1 -0
- package/dist/cli/commands/interactive-commands/export/index.js +21 -0
- package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/general-commands.js +1 -0
- package/dist/cli/commands/interactive-commands/mcp/index.d.ts +2 -2
- package/dist/cli/commands/interactive-commands/mcp/index.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/mcp/index.js +4 -7
- package/dist/cli/commands/interactive-commands/model/index.d.ts +2 -2
- package/dist/cli/commands/interactive-commands/model/index.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/model/index.js +4 -7
- package/dist/cli/commands/interactive-commands/plugin/index.d.ts +13 -0
- package/dist/cli/commands/interactive-commands/plugin/index.d.ts.map +1 -0
- package/dist/cli/commands/interactive-commands/plugin/index.js +18 -0
- package/dist/cli/commands/interactive-commands/prompt-commands.d.ts +3 -1
- package/dist/cli/commands/interactive-commands/prompt-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/prompt-commands.js +72 -36
- package/dist/cli/commands/interactive-commands/system/system-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/system/system-commands.js +2 -3
- package/dist/cli/commands/plugin.d.ts +161 -0
- package/dist/cli/commands/plugin.d.ts.map +1 -0
- package/dist/cli/commands/plugin.js +376 -0
- package/dist/cli/commands/setup.d.ts +9 -9
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +325 -37
- package/dist/cli/commands/sync-agents.d.ts +44 -0
- package/dist/cli/commands/sync-agents.d.ts.map +1 -0
- package/dist/cli/commands/sync-agents.js +483 -0
- package/dist/cli/ink-cli/InkCLIRefactored.d.ts +14 -1
- package/dist/cli/ink-cli/InkCLIRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/InkCLIRefactored.js +8 -2
- package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts +1 -1
- package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ApprovalPrompt.js +80 -12
- package/dist/cli/ink-cli/components/Footer.d.ts +2 -1
- package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/Footer.js +6 -2
- package/dist/cli/ink-cli/components/SlashCommandAutocomplete.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/SlashCommandAutocomplete.js +15 -7
- package/dist/cli/ink-cli/components/StatusBar.d.ts +9 -1
- package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/StatusBar.js +17 -5
- package/dist/cli/ink-cli/components/TodoPanel.d.ts +11 -8
- package/dist/cli/ink-cli/components/TodoPanel.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/TodoPanel.js +38 -36
- 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 +14 -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 +16 -4
- package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.js +4 -1
- package/dist/cli/ink-cli/components/overlays/ExportWizard.d.ts +22 -0
- package/dist/cli/ink-cli/components/overlays/ExportWizard.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/ExportWizard.js +308 -0
- package/dist/cli/ink-cli/components/overlays/LogLevelSelector.d.ts +1 -0
- package/dist/cli/ink-cli/components/overlays/LogLevelSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +31 -20
- package/dist/cli/ink-cli/components/overlays/MarketplaceAddPrompt.d.ts +20 -0
- package/dist/cli/ink-cli/components/overlays/MarketplaceAddPrompt.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/MarketplaceAddPrompt.js +81 -0
- package/dist/cli/ink-cli/components/overlays/MarketplaceBrowser.d.ts +31 -0
- package/dist/cli/ink-cli/components/overlays/MarketplaceBrowser.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/MarketplaceBrowser.js +297 -0
- package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.js +7 -1
- package/dist/cli/ink-cli/components/overlays/McpServerActions.d.ts +1 -1
- package/dist/cli/ink-cli/components/overlays/McpServerActions.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/McpServerActions.js +9 -0
- package/dist/cli/ink-cli/components/overlays/McpServerList.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/McpServerList.js +9 -2
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +15 -2
- package/dist/cli/ink-cli/components/overlays/PluginActions.d.ts +27 -0
- package/dist/cli/ink-cli/components/overlays/PluginActions.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/PluginActions.js +66 -0
- package/dist/cli/ink-cli/components/overlays/PluginList.d.ts +21 -0
- package/dist/cli/ink-cli/components/overlays/PluginList.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/PluginList.js +70 -0
- package/dist/cli/ink-cli/components/overlays/PluginManager.d.ts +21 -0
- package/dist/cli/ink-cli/components/overlays/PluginManager.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/PluginManager.js +63 -0
- package/dist/cli/ink-cli/components/overlays/PromptList.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/PromptList.js +4 -1
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts +2 -1
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.js +61 -2
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts +4 -2
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.js +4 -4
- package/dist/cli/ink-cli/constants/tips.js +2 -2
- package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/InputContainer.js +31 -3
- package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/OverlayContainer.js +260 -11
- package/dist/cli/ink-cli/hooks/index.d.ts +1 -0
- package/dist/cli/ink-cli/hooks/index.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/index.js +1 -0
- package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useCLIState.js +3 -0
- package/dist/cli/ink-cli/hooks/useGitBranch.d.ts +13 -0
- package/dist/cli/ink-cli/hooks/useGitBranch.d.ts.map +1 -0
- package/dist/cli/ink-cli/hooks/useGitBranch.js +35 -0
- package/dist/cli/ink-cli/hooks/useInputOrchestrator.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useInputOrchestrator.js +50 -6
- package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
- package/dist/cli/ink-cli/services/processStream.js +42 -10
- package/dist/cli/ink-cli/state/initialState.d.ts.map +1 -1
- package/dist/cli/ink-cli/state/initialState.js +3 -0
- package/dist/cli/ink-cli/state/types.d.ts +16 -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 +2 -0
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts +14 -1
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.js +68 -8
- package/dist/cli/ink-cli/utils/toolUtils.d.ts +11 -0
- package/dist/cli/ink-cli/utils/toolUtils.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/toolUtils.js +17 -0
- package/dist/cli/mcp/index.d.ts +8 -0
- package/dist/cli/mcp/index.d.ts.map +1 -0
- package/dist/cli/mcp/index.js +7 -0
- package/dist/cli/mcp/oauth-factory.d.ts +6 -0
- package/dist/cli/mcp/oauth-factory.d.ts.map +1 -0
- package/dist/cli/mcp/oauth-factory.js +25 -0
- package/dist/cli/mcp/oauth-provider.d.ts +10 -0
- package/dist/cli/mcp/oauth-provider.d.ts.map +1 -0
- package/dist/cli/mcp/oauth-provider.js +77 -0
- package/dist/cli/mcp/oauth-redirect.d.ts +3 -0
- package/dist/cli/mcp/oauth-redirect.d.ts.map +1 -0
- package/dist/cli/mcp/oauth-redirect.js +4 -0
- package/dist/cli/mcp/oauth-server.d.ts +2 -0
- package/dist/cli/mcp/oauth-server.d.ts.map +1 -0
- package/dist/cli/mcp/oauth-server.js +70 -0
- package/dist/cli/mcp/oauth-store.d.ts +10 -0
- package/dist/cli/mcp/oauth-store.d.ts.map +1 -0
- package/dist/cli/mcp/oauth-store.js +27 -0
- package/dist/cli/mcp/oauth-ui.d.ts +2 -0
- package/dist/cli/mcp/oauth-ui.d.ts.map +1 -0
- package/dist/cli/mcp/oauth-ui.js +12 -0
- package/dist/cli/mcp/oauth-utils.d.ts +2 -0
- package/dist/cli/mcp/oauth-utils.d.ts.map +1 -0
- package/dist/cli/mcp/oauth-utils.js +17 -0
- package/dist/cli/utils/api-key-setup.d.ts.map +1 -1
- package/dist/cli/utils/api-key-setup.js +13 -90
- package/dist/cli/utils/api-key-verification.d.ts.map +1 -1
- package/dist/cli/utils/api-key-verification.js +36 -0
- package/dist/cli/utils/config-validation.d.ts +3 -1
- package/dist/cli/utils/config-validation.d.ts.map +1 -1
- package/dist/cli/utils/config-validation.js +42 -19
- package/dist/cli/utils/dexto-auth-check.d.ts +53 -0
- package/dist/cli/utils/dexto-auth-check.d.ts.map +1 -0
- package/dist/cli/utils/dexto-auth-check.js +104 -0
- package/dist/cli/utils/dexto-setup.d.ts +8 -0
- package/dist/cli/utils/dexto-setup.d.ts.map +1 -0
- package/dist/cli/utils/dexto-setup.js +17 -0
- package/dist/cli/utils/options.d.ts.map +1 -1
- package/dist/cli/utils/options.js +5 -1
- package/dist/cli/utils/provider-setup.d.ts +4 -0
- package/dist/cli/utils/provider-setup.d.ts.map +1 -1
- package/dist/cli/utils/provider-setup.js +20 -0
- package/dist/cli/utils/version-check.d.ts +45 -0
- package/dist/cli/utils/version-check.d.ts.map +1 -0
- package/dist/cli/utils/version-check.js +195 -0
- package/dist/config/cli-overrides.d.ts +17 -8
- package/dist/config/cli-overrides.d.ts.map +1 -1
- package/dist/config/cli-overrides.js +36 -22
- package/dist/config/effective-llm.d.ts +123 -0
- package/dist/config/effective-llm.d.ts.map +1 -0
- package/dist/config/effective-llm.js +171 -0
- package/dist/index.js +451 -126
- package/dist/webui/assets/index-C9JXwpvo.css +1 -0
- package/dist/webui/assets/{index-DVQWNLpT.js → index-Dl3mj53P.js} +217 -217
- package/dist/webui/index.html +2 -2
- package/package.json +9 -8
- package/dist/webui/assets/index-BglIVTSG.css +0 -1
|
@@ -15,6 +15,7 @@ import { Box, Text } from 'ink';
|
|
|
15
15
|
// Hooks
|
|
16
16
|
import { useTerminalSize } from '../../hooks/index.js';
|
|
17
17
|
import { useCLIState } from '../../hooks/useCLIState.js';
|
|
18
|
+
import { useGitBranch } from '../../hooks/useGitBranch.js';
|
|
18
19
|
import { useScrollable } from '../../contexts/index.js';
|
|
19
20
|
// Components
|
|
20
21
|
import { Header } from '../chat/Header.js';
|
|
@@ -48,6 +49,8 @@ export function AlternateBufferCLI({ agent, initialSessionId, startupInfo, onSel
|
|
|
48
49
|
startupInfo,
|
|
49
50
|
onKeyboardScroll: handleKeyboardScroll,
|
|
50
51
|
});
|
|
52
|
+
// Get current git branch name
|
|
53
|
+
const branchName = useGitBranch();
|
|
51
54
|
// Register the VirtualizedList as scrollable so ScrollProvider can handle mouse scroll
|
|
52
55
|
const getScrollState = useCallback(() => {
|
|
53
56
|
const scrollState = listRef.current?.getScrollState();
|
|
@@ -99,19 +102,28 @@ export function AlternateBufferCLI({ agent, initialSessionId, startupInfo, onSel
|
|
|
99
102
|
// Build list data: header as first item, then finalized + pending + dequeued buffer
|
|
100
103
|
// In alternate buffer mode, everything is re-rendered anyway, so we combine all
|
|
101
104
|
// Order: finalized messages → pending/streaming → dequeued user messages (guarantees order)
|
|
105
|
+
// IMPORTANT: Deduplicate by ID to prevent race condition where a message appears in both
|
|
106
|
+
// finalized (messages) and pending during the brief window between setState calls
|
|
102
107
|
const listData = useMemo(() => {
|
|
103
108
|
const items = [{ type: 'header' }];
|
|
109
|
+
const seenIds = new Set();
|
|
104
110
|
for (const msg of visibleMessages) {
|
|
105
111
|
items.push({ type: 'message', message: msg });
|
|
112
|
+
seenIds.add(msg.id);
|
|
106
113
|
}
|
|
107
|
-
// Add pending/streaming messages
|
|
114
|
+
// Add pending/streaming messages (skip if already in finalized - race condition guard)
|
|
108
115
|
for (const msg of pendingMessages) {
|
|
109
|
-
|
|
116
|
+
if (!seenIds.has(msg.id)) {
|
|
117
|
+
items.push({ type: 'message', message: msg });
|
|
118
|
+
seenIds.add(msg.id);
|
|
119
|
+
}
|
|
110
120
|
}
|
|
111
121
|
// Add dequeued buffer (user messages waiting to be flushed to finalized)
|
|
112
122
|
// These render AFTER pending to guarantee correct visual order
|
|
113
123
|
for (const msg of dequeuedBuffer) {
|
|
114
|
-
|
|
124
|
+
if (!seenIds.has(msg.id)) {
|
|
125
|
+
items.push({ type: 'message', message: msg });
|
|
126
|
+
}
|
|
115
127
|
}
|
|
116
128
|
return items;
|
|
117
129
|
}, [visibleMessages, pendingMessages, dequeuedBuffer]);
|
|
@@ -163,5 +175,5 @@ export function AlternateBufferCLI({ agent, initialSessionId, startupInfo, onSel
|
|
|
163
175
|
return 'header';
|
|
164
176
|
return item.message.id;
|
|
165
177
|
}, []);
|
|
166
|
-
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: [_jsx(
|
|
178
|
+
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: [_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 }), _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, 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 }), _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 }), 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)" })] })), _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('!') }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
|
|
167
179
|
}
|
|
@@ -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;AAoBxD,UAAU,cAAc;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,SAAS,CAAC,EACtB,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,YAAmB,GACtB,EAAE,cAAc,2CA2OhB"}
|
|
@@ -21,6 +21,7 @@ const CLEAR_TERMINAL = '\x1B[2J\x1B[3J\x1B[H';
|
|
|
21
21
|
// Hooks
|
|
22
22
|
import { useCLIState } from '../../hooks/useCLIState.js';
|
|
23
23
|
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
|
|
24
|
+
import { useGitBranch } from '../../hooks/useGitBranch.js';
|
|
24
25
|
// Components
|
|
25
26
|
import { Header } from '../chat/Header.js';
|
|
26
27
|
import { MessageItem } from '../chat/MessageItem.js';
|
|
@@ -40,6 +41,8 @@ export function StaticCLI({ agent, initialSessionId, startupInfo, useStreaming =
|
|
|
40
41
|
startupInfo,
|
|
41
42
|
// No keyboard scroll handler - let terminal handle scrollback
|
|
42
43
|
});
|
|
44
|
+
// Get current git branch name
|
|
45
|
+
const branchName = useGitBranch();
|
|
43
46
|
// Terminal resize handling - clear and re-render Static content
|
|
44
47
|
const { write: stdoutWrite } = useStdout();
|
|
45
48
|
const { columns: terminalWidth } = useTerminalSize();
|
|
@@ -99,5 +102,5 @@ export function StaticCLI({ agent, initialSessionId, startupInfo, useStreaming =
|
|
|
99
102
|
startupInfo,
|
|
100
103
|
terminalWidth,
|
|
101
104
|
]);
|
|
102
|
-
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: [_jsx(
|
|
105
|
+
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: [_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 }), _jsx(TodoPanel, { todos: todos, isExpanded: ui.todoExpanded, isProcessing: ui.isProcessing }), _jsx(QueuedMessagesDisplay, { messages: queuedMessages }), _jsx(InputContainer, { ref: inputContainerRef, buffer: buffer, input: input, ui: ui, session: session, 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 }), _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 }), 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)" })] })), _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('!') }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
|
|
103
106
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExportWizard Component
|
|
3
|
+
* Interactive wizard for exporting conversation to markdown or JSON
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { Key } from '../../hooks/useInputOrchestrator.js';
|
|
7
|
+
import type { DextoAgent } from '@dexto/core';
|
|
8
|
+
interface ExportWizardProps {
|
|
9
|
+
isVisible: boolean;
|
|
10
|
+
agent: DextoAgent;
|
|
11
|
+
sessionId: string | null;
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
}
|
|
14
|
+
export interface ExportWizardHandle {
|
|
15
|
+
handleInput: (input: string, key: Key) => boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Interactive wizard for exporting conversation
|
|
19
|
+
*/
|
|
20
|
+
declare const ExportWizard: React.ForwardRefExoticComponent<ExportWizardProps & React.RefAttributes<ExportWizardHandle>>;
|
|
21
|
+
export default ExportWizard;
|
|
22
|
+
//# sourceMappingURL=ExportWizard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExportWizard.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/ExportWizard.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA4E,MAAM,OAAO,CAAC;AAIjG,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAY9C,UAAU,iBAAiB;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IAC/B,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AA4JD;;GAEG;AACH,QAAA,MAAM,YAAY,8FA+UhB,CAAC;AAEH,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ExportWizard Component
|
|
4
|
+
* Interactive wizard for exporting conversation to markdown or JSON
|
|
5
|
+
*/
|
|
6
|
+
import { useState, useEffect, forwardRef, useImperativeHandle, useCallback } from 'react';
|
|
7
|
+
import { Box, Text } from 'ink';
|
|
8
|
+
import fs from 'fs/promises';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
/**
|
|
11
|
+
* Generate default filename based on date and session ID
|
|
12
|
+
*/
|
|
13
|
+
function generateDefaultFilename(sessionId, format) {
|
|
14
|
+
const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
|
|
15
|
+
const shortId = sessionId ? sessionId.slice(0, 6) : 'unknown';
|
|
16
|
+
const ext = format === 'markdown' ? 'md' : 'json';
|
|
17
|
+
return `conversation-${date}-${shortId}.${ext}`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Format conversation history as Markdown
|
|
21
|
+
*/
|
|
22
|
+
function formatAsMarkdown(messages, metadata, includeToolCalls) {
|
|
23
|
+
const lines = [];
|
|
24
|
+
// Header
|
|
25
|
+
lines.push('# Conversation Export');
|
|
26
|
+
lines.push('');
|
|
27
|
+
lines.push(`- **Session**: ${metadata.sessionId}`);
|
|
28
|
+
if (metadata.title) {
|
|
29
|
+
lines.push(`- **Title**: ${metadata.title}`);
|
|
30
|
+
}
|
|
31
|
+
if (metadata.createdAt) {
|
|
32
|
+
lines.push(`- **Created**: ${metadata.createdAt}`);
|
|
33
|
+
}
|
|
34
|
+
lines.push(`- **Exported**: ${new Date().toISOString()}`);
|
|
35
|
+
lines.push('');
|
|
36
|
+
lines.push('---');
|
|
37
|
+
lines.push('');
|
|
38
|
+
// Messages
|
|
39
|
+
for (const msg of messages) {
|
|
40
|
+
const role = msg.role.charAt(0).toUpperCase() + msg.role.slice(1);
|
|
41
|
+
// Skip tool messages if not including tool calls
|
|
42
|
+
if (!includeToolCalls && msg.role === 'tool') {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
lines.push(`## ${role}`);
|
|
46
|
+
if (msg.timestamp) {
|
|
47
|
+
lines.push(`*${msg.timestamp}*`);
|
|
48
|
+
}
|
|
49
|
+
lines.push('');
|
|
50
|
+
// Handle different content types
|
|
51
|
+
if (typeof msg.content === 'string') {
|
|
52
|
+
lines.push(msg.content);
|
|
53
|
+
}
|
|
54
|
+
else if (Array.isArray(msg.content)) {
|
|
55
|
+
// Handle content parts (text, tool calls, tool results)
|
|
56
|
+
for (const part of msg.content) {
|
|
57
|
+
if (typeof part === 'string') {
|
|
58
|
+
lines.push(part);
|
|
59
|
+
}
|
|
60
|
+
else if (part && typeof part === 'object') {
|
|
61
|
+
if ('text' in part) {
|
|
62
|
+
lines.push(String(part.text));
|
|
63
|
+
}
|
|
64
|
+
else if ('type' in part && part.type === 'tool-call' && includeToolCalls) {
|
|
65
|
+
const toolCall = part;
|
|
66
|
+
lines.push('');
|
|
67
|
+
lines.push(`### Tool: ${toolCall.toolName || 'unknown'}`);
|
|
68
|
+
lines.push('```json');
|
|
69
|
+
lines.push(JSON.stringify(toolCall.args || {}, null, 2));
|
|
70
|
+
lines.push('```');
|
|
71
|
+
}
|
|
72
|
+
else if ('type' in part && part.type === 'tool-result' && includeToolCalls) {
|
|
73
|
+
const toolResult = part;
|
|
74
|
+
lines.push('');
|
|
75
|
+
lines.push('<details>');
|
|
76
|
+
lines.push(`<summary>Result: ${toolResult.toolName || 'unknown'}</summary>`);
|
|
77
|
+
lines.push('');
|
|
78
|
+
lines.push('```');
|
|
79
|
+
const resultStr = typeof toolResult.result === 'string'
|
|
80
|
+
? toolResult.result
|
|
81
|
+
: JSON.stringify(toolResult.result, null, 2);
|
|
82
|
+
// Truncate very long results
|
|
83
|
+
if (resultStr.length > 2000) {
|
|
84
|
+
lines.push(resultStr.slice(0, 2000) + '\n... (truncated)');
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
lines.push(resultStr);
|
|
88
|
+
}
|
|
89
|
+
lines.push('```');
|
|
90
|
+
lines.push('</details>');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (msg.content && typeof msg.content === 'object') {
|
|
96
|
+
lines.push('```json');
|
|
97
|
+
lines.push(JSON.stringify(msg.content, null, 2));
|
|
98
|
+
lines.push('```');
|
|
99
|
+
}
|
|
100
|
+
lines.push('');
|
|
101
|
+
lines.push('---');
|
|
102
|
+
lines.push('');
|
|
103
|
+
}
|
|
104
|
+
return lines.join('\n');
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Format conversation history as JSON
|
|
108
|
+
*/
|
|
109
|
+
function formatAsJson(messages, metadata, includeToolCalls) {
|
|
110
|
+
const filteredMessages = includeToolCalls
|
|
111
|
+
? messages
|
|
112
|
+
: messages
|
|
113
|
+
.filter((m) => m.role !== 'tool')
|
|
114
|
+
.map((m) => ({
|
|
115
|
+
...m,
|
|
116
|
+
content: Array.isArray(m.content)
|
|
117
|
+
? m.content.filter((part) => {
|
|
118
|
+
if (!part || typeof part !== 'object')
|
|
119
|
+
return true;
|
|
120
|
+
return !('type' in part &&
|
|
121
|
+
(part.type === 'tool-call' || part.type === 'tool-result'));
|
|
122
|
+
})
|
|
123
|
+
: m.content,
|
|
124
|
+
}));
|
|
125
|
+
return JSON.stringify({
|
|
126
|
+
exportedAt: new Date().toISOString(),
|
|
127
|
+
session: metadata,
|
|
128
|
+
messages: filteredMessages,
|
|
129
|
+
}, null, 2);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Interactive wizard for exporting conversation
|
|
133
|
+
*/
|
|
134
|
+
const ExportWizard = forwardRef(function ExportWizard({ isVisible, agent, sessionId, onClose }, ref) {
|
|
135
|
+
const [step, setStep] = useState('format');
|
|
136
|
+
const [options, setOptions] = useState({
|
|
137
|
+
format: 'markdown',
|
|
138
|
+
includeToolCalls: true,
|
|
139
|
+
filename: '',
|
|
140
|
+
});
|
|
141
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
142
|
+
const [filenameInput, setFilenameInput] = useState('');
|
|
143
|
+
const [exportResult, setExportResult] = useState(null);
|
|
144
|
+
// Reset when becoming visible
|
|
145
|
+
useEffect(() => {
|
|
146
|
+
if (isVisible) {
|
|
147
|
+
setStep('format');
|
|
148
|
+
setOptions({
|
|
149
|
+
format: 'markdown',
|
|
150
|
+
includeToolCalls: true,
|
|
151
|
+
filename: '',
|
|
152
|
+
});
|
|
153
|
+
setSelectedIndex(0);
|
|
154
|
+
setFilenameInput('');
|
|
155
|
+
setExportResult(null);
|
|
156
|
+
}
|
|
157
|
+
}, [isVisible]);
|
|
158
|
+
// Update default filename when format changes
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (step === 'filename' && !filenameInput) {
|
|
161
|
+
setFilenameInput(generateDefaultFilename(sessionId, options.format));
|
|
162
|
+
}
|
|
163
|
+
}, [step, sessionId, options.format, filenameInput]);
|
|
164
|
+
const doExport = useCallback(async () => {
|
|
165
|
+
if (!sessionId) {
|
|
166
|
+
setExportResult({ success: false, error: 'No active session' });
|
|
167
|
+
setStep('error');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
setStep('exporting');
|
|
171
|
+
try {
|
|
172
|
+
// Get session history and metadata
|
|
173
|
+
const history = await agent.getSessionHistory(sessionId);
|
|
174
|
+
const metadata = await agent.getSessionMetadata(sessionId);
|
|
175
|
+
const exportMetadata = {
|
|
176
|
+
sessionId,
|
|
177
|
+
title: metadata?.title,
|
|
178
|
+
createdAt: metadata?.createdAt
|
|
179
|
+
? new Date(metadata.createdAt).toISOString()
|
|
180
|
+
: undefined,
|
|
181
|
+
};
|
|
182
|
+
// Format content - cast history to expected type
|
|
183
|
+
const formattedHistory = history.map((msg) => ({
|
|
184
|
+
role: msg.role,
|
|
185
|
+
content: msg.content,
|
|
186
|
+
timestamp: 'timestamp' in msg && typeof msg.timestamp === 'number'
|
|
187
|
+
? new Date(msg.timestamp).toISOString()
|
|
188
|
+
: undefined,
|
|
189
|
+
}));
|
|
190
|
+
const content = options.format === 'markdown'
|
|
191
|
+
? formatAsMarkdown(formattedHistory, exportMetadata, options.includeToolCalls)
|
|
192
|
+
: formatAsJson(formattedHistory, exportMetadata, options.includeToolCalls);
|
|
193
|
+
// Write file - use path.basename to prevent path traversal attacks
|
|
194
|
+
const rawFilename = options.filename || filenameInput;
|
|
195
|
+
const safeFilename = path.basename(rawFilename);
|
|
196
|
+
const outputPath = path.resolve(process.cwd(), safeFilename);
|
|
197
|
+
await fs.writeFile(outputPath, content, 'utf-8');
|
|
198
|
+
setExportResult({ success: true, path: outputPath });
|
|
199
|
+
setStep('done');
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
setExportResult({
|
|
203
|
+
success: false,
|
|
204
|
+
error: error instanceof Error ? error.message : String(error),
|
|
205
|
+
});
|
|
206
|
+
setStep('error');
|
|
207
|
+
}
|
|
208
|
+
}, [agent, sessionId, options, filenameInput]);
|
|
209
|
+
// Handle keyboard input
|
|
210
|
+
useImperativeHandle(ref, () => ({
|
|
211
|
+
handleInput: (input, key) => {
|
|
212
|
+
if (!isVisible)
|
|
213
|
+
return false;
|
|
214
|
+
// Escape to close
|
|
215
|
+
if (key.escape) {
|
|
216
|
+
onClose();
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
// Done/error state - Enter/Esc closes, consume all other input
|
|
220
|
+
if (step === 'done' || step === 'error') {
|
|
221
|
+
if (key.return || key.escape) {
|
|
222
|
+
onClose();
|
|
223
|
+
}
|
|
224
|
+
return true; // Consume all input in terminal states
|
|
225
|
+
}
|
|
226
|
+
// Format selection step
|
|
227
|
+
if (step === 'format') {
|
|
228
|
+
if (key.upArrow || key.downArrow) {
|
|
229
|
+
setSelectedIndex((prev) => (prev === 0 ? 1 : 0));
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
if (key.return) {
|
|
233
|
+
setOptions((prev) => ({
|
|
234
|
+
...prev,
|
|
235
|
+
format: selectedIndex === 0 ? 'markdown' : 'json',
|
|
236
|
+
}));
|
|
237
|
+
setSelectedIndex(0);
|
|
238
|
+
setStep('toolCalls');
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
// Tool calls selection step
|
|
244
|
+
if (step === 'toolCalls') {
|
|
245
|
+
if (key.upArrow || key.downArrow) {
|
|
246
|
+
setSelectedIndex((prev) => (prev === 0 ? 1 : 0));
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
if (key.return) {
|
|
250
|
+
setOptions((prev) => ({
|
|
251
|
+
...prev,
|
|
252
|
+
includeToolCalls: selectedIndex === 0,
|
|
253
|
+
}));
|
|
254
|
+
setFilenameInput(generateDefaultFilename(sessionId, options.format));
|
|
255
|
+
setStep('filename');
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
// Filename input step
|
|
261
|
+
if (step === 'filename') {
|
|
262
|
+
if (key.return) {
|
|
263
|
+
const finalFilename = filenameInput.trim();
|
|
264
|
+
if (!finalFilename) {
|
|
265
|
+
// Don't proceed with empty filename
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
setOptions((prev) => ({ ...prev, filename: finalFilename }));
|
|
269
|
+
setSelectedIndex(0); // Reset to "Export" option
|
|
270
|
+
setStep('confirm');
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
if (key.backspace || key.delete) {
|
|
274
|
+
setFilenameInput((prev) => prev.slice(0, -1));
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
if (input && !key.ctrl && !key.meta) {
|
|
278
|
+
setFilenameInput((prev) => prev + input);
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
// Confirm step
|
|
284
|
+
if (step === 'confirm') {
|
|
285
|
+
if (key.upArrow || key.downArrow) {
|
|
286
|
+
setSelectedIndex((prev) => (prev === 0 ? 1 : 0));
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
if (key.return) {
|
|
290
|
+
if (selectedIndex === 0) {
|
|
291
|
+
doExport();
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
onClose();
|
|
295
|
+
}
|
|
296
|
+
return true;
|
|
297
|
+
}
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
return false;
|
|
301
|
+
},
|
|
302
|
+
}), [isVisible, step, selectedIndex, options, filenameInput, onClose, doExport, sessionId]);
|
|
303
|
+
if (!isVisible)
|
|
304
|
+
return null;
|
|
305
|
+
// Render based on current step
|
|
306
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, marginTop: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "\uD83D\uDCE4 Export Conversation" }) }), step === 'format' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Select export format:" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { ...(selectedIndex === 0 ? { color: 'cyan' } : {}), children: [selectedIndex === 0 ? '❯ ' : ' ', "Markdown (.md) - Human readable"] }), _jsxs(Text, { ...(selectedIndex === 1 ? { color: 'cyan' } : {}), children: [selectedIndex === 1 ? '❯ ' : ' ', "JSON (.json) - Structured data"] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "\u2191\u2193 to select \u2022 Enter to continue \u2022 Esc to cancel" }) })] })), step === 'toolCalls' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Include tool calls and results?" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { ...(selectedIndex === 0 ? { color: 'cyan' } : {}), children: [selectedIndex === 0 ? '❯ ' : ' ', "Yes - Include all tool interactions"] }), _jsxs(Text, { ...(selectedIndex === 1 ? { color: 'cyan' } : {}), children: [selectedIndex === 1 ? '❯ ' : ' ', "No - Only user and assistant messages"] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "\u2191\u2193 to select \u2022 Enter to continue \u2022 Esc to cancel" }) })] })), step === 'filename' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Filename:" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "cyan", children: "> " }), _jsx(Text, { children: filenameInput }), _jsx(Text, { color: "cyan", children: "_" })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "Enter to continue \u2022 Esc to cancel" }) })] })), step === 'confirm' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: "Export with these settings?" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", marginLeft: 2, children: [_jsxs(Text, { color: "gray", children: ["Format:", ' ', _jsx(Text, { color: "white", children: options.format === 'markdown' ? 'Markdown' : 'JSON' })] }), _jsxs(Text, { color: "gray", children: ["Tool calls:", ' ', _jsx(Text, { color: "white", children: options.includeToolCalls ? 'Yes' : 'No' })] }), _jsxs(Text, { color: "gray", children: ["File: ", _jsx(Text, { color: "white", children: filenameInput })] })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { ...(selectedIndex === 0 ? { color: 'green' } : {}), children: [selectedIndex === 0 ? '❯ ' : ' ', "Export"] }), _jsxs(Text, { ...(selectedIndex === 1 ? { color: 'red' } : {}), children: [selectedIndex === 1 ? '❯ ' : ' ', "Cancel"] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "\u2191\u2193 to select \u2022 Enter to confirm" }) })] })), step === 'exporting' && (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { color: "yellow", children: "Exporting..." }) })), step === 'done' && exportResult?.success && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "green", children: "\u2713 Exported successfully!" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: "gray", children: "Saved to: " }), _jsx(Text, { children: exportResult.path })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "Press Enter or Esc to close" }) })] })), step === 'error' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "red", children: "\u2717 Export failed" }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "red", children: exportResult?.error }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "Press Enter or Esc to close" }) })] }))] }));
|
|
307
|
+
});
|
|
308
|
+
export default ExportWizard;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LogLevelSelector.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/LogLevelSelector.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAuE,MAAM,OAAO,CAAC;AAE5F,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,UAAU,qBAAqB;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"LogLevelSelector.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/LogLevelSelector.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAuE,MAAM,OAAO,CAAC;AAE5F,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,UAAU,qBAAqB;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAkBD;;GAEG;AACH,QAAA,MAAM,gBAAgB,sGAwGrB,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -17,7 +17,7 @@ const LOG_LEVELS = [
|
|
|
17
17
|
/**
|
|
18
18
|
* Log level selector - thin wrapper around BaseSelector
|
|
19
19
|
*/
|
|
20
|
-
const LogLevelSelector = forwardRef(function LogLevelSelector({ isVisible, onSelect, onClose, agent }, ref) {
|
|
20
|
+
const LogLevelSelector = forwardRef(function LogLevelSelector({ isVisible, onSelect, onClose, agent, sessionId }, ref) {
|
|
21
21
|
const baseSelectorRef = useRef(null);
|
|
22
22
|
// Forward handleInput to BaseSelector
|
|
23
23
|
useImperativeHandle(ref, () => ({
|
|
@@ -30,30 +30,41 @@ const LogLevelSelector = forwardRef(function LogLevelSelector({ isVisible, onSel
|
|
|
30
30
|
const [logFilePath, setLogFilePath] = useState(null);
|
|
31
31
|
// Build levels list with current indicator
|
|
32
32
|
useEffect(() => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
33
|
+
let isCancelled = false;
|
|
34
|
+
const run = async () => {
|
|
35
|
+
if (!isVisible) {
|
|
36
|
+
setLogFilePath(null);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// Get current level from agent's logger (shared across all child loggers)
|
|
40
|
+
const currentLevel = agent.logger.getLevel();
|
|
41
|
+
const levelList = LOG_LEVELS.map((l) => ({
|
|
42
|
+
...l,
|
|
43
|
+
isCurrent: l.level === currentLevel,
|
|
44
|
+
}));
|
|
45
|
+
setLevels(levelList);
|
|
46
|
+
// File logging is session-scoped; prefer the active session logger if available.
|
|
47
|
+
const session = sessionId ? await agent.getSession(sessionId) : undefined;
|
|
48
|
+
if (!isCancelled) {
|
|
49
|
+
setLogFilePath(session?.logger.getLogFilePath() ?? null);
|
|
50
|
+
}
|
|
51
|
+
// Set initial selection to current level
|
|
52
|
+
const currentIndex = levelList.findIndex((l) => l.isCurrent);
|
|
53
|
+
if (currentIndex >= 0) {
|
|
54
|
+
setSelectedIndex(currentIndex);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
void run();
|
|
58
|
+
return () => {
|
|
59
|
+
isCancelled = true;
|
|
60
|
+
};
|
|
61
|
+
}, [isVisible, agent, sessionId]);
|
|
51
62
|
// Format level item for display
|
|
52
63
|
const formatItem = (option, isSelected) => (_jsxs(_Fragment, { children: [_jsxs(Text, { children: [option.icon, " "] }), _jsx(Text, { color: isSelected ? 'cyan' : 'gray', bold: isSelected, children: option.level }), _jsxs(Text, { color: isSelected ? 'white' : 'gray', children: [" - ", option.description] }), option.isCurrent && (_jsxs(Text, { color: isSelected ? 'cyan' : 'gray', bold: isSelected, children: [' ', "\u2190 Current"] }))] }));
|
|
53
64
|
// Handle selection
|
|
54
65
|
const handleSelect = (option) => {
|
|
55
66
|
onSelect(option.level);
|
|
56
67
|
};
|
|
57
|
-
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" }), logFilePath && process.env.
|
|
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" }), logFilePath && process.env.DEXTO_DEV_MODE === 'true' && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "gray", children: ["\uD83D\uDCC1 Log file: ", logFilePath] }) }))] }));
|
|
58
69
|
});
|
|
59
70
|
export default LogLevelSelector;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MarketplaceAddPrompt Component
|
|
3
|
+
* Prompts user to enter a marketplace source to add
|
|
4
|
+
*/
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import type { Key } from '../../hooks/useInputOrchestrator.js';
|
|
7
|
+
interface MarketplaceAddPromptProps {
|
|
8
|
+
isVisible: boolean;
|
|
9
|
+
onComplete: (name: string, pluginCount: number) => void;
|
|
10
|
+
onClose: () => void;
|
|
11
|
+
}
|
|
12
|
+
export interface MarketplaceAddPromptHandle {
|
|
13
|
+
handleInput: (input: string, key: Key) => boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Marketplace add prompt - single input for source
|
|
17
|
+
*/
|
|
18
|
+
declare const MarketplaceAddPrompt: React.ForwardRefExoticComponent<MarketplaceAddPromptProps & React.RefAttributes<MarketplaceAddPromptHandle>>;
|
|
19
|
+
export default MarketplaceAddPrompt;
|
|
20
|
+
//# sourceMappingURL=MarketplaceAddPrompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MarketplaceAddPrompt.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/MarketplaceAddPrompt.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAA4E,MAAM,OAAO,CAAC;AAIjG,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAE/D,UAAU,yBAAyB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD,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;;GAEG;AACH,QAAA,MAAM,oBAAoB,8GAsIzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* MarketplaceAddPrompt Component
|
|
4
|
+
* Prompts user to enter a marketplace source to add
|
|
5
|
+
*/
|
|
6
|
+
import { useState, useEffect, forwardRef, useImperativeHandle, useCallback } from 'react';
|
|
7
|
+
import { Box, Text } from 'ink';
|
|
8
|
+
import { addMarketplace } from '@dexto/agent-management';
|
|
9
|
+
import { logger } from '@dexto/core';
|
|
10
|
+
/**
|
|
11
|
+
* Marketplace add prompt - single input for source
|
|
12
|
+
*/
|
|
13
|
+
const MarketplaceAddPrompt = forwardRef(function MarketplaceAddPrompt({ isVisible, onComplete, onClose }, ref) {
|
|
14
|
+
const [input, setInput] = useState('');
|
|
15
|
+
const [error, setError] = useState(null);
|
|
16
|
+
const [isAdding, setIsAdding] = useState(false);
|
|
17
|
+
// Reset when becoming visible
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (isVisible) {
|
|
20
|
+
setInput('');
|
|
21
|
+
setError(null);
|
|
22
|
+
setIsAdding(false);
|
|
23
|
+
}
|
|
24
|
+
}, [isVisible]);
|
|
25
|
+
// Handle adding marketplace
|
|
26
|
+
const handleAdd = useCallback(async () => {
|
|
27
|
+
const source = input.trim();
|
|
28
|
+
if (!source) {
|
|
29
|
+
setError('Please enter a marketplace source');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
setError(null);
|
|
33
|
+
setIsAdding(true);
|
|
34
|
+
try {
|
|
35
|
+
const result = await addMarketplace(source);
|
|
36
|
+
onComplete(result.name, result.pluginCount);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
40
|
+
setError(errorMessage);
|
|
41
|
+
logger.error(`MarketplaceAddPrompt.handleAdd failed: ${errorMessage}`);
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
setIsAdding(false);
|
|
45
|
+
}
|
|
46
|
+
}, [input, onComplete]);
|
|
47
|
+
// Handle input
|
|
48
|
+
useImperativeHandle(ref, () => ({
|
|
49
|
+
handleInput: (inputStr, key) => {
|
|
50
|
+
// Escape to close
|
|
51
|
+
if (key.escape) {
|
|
52
|
+
onClose();
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
// Enter to submit
|
|
56
|
+
if (key.return) {
|
|
57
|
+
if (!isAdding) {
|
|
58
|
+
handleAdd();
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
// Backspace
|
|
63
|
+
if (key.backspace || key.delete) {
|
|
64
|
+
setInput((prev) => prev.slice(0, -1));
|
|
65
|
+
setError(null);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
// Regular character input
|
|
69
|
+
if (inputStr && !key.ctrl && !key.meta) {
|
|
70
|
+
setInput((prev) => prev + inputStr);
|
|
71
|
+
setError(null);
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
},
|
|
76
|
+
}), [handleAdd, isAdding, onClose]);
|
|
77
|
+
if (!isVisible)
|
|
78
|
+
return null;
|
|
79
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "green", paddingX: 1, marginTop: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "green", children: "Add Marketplace" }) }), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "gray", children: "Enter marketplace source:" }) }), _jsxs(Box, { marginBottom: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", dimColor: true, children: "- GitHub: owner/repo (e.g., anthropics/claude-plugins-official)" }), _jsx(Text, { color: "gray", dimColor: true, children: "- Git URL: https://github.com/user/repo.git" }), _jsx(Text, { color: "gray", dimColor: true, children: "- Local: /path/to/marketplace or ~/marketplace" })] }), _jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: '> ' }), _jsx(Text, { children: input }), _jsx(Text, { color: "cyan", children: "_" })] }), error && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "red", children: error }) })), isAdding && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "Adding marketplace..." }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "Press Enter to add, Escape to cancel" }) })] }));
|
|
80
|
+
});
|
|
81
|
+
export default MarketplaceAddPrompt;
|