dexto 1.5.4 → 1.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +371 -408
  2. package/dist/agents/agent-template.yml +1 -1
  3. package/dist/agents/coding-agent/coding-agent.yml +16 -2
  4. package/dist/agents/podcast-agent/podcast-agent.yml +1 -1
  5. package/dist/cli/cli-subscriber.d.ts +0 -1
  6. package/dist/cli/cli-subscriber.d.ts.map +1 -1
  7. package/dist/cli/cli-subscriber.js +0 -8
  8. package/dist/cli/commands/index.d.ts +1 -0
  9. package/dist/cli/commands/index.d.ts.map +1 -1
  10. package/dist/cli/commands/index.js +1 -0
  11. package/dist/cli/commands/interactive-commands/commands.d.ts.map +1 -1
  12. package/dist/cli/commands/interactive-commands/commands.js +2 -0
  13. package/dist/cli/commands/interactive-commands/export/index.d.ts +13 -0
  14. package/dist/cli/commands/interactive-commands/export/index.d.ts.map +1 -0
  15. package/dist/cli/commands/interactive-commands/export/index.js +21 -0
  16. package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
  17. package/dist/cli/commands/interactive-commands/general-commands.js +45 -23
  18. package/dist/cli/commands/interactive-commands/system/system-commands.d.ts.map +1 -1
  19. package/dist/cli/commands/interactive-commands/system/system-commands.js +2 -3
  20. package/dist/cli/commands/setup.js +106 -27
  21. package/dist/cli/commands/sync-agents.d.ts +44 -0
  22. package/dist/cli/commands/sync-agents.d.ts.map +1 -0
  23. package/dist/cli/commands/sync-agents.js +483 -0
  24. package/dist/cli/ink-cli/InkCLIRefactored.d.ts +14 -1
  25. package/dist/cli/ink-cli/InkCLIRefactored.d.ts.map +1 -1
  26. package/dist/cli/ink-cli/InkCLIRefactored.js +7 -2
  27. package/dist/cli/ink-cli/components/Footer.d.ts +4 -1
  28. package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
  29. package/dist/cli/ink-cli/components/Footer.js +62 -18
  30. package/dist/cli/ink-cli/components/StatusBar.d.ts +5 -1
  31. package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
  32. package/dist/cli/ink-cli/components/StatusBar.js +16 -4
  33. package/dist/cli/ink-cli/components/TodoPanel.d.ts +26 -0
  34. package/dist/cli/ink-cli/components/TodoPanel.d.ts.map +1 -0
  35. package/dist/cli/ink-cli/components/TodoPanel.js +62 -0
  36. package/dist/cli/ink-cli/components/chat/Header.d.ts.map +1 -1
  37. package/dist/cli/ink-cli/components/chat/Header.js +1 -1
  38. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +1 -1
  39. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
  40. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +15 -5
  41. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
  42. package/dist/cli/ink-cli/components/modes/StaticCLI.js +3 -2
  43. package/dist/cli/ink-cli/components/overlays/ContextStatsOverlay.d.ts.map +1 -1
  44. package/dist/cli/ink-cli/components/overlays/ContextStatsOverlay.js +4 -3
  45. package/dist/cli/ink-cli/components/overlays/ExportWizard.d.ts +22 -0
  46. package/dist/cli/ink-cli/components/overlays/ExportWizard.d.ts.map +1 -0
  47. package/dist/cli/ink-cli/components/overlays/ExportWizard.js +308 -0
  48. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +1 -1
  49. package/dist/cli/ink-cli/components/shared/MarkdownText.d.ts.map +1 -1
  50. package/dist/cli/ink-cli/components/shared/MarkdownText.js +28 -1
  51. package/dist/cli/ink-cli/constants/processingPhrases.d.ts.map +1 -1
  52. package/dist/cli/ink-cli/constants/processingPhrases.js +7 -0
  53. package/dist/cli/ink-cli/constants/tips.js +2 -2
  54. package/dist/cli/ink-cli/containers/InputContainer.d.ts +3 -1
  55. package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
  56. package/dist/cli/ink-cli/containers/InputContainer.js +4 -1
  57. package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
  58. package/dist/cli/ink-cli/containers/OverlayContainer.js +5 -1
  59. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts +8 -2
  60. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts.map +1 -1
  61. package/dist/cli/ink-cli/hooks/useAgentEvents.js +69 -3
  62. package/dist/cli/ink-cli/hooks/useCLIState.d.ts +4 -2
  63. package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
  64. package/dist/cli/ink-cli/hooks/useCLIState.js +11 -0
  65. package/dist/cli/ink-cli/hooks/useInputOrchestrator.d.ts.map +1 -1
  66. package/dist/cli/ink-cli/hooks/useInputOrchestrator.js +5 -0
  67. package/dist/cli/ink-cli/services/processStream.d.ts +2 -0
  68. package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
  69. package/dist/cli/ink-cli/services/processStream.js +26 -55
  70. package/dist/cli/ink-cli/state/initialState.d.ts.map +1 -1
  71. package/dist/cli/ink-cli/state/initialState.js +1 -0
  72. package/dist/cli/ink-cli/state/types.d.ts +31 -1
  73. package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
  74. package/dist/cli/ink-cli/utils/commandOverlays.d.ts.map +1 -1
  75. package/dist/cli/ink-cli/utils/commandOverlays.js +1 -0
  76. package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
  77. package/dist/cli/ink-cli/utils/messageFormatting.js +2 -1
  78. package/dist/cli/utils/api-key-setup.d.ts.map +1 -1
  79. package/dist/cli/utils/api-key-setup.js +13 -90
  80. package/dist/cli/utils/options.d.ts.map +1 -1
  81. package/dist/cli/utils/options.js +10 -2
  82. package/dist/cli/utils/version-check.d.ts +45 -0
  83. package/dist/cli/utils/version-check.d.ts.map +1 -0
  84. package/dist/cli/utils/version-check.js +195 -0
  85. package/dist/config/cli-overrides.d.ts +2 -0
  86. package/dist/config/cli-overrides.d.ts.map +1 -1
  87. package/dist/config/cli-overrides.js +9 -0
  88. package/dist/index.js +67 -37
  89. package/dist/webui/assets/index-BglIVTSG.css +1 -0
  90. package/dist/webui/assets/index-DVQWNLpT.js +2059 -0
  91. package/dist/webui/index.html +2 -2
  92. package/package.json +10 -8
  93. package/dist/webui/assets/index-Bh2aB65S.js +0 -2054
  94. package/dist/webui/assets/index-CUVc7IDL.css +0 -1
@@ -21,7 +21,7 @@ import { useTokenCounter } from '../hooks/useTokenCounter.js';
21
21
  * - Hide spinner during approval wait (user is reviewing, not waiting)
22
22
  * - Only show elapsed time after 30s (avoid visual noise for fast operations)
23
23
  */
24
- export function StatusBar({ agent, isProcessing, isThinking, isCompacting, approvalQueueCount, copyModeEnabled = false, isAwaitingApproval = false, }) {
24
+ export function StatusBar({ agent, isProcessing, isThinking, isCompacting, approvalQueueCount, copyModeEnabled = false, isAwaitingApproval = false, todoExpanded = true, hasTodos = false, }) {
25
25
  // Cycle through witty phrases while processing (not during compacting)
26
26
  const { phrase } = usePhraseCycler({ isActive: isProcessing && !isCompacting });
27
27
  // Track elapsed time during processing
@@ -42,14 +42,22 @@ export function StatusBar({ agent, isProcessing, isThinking, isCompacting, appro
42
42
  if (isAwaitingApproval) {
43
43
  return null;
44
44
  }
45
+ // Build the task toggle hint based on state
46
+ const todoHint = hasTodos
47
+ ? todoExpanded
48
+ ? 'ctrl+t to hide tasks'
49
+ : 'ctrl+t to show tasks'
50
+ : null;
45
51
  // Show compacting state - yellow/orange color to indicate context management
46
52
  if (isCompacting) {
47
53
  const metaParts = [];
48
54
  if (showTime)
49
55
  metaParts.push(`(${elapsedTime})`);
50
56
  metaParts.push('Esc to cancel');
57
+ if (todoHint)
58
+ metaParts.push(todoHint);
51
59
  const metaContent = metaParts.join(' • ');
52
- return (_jsxs(Box, { paddingX: 1, marginTop: 1, marginBottom: 1, flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", alignItems: "center", children: [_jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { color: "yellow", children: " \uD83D\uDCE6 Compacting context..." })] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: metaContent }) })] }));
60
+ return (_jsxs(Box, { paddingX: 1, marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", alignItems: "center", children: [_jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { color: "yellow", children: " \uD83D\uDCE6 Compacting context..." })] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: metaContent }) })] }));
53
61
  }
54
62
  // Show initial processing state (before streaming starts) - green/teal color
55
63
  // TODO: Rename this event/state to "reasoning" and associate it with actual reasoning tokens
@@ -61,8 +69,10 @@ export function StatusBar({ agent, isProcessing, isThinking, isCompacting, appro
61
69
  if (tokenCount)
62
70
  metaParts.push(tokenCount);
63
71
  metaParts.push('Esc to cancel');
72
+ if (todoHint)
73
+ metaParts.push(todoHint);
64
74
  const metaContent = metaParts.join(' • ');
65
- return (_jsxs(Box, { paddingX: 1, marginTop: 1, marginBottom: 1, flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", alignItems: "center", children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { color: "green", children: [" ", phrase] })] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: metaContent }) })] }));
75
+ return (_jsxs(Box, { paddingX: 1, marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", alignItems: "center", children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { color: "green", children: [" ", phrase] })] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: metaContent }) })] }));
66
76
  }
67
77
  // Show active streaming state - green/teal color
68
78
  // Always use 2-line layout: phrase on first line, meta on second
@@ -73,6 +83,8 @@ export function StatusBar({ agent, isProcessing, isThinking, isCompacting, appro
73
83
  if (tokenCount)
74
84
  metaParts.push(tokenCount);
75
85
  metaParts.push('Esc to cancel');
86
+ if (todoHint)
87
+ metaParts.push(todoHint);
76
88
  const metaContent = metaParts.join(' • ');
77
- return (_jsxs(Box, { paddingX: 1, marginTop: 1, marginBottom: 1, flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", alignItems: "center", children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { color: "green", children: [" ", phrase] }), approvalQueueCount > 0 && (_jsxs(Text, { color: "yellowBright", children: [" \u2022 ", approvalQueueCount, " queued"] }))] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: metaContent }) })] }));
89
+ return (_jsxs(Box, { paddingX: 1, marginTop: 1, flexDirection: "column", children: [_jsxs(Box, { flexDirection: "row", alignItems: "center", children: [_jsx(Text, { color: "green", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { color: "green", children: [" ", phrase] }), approvalQueueCount > 0 && (_jsxs(Text, { color: "yellowBright", children: [" \u2022 ", approvalQueueCount, " queued"] }))] }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "gray", children: metaContent }) })] }));
78
90
  }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * TodoPanel Component
3
+ *
4
+ * Displays the current todo list for workflow tracking.
5
+ * Shows todos with their status indicators (pending, in progress, completed).
6
+ *
7
+ * Display modes:
8
+ * - Processing + Collapsed: Shows "Next:" with the next pending/in-progress task
9
+ * - Processing + Expanded: Shows simple checklist with ☐/☑ indicators below status bar
10
+ * - Idle + Expanded: Shows boxed format with header
11
+ * - Idle + Collapsed: Hidden
12
+ */
13
+ import type { TodoItem } from '../state/types.js';
14
+ interface TodoPanelProps {
15
+ todos: TodoItem[];
16
+ /** Whether to show the full list or just the next task */
17
+ isExpanded: boolean;
18
+ /** Whether the agent is currently processing (affects display style) */
19
+ isProcessing?: boolean;
20
+ }
21
+ /**
22
+ * TodoPanel - Shows current todos for workflow tracking
23
+ */
24
+ export declare function TodoPanel({ todos, isExpanded, isProcessing }: TodoPanelProps): import("react/jsx-runtime").JSX.Element | null;
25
+ export {};
26
+ //# sourceMappingURL=TodoPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TodoPanel.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/TodoPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,mBAAmB,CAAC;AAE9D,UAAU,cAAc;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,0DAA0D;IAC1D,UAAU,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAiBD;;GAEG;AACH,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,YAAoB,EAAE,EAAE,cAAc,kDAkHpF"}
@@ -0,0 +1,62 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ /**
4
+ * Get status indicator for a todo item (used in boxed mode)
5
+ */
6
+ function getStatusIndicator(status) {
7
+ switch (status) {
8
+ case 'completed':
9
+ return { icon: '✓', color: 'green' };
10
+ case 'in_progress':
11
+ return { icon: '●', color: 'yellow' };
12
+ case 'pending':
13
+ default:
14
+ return { icon: '○', color: 'gray' };
15
+ }
16
+ }
17
+ /**
18
+ * TodoPanel - Shows current todos for workflow tracking
19
+ */
20
+ export function TodoPanel({ todos, isExpanded, isProcessing = false }) {
21
+ if (todos.length === 0) {
22
+ return null;
23
+ }
24
+ // Sort todos by position
25
+ const sortedTodos = [...todos].sort((a, b) => a.position - b.position);
26
+ // Find the next task to work on (in_progress first, then first pending)
27
+ const currentTask = sortedTodos.find((t) => t.status === 'in_progress');
28
+ const nextPendingTask = sortedTodos.find((t) => t.status === 'pending');
29
+ const nextTask = currentTask || nextPendingTask;
30
+ // When idle (not processing)
31
+ if (!isProcessing) {
32
+ // Collapsed + idle = hidden
33
+ if (!isExpanded) {
34
+ return null;
35
+ }
36
+ // Expanded + idle = boxed format
37
+ const completedCount = todos.filter((t) => t.status === 'completed').length;
38
+ const totalCount = todos.length;
39
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, marginX: 1, marginBottom: 1, children: [_jsxs(Box, { children: [_jsxs(Text, { bold: true, color: "cyan", children: ["\uD83D\uDCCB Tasks", ' '] }), _jsxs(Text, { color: "gray", children: ["(", completedCount, "/", totalCount, ")"] }), _jsxs(Text, { color: "gray", dimColor: true, children: [' ', "\u00B7 ctrl+t to hide tasks"] })] }), _jsx(Box, { flexDirection: "column", children: sortedTodos.map((todo) => {
40
+ const { icon, color } = getStatusIndicator(todo.status);
41
+ const isCompleted = todo.status === 'completed';
42
+ const isInProgress = todo.status === 'in_progress';
43
+ return (_jsxs(Box, { children: [_jsxs(Text, { color: color, children: [icon, " "] }), _jsx(Text, { color: isCompleted ? 'gray' : isInProgress ? 'white' : 'gray', strikethrough: isCompleted, dimColor: !isInProgress && !isCompleted, children: isInProgress ? todo.activeForm : todo.content })] }, todo.id));
44
+ }) })] }));
45
+ }
46
+ // When processing - use minimal style
47
+ // Collapsed: show current task being worked on
48
+ if (!isExpanded) {
49
+ if (!currentTask) {
50
+ return null; // No active task
51
+ }
52
+ return (_jsx(Box, { paddingX: 1, marginBottom: 1, children: _jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "gray", children: "\u23BF " }), _jsx(Text, { color: "gray", children: currentTask.activeForm })] }) }));
53
+ }
54
+ // Expanded: show simple checklist
55
+ return (_jsx(Box, { flexDirection: "column", paddingX: 1, marginBottom: 1, children: sortedTodos.map((todo, index) => {
56
+ const isFirst = index === 0;
57
+ const isCompleted = todo.status === 'completed';
58
+ const isInProgress = todo.status === 'in_progress';
59
+ const checkbox = isCompleted ? '☑' : '☐';
60
+ return (_jsxs(Box, { marginLeft: 2, children: [_jsx(Text, { color: "gray", children: isFirst ? '⎿ ' : ' ' }), _jsxs(Text, { color: isCompleted ? 'green' : isInProgress ? 'yellow' : 'white', children: [checkbox, ' '] }), _jsx(Text, { color: isCompleted ? 'gray' : 'white', dimColor: isCompleted, children: todo.content })] }, todo.id));
61
+ }) }));
62
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/chat/Header.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGxD,UAAU,WAAW;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,WAAW,EAAE,EAAE,WAAW,2CAgE1F"}
1
+ {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/chat/Header.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGxD,UAAU,WAAW;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,WAAW,EAAE,EAAE,WAAW,2CAoF1F"}
@@ -12,5 +12,5 @@ export function Header({ modelName, sessionId, hasActiveSession, startupInfo })
12
12
  ██║ ██║█████╗ ╚███╔╝ ██║ ██║ ██║
13
13
  ██║ ██║██╔══╝ ██╔██╗ ██║ ██║ ██║
14
14
  ██████╔╝███████╗██╔╝ ██╗ ██║ ╚██████╔╝
15
- ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝` }) }), _jsxs(Box, { marginTop: 1, flexDirection: "row", children: [_jsx(Text, { color: "gray", children: "Model: " }), _jsx(Text, { color: "white", children: modelName }), hasActiveSession && sessionId && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "gray", children: " \u2022 Session: " }), _jsx(Text, { color: "white", children: sessionId.slice(0, 8) })] }))] }), _jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "gray", children: "Servers: " }), _jsx(Text, { color: "white", children: startupInfo.connectedServers.count }), _jsx(Text, { color: "gray", children: " \u2022 Tools: " }), _jsx(Text, { color: "white", children: startupInfo.toolCount })] }), startupInfo.failedConnections.length > 0 && (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { color: "yellowBright", children: ["\u26A0\uFE0F Failed: ", startupInfo.failedConnections.join(', ')] }) })), startupInfo.logFile && process.env.DEXTO_PRIVACY_MODE !== 'true' && (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { color: "gray", children: ["Logs: ", startupInfo.logFile] }) })), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: " " }) })] }));
15
+ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝` }) }), _jsxs(Box, { marginTop: 1, flexDirection: "row", children: [_jsx(Text, { color: "gray", children: "Model: " }), _jsx(Text, { color: "white", children: modelName }), hasActiveSession && sessionId && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "gray", children: " \u2022 Session: " }), _jsx(Text, { color: "white", children: sessionId.slice(0, 8) })] }))] }), _jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: "gray", children: "Servers: " }), _jsx(Text, { color: "white", children: startupInfo.connectedServers.count }), _jsx(Text, { color: "gray", children: " \u2022 Tools: " }), _jsx(Text, { color: "white", children: startupInfo.toolCount })] }), startupInfo.failedConnections.length > 0 && (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { color: "yellowBright", children: ["\u26A0\uFE0F Failed: ", startupInfo.failedConnections.join(', ')] }) })), startupInfo.logFile && process.env.DEXTO_DEV_MODE === 'true' && (_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { color: "gray", children: ["Logs: ", startupInfo.logFile] }) })), startupInfo.updateInfo && (_jsxs(Box, { marginTop: 1, flexDirection: "row", children: [_jsxs(Text, { color: "yellow", children: ["\u2B06\uFE0F Update available: ", startupInfo.updateInfo.current, " \u2192", ' ', startupInfo.updateInfo.latest] }), _jsx(Text, { color: "gray", children: " \u2022 Run: " }), _jsx(Text, { color: "cyan", children: startupInfo.updateInfo.updateCommand })] })), startupInfo.needsAgentSync && (_jsxs(Box, { marginTop: startupInfo.updateInfo ? 0 : 1, flexDirection: "row", children: [_jsx(Text, { color: "yellow", children: "\uD83D\uDD04 Agent configs have updates available. Run: " }), _jsx(Text, { color: "cyan", children: "dexto sync-agents" })] })), _jsx(Box, { marginBottom: 1, children: _jsx(Text, { children: " " }) })] }));
16
16
  }
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from 'ink';
3
3
  import { StyledBox, StyledRow, StyledListItem } from './StyledBox.js';
4
4
  export function LogConfigBox({ data }) {
5
- return (_jsxs(StyledBox, { title: "Logging Configuration", children: [_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StyledRow, { label: "Current level", value: data.currentLevel, valueColor: "green" }), data.logFile && process.env.DEXTO_PRIVACY_MODE !== 'true' && (_jsx(StyledRow, { label: "Log file", value: data.logFile }))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: "Available levels (least to most verbose):" }), data.availableLevels.map((level) => {
5
+ return (_jsxs(StyledBox, { title: "Logging Configuration", children: [_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StyledRow, { label: "Current level", value: data.currentLevel, valueColor: "green" }), data.logFile && process.env.DEXTO_DEV_MODE === 'true' && (_jsx(StyledRow, { label: "Log file", value: data.logFile }))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: "Available levels (least to most verbose):" }), data.availableLevels.map((level) => {
6
6
  const isCurrent = level === data.currentLevel;
7
7
  return (_jsx(StyledListItem, { icon: isCurrent ? '>' : ' ', text: level, isActive: isCurrent }, level));
8
8
  })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", children: "Use /log <level> to change level" }) })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"AlternateBufferCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/AlternateBufferCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA2BjE,UAAU,uBAAuB;IAC7B,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,YAAmB,GACtB,EAAE,uBAAuB,2CAkTzB"}
1
+ {"version":3,"file":"AlternateBufferCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/AlternateBufferCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA4BjE,UAAU,uBAAuB;IAC7B,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,YAAmB,GACtB,EAAE,uBAAuB,2CA0UzB"}
@@ -23,6 +23,7 @@ import { QueuedMessagesDisplay } from '../chat/QueuedMessagesDisplay.js';
23
23
  import { StatusBar } from '../StatusBar.js';
24
24
  import { HistorySearchBar } from '../HistorySearchBar.js';
25
25
  import { Footer } from '../Footer.js';
26
+ import { TodoPanel } from '../TodoPanel.js';
26
27
  import { VirtualizedList, SCROLL_TO_ITEM_END, } from '../shared/VirtualizedList.js';
27
28
  // Containers
28
29
  import { InputContainer } from '../../containers/InputContainer.js';
@@ -41,7 +42,7 @@ export function AlternateBufferCLI({ agent, initialSessionId, startupInfo, onSel
41
42
  listRef.current?.scrollBy(delta);
42
43
  }, []);
43
44
  // Use shared CLI state with keyboard scroll handler
44
- const { messages, setMessages, pendingMessages, setPendingMessages, dequeuedBuffer, setDequeuedBuffer, queuedMessages, setQueuedMessages, ui, setUi, input, setInput, session, setSession, approval, setApproval, approvalQueue, setApprovalQueue, inputService, buffer, overlayContainerRef, visibleMessages, } = useCLIState({
45
+ 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({
45
46
  agent,
46
47
  initialSessionId,
47
48
  startupInfo,
@@ -98,19 +99,28 @@ export function AlternateBufferCLI({ agent, initialSessionId, startupInfo, onSel
98
99
  // Build list data: header as first item, then finalized + pending + dequeued buffer
99
100
  // In alternate buffer mode, everything is re-rendered anyway, so we combine all
100
101
  // Order: finalized messages → pending/streaming → dequeued user messages (guarantees order)
102
+ // IMPORTANT: Deduplicate by ID to prevent race condition where a message appears in both
103
+ // finalized (messages) and pending during the brief window between setState calls
101
104
  const listData = useMemo(() => {
102
105
  const items = [{ type: 'header' }];
106
+ const seenIds = new Set();
103
107
  for (const msg of visibleMessages) {
104
108
  items.push({ type: 'message', message: msg });
109
+ seenIds.add(msg.id);
105
110
  }
106
- // Add pending/streaming messages
111
+ // Add pending/streaming messages (skip if already in finalized - race condition guard)
107
112
  for (const msg of pendingMessages) {
108
- items.push({ type: 'message', message: msg });
113
+ if (!seenIds.has(msg.id)) {
114
+ items.push({ type: 'message', message: msg });
115
+ seenIds.add(msg.id);
116
+ }
109
117
  }
110
118
  // Add dequeued buffer (user messages waiting to be flushed to finalized)
111
119
  // These render AFTER pending to guarantee correct visual order
112
120
  for (const msg of dequeuedBuffer) {
113
- items.push({ type: 'message', message: msg });
121
+ if (!seenIds.has(msg.id)) {
122
+ items.push({ type: 'message', message: msg });
123
+ }
114
124
  }
115
125
  return items;
116
126
  }, [visibleMessages, pendingMessages, dequeuedBuffer]);
@@ -162,5 +172,5 @@ export function AlternateBufferCLI({ agent, initialSessionId, startupInfo, onSel
162
172
  return 'header';
163
173
  return item.message.id;
164
174
  }, []);
165
- 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 }), 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, 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, { modelName: session.modelName, cwd: process.cwd(), autoApproveEdits: ui.autoApproveEdits, isShellMode: buffer.text.startsWith('!') }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
175
+ 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') }), _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(), autoApproveEdits: ui.autoApproveEdits, isShellMode: buffer.text.startsWith('!') }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
166
176
  }
@@ -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;AAkBxD,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,2CAsNhB"}
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;AAmBxD,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,2CAoOhB"}
@@ -28,12 +28,13 @@ import { QueuedMessagesDisplay } from '../chat/QueuedMessagesDisplay.js';
28
28
  import { StatusBar } from '../StatusBar.js';
29
29
  import { HistorySearchBar } from '../HistorySearchBar.js';
30
30
  import { Footer } from '../Footer.js';
31
+ import { TodoPanel } from '../TodoPanel.js';
31
32
  // Containers
32
33
  import { InputContainer } from '../../containers/InputContainer.js';
33
34
  import { OverlayContainer } from '../../containers/OverlayContainer.js';
34
35
  export function StaticCLI({ agent, initialSessionId, startupInfo, useStreaming = true, }) {
35
36
  // Use shared CLI state (no keyboard scroll in Static mode)
36
- const { messages, setMessages, pendingMessages, setPendingMessages, dequeuedBuffer, setDequeuedBuffer, queuedMessages, setQueuedMessages, ui, setUi, input, setInput, session, setSession, approval, setApproval, approvalQueue, setApprovalQueue, inputService, buffer, overlayContainerRef, visibleMessages, } = useCLIState({
37
+ 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({
37
38
  agent,
38
39
  initialSessionId,
39
40
  startupInfo,
@@ -98,5 +99,5 @@ export function StaticCLI({ agent, initialSessionId, startupInfo, useStreaming =
98
99
  startupInfo,
99
100
  terminalWidth,
100
101
  ]);
101
- 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 }), _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, 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, { modelName: session.modelName, cwd: process.cwd(), autoApproveEdits: ui.autoApproveEdits, isShellMode: buffer.text.startsWith('!') }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
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(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') }), _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(), autoApproveEdits: ui.autoApproveEdits, isShellMode: buffer.text.startsWith('!') }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
102
103
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ContextStatsOverlay.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/ContextStatsOverlay.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAA+D,MAAM,OAAO,CAAC;AAEpF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,UAAU,wBAAwB;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACtC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AA8JD;;GAEG;AACH,QAAA,MAAM,mBAAmB,4GAsWxB,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"ContextStatsOverlay.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/overlays/ContextStatsOverlay.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAA+D,MAAM,OAAO,CAAC;AAEpF,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,UAAU,wBAAwB;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACtC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AA6JD;;GAEG;AACH,QAAA,MAAM,mBAAmB,4GAoWxB,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -202,7 +202,8 @@ const ContextStatsOverlay = forwardRef(function ContextStatsOverlay({ isVisible,
202
202
  const percent = totalTokenSpace > 0 ? ((tokens / totalTokenSpace) * 100).toFixed(1) : '0.0';
203
203
  return `${percent}%`;
204
204
  };
205
- const tokenDisplay = `~${formatTokens(stats.estimatedTokens)}`;
205
+ const usedTokens = stats.estimatedTokens + autoCompactBuffer;
206
+ const tokenDisplay = `~${formatTokens(usedTokens)}`;
206
207
  const isToolsExpanded = expandedSections.has('tools');
207
208
  // Create stacked bar segments
208
209
  // Uses maxContextTokens (effective limit) + autoCompactBuffer as the full bar
@@ -227,7 +228,7 @@ const ContextStatsOverlay = forwardRef(function ContextStatsOverlay({ isVisible,
227
228
  return (_jsx(Text, { color: "white", children: isHighlighted
228
229
  ? '▼'.repeat(segment.width)
229
230
  : ' '.repeat(segment.width) }, idx));
230
- }) }), _jsx(Box, { children: barSegments.map((segment, idx) => (_jsx(Text, { color: segment.color, children: segment.char.repeat(segment.width) }, idx))) }), _jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: "gray", children: [tokenDisplay, " / ", formatTokens(stats.maxContextTokens), " tokens"] }), _jsx(Text, { color: "gray", children: " \u2022 " }), _jsxs(Text, { color: stats.usagePercent > 80
231
+ }) }), _jsx(Box, { children: barSegments.map((segment, idx) => (_jsx(Text, { color: segment.color, children: segment.char.repeat(segment.width) }, idx))) }), _jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: "gray", children: [tokenDisplay, " / ", formatTokens(totalTokenSpace), " tokens"] }), _jsx(Text, { color: "gray", children: " \u2022 " }), _jsxs(Text, { color: stats.usagePercent > 80
231
232
  ? 'red'
232
233
  : stats.usagePercent > 60
233
234
  ? 'yellow'
@@ -235,6 +236,6 @@ const ContextStatsOverlay = forwardRef(function ContextStatsOverlay({ isVisible,
235
236
  .sort((a, b) => b.tokens - a.tokens)
236
237
  .map((tool, idx, arr) => (_jsxs(Text, { color: "gray", dimColor: true, children: [idx === arr.length - 1 ? '└─' : '├─', ' ', _jsx(Text, { color: "yellow", dimColor: true, children: tool.name }), ": ", formatTokens(tool.tokens), " (", pct(tool.tokens), ")"] }, tool.name)))) })), renderRow(2, 'messages', 'Messages', stats.breakdown.messages, false), renderRow(3, 'freeSpace', 'Free space', freeTokens, false), renderRow(4, 'autoCompactBuffer', bufferPercent > 0
237
238
  ? `Auto compact buffer (${bufferPercent}%)`
238
- : 'Auto compact buffer', autoCompactBuffer, true)] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { color: "gray", children: ["Messages: ", stats.filteredMessageCount, " visible (", stats.messageCount, " total)"] }), stats.prunedToolCount > 0 && (_jsxs(Text, { color: "yellow", children: ["\uD83D\uDDD1\uFE0F ", stats.prunedToolCount, " tool output(s) pruned"] })), stats.compactionCount > 0 && (_jsxs(Text, { color: "blue", children: ["\uD83D\uDCE6 Compacted ", stats.compactionCount, " time", stats.compactionCount > 1 ? 's' : ''] })), stats.usagePercent > 100 && (_jsx(Text, { color: "yellow", children: "\uD83D\uDCA1 Use /compact to manually compact, or send a message to trigger auto-compaction" }))] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "\u2191\u2193: navigate | Enter: expand/collapse | Esc: close" }) })] }));
239
+ : 'Auto compact buffer', autoCompactBuffer, true)] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { color: "gray", children: ["Messages: ", stats.filteredMessageCount, " visible (", stats.messageCount, " total)"] }), stats.prunedToolCount > 0 && (_jsxs(Text, { color: "yellow", children: ["\uD83D\uDDD1\uFE0F ", stats.prunedToolCount, " tool output(s) pruned"] })), stats.hasSummary && (_jsx(Text, { color: "blue", children: "\uD83D\uDCE6 Context has been compacted (summary present)" })), stats.usagePercent > 100 && (_jsx(Text, { color: "yellow", children: "\uD83D\uDCA1 Use /compact to manually compact, or send a message to trigger auto-compaction" }))] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "\u2191\u2193: navigate | Enter: expand/collapse | Esc: close" }) })] }));
239
240
  });
240
241
  export default ContextStatsOverlay;
@@ -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"}