dexto 1.5.8 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/README.md +3 -3
  2. package/dist/agents/agent-template.yml +2 -2
  3. package/dist/agents/coding-agent/README.md +10 -10
  4. package/dist/agents/coding-agent/coding-agent.yml +84 -83
  5. package/dist/agents/default-agent.yml +32 -47
  6. package/dist/agents/explore-agent/explore-agent.yml +3 -6
  7. package/dist/agents/image-editor-agent/image-editor-agent.yml +1 -1
  8. package/dist/agents/nano-banana-agent/nano-banana-agent.yml +1 -1
  9. package/dist/agents/podcast-agent/podcast-agent.yml +1 -1
  10. package/dist/agents/product-name-researcher/product-name-researcher.yml +1 -1
  11. package/dist/agents/sora-video-agent/sora-video-agent.yml +4 -6
  12. package/dist/agents/triage-demo/triage-agent.yml +1 -1
  13. package/dist/analytics/events.d.ts +1 -1
  14. package/dist/analytics/events.d.ts.map +1 -1
  15. package/dist/api/mcp/tool-aggregation-handler.d.ts +2 -2
  16. package/dist/api/server-hono.d.ts +2 -2
  17. package/dist/api/server-hono.d.ts.map +1 -1
  18. package/dist/api/server-hono.js +37 -60
  19. package/dist/cli/approval/cli-approval-handler.d.ts +10 -3
  20. package/dist/cli/approval/cli-approval-handler.d.ts.map +1 -1
  21. package/dist/cli/approval/cli-approval-handler.js +1 -1
  22. package/dist/cli/assets/sounds/SOURCES.md +35 -0
  23. package/dist/cli/assets/sounds/boot.wav +0 -0
  24. package/dist/cli/assets/sounds/chime.wav +0 -0
  25. package/dist/cli/assets/sounds/coin.wav +0 -0
  26. package/dist/cli/assets/sounds/confirm.wav +0 -0
  27. package/dist/cli/assets/sounds/levelup.wav +0 -0
  28. package/dist/cli/assets/sounds/ping.wav +0 -0
  29. package/dist/cli/assets/sounds/powerup.wav +0 -0
  30. package/dist/cli/assets/sounds/startup.wav +0 -0
  31. package/dist/cli/assets/sounds/success.wav +0 -0
  32. package/dist/cli/assets/sounds/treasure.wav +0 -0
  33. package/dist/cli/assets/sounds/win.wav +0 -0
  34. package/dist/cli/commands/create-app.d.ts +1 -11
  35. package/dist/cli/commands/create-app.d.ts.map +1 -1
  36. package/dist/cli/commands/create-app.js +21 -545
  37. package/dist/cli/commands/create-image.d.ts.map +1 -1
  38. package/dist/cli/commands/create-image.js +54 -53
  39. package/dist/cli/commands/image.d.ts +52 -0
  40. package/dist/cli/commands/image.d.ts.map +1 -0
  41. package/dist/cli/commands/image.js +118 -0
  42. package/dist/cli/commands/index.d.ts +2 -1
  43. package/dist/cli/commands/index.d.ts.map +1 -1
  44. package/dist/cli/commands/index.js +3 -1
  45. package/dist/cli/commands/init-app.d.ts +4 -8
  46. package/dist/cli/commands/init-app.d.ts.map +1 -1
  47. package/dist/cli/commands/init-app.js +37 -161
  48. package/dist/cli/commands/interactive-commands/command-parser.d.ts +2 -0
  49. package/dist/cli/commands/interactive-commands/command-parser.d.ts.map +1 -1
  50. package/dist/cli/commands/interactive-commands/commands.d.ts +1 -1
  51. package/dist/cli/commands/interactive-commands/commands.d.ts.map +1 -1
  52. package/dist/cli/commands/interactive-commands/commands.js +2 -2
  53. package/dist/cli/commands/interactive-commands/exit-handler.d.ts +12 -0
  54. package/dist/cli/commands/interactive-commands/exit-handler.d.ts.map +1 -0
  55. package/dist/cli/commands/interactive-commands/exit-handler.js +20 -0
  56. package/dist/cli/commands/interactive-commands/exit-stats.d.ts +24 -0
  57. package/dist/cli/commands/interactive-commands/exit-stats.d.ts.map +1 -0
  58. package/dist/cli/commands/interactive-commands/exit-stats.js +17 -0
  59. package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
  60. package/dist/cli/commands/interactive-commands/general-commands.js +55 -5
  61. package/dist/cli/commands/interactive-commands/prompt-commands.d.ts.map +1 -1
  62. package/dist/cli/commands/interactive-commands/prompt-commands.js +14 -74
  63. package/dist/cli/commands/interactive-commands/session/index.d.ts +2 -1
  64. package/dist/cli/commands/interactive-commands/session/index.d.ts.map +1 -1
  65. package/dist/cli/commands/interactive-commands/session/index.js +2 -1
  66. package/dist/cli/commands/interactive-commands/session/session-commands.d.ts +2 -2
  67. package/dist/cli/commands/interactive-commands/session/session-commands.d.ts.map +1 -1
  68. package/dist/cli/commands/interactive-commands/session/session-commands.js +2 -4
  69. package/dist/cli/commands/interactive-commands/system/system-commands.d.ts +1 -13
  70. package/dist/cli/commands/interactive-commands/system/system-commands.d.ts.map +1 -1
  71. package/dist/cli/commands/interactive-commands/system/system-commands.js +52 -83
  72. package/dist/cli/commands/plugin.d.ts +4 -4
  73. package/dist/cli/commands/sync-agents.d.ts +2 -12
  74. package/dist/cli/commands/sync-agents.d.ts.map +1 -1
  75. package/dist/cli/commands/sync-agents.js +2 -50
  76. package/dist/cli/ink-cli/InkCLIRefactored.d.ts +7 -1
  77. package/dist/cli/ink-cli/InkCLIRefactored.d.ts.map +1 -1
  78. package/dist/cli/ink-cli/InkCLIRefactored.js +138 -27
  79. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts +2 -2
  80. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
  81. package/dist/cli/ink-cli/components/ApprovalPrompt.js +85 -30
  82. package/dist/cli/ink-cli/components/BackgroundTasksPanel.js +1 -1
  83. package/dist/cli/ink-cli/components/ElicitationForm.d.ts +5 -3
  84. package/dist/cli/ink-cli/components/ElicitationForm.d.ts.map +1 -1
  85. package/dist/cli/ink-cli/components/ElicitationForm.js +414 -180
  86. package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
  87. package/dist/cli/ink-cli/components/Footer.js +1 -2
  88. package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
  89. package/dist/cli/ink-cli/components/ResourceAutocomplete.js +20 -11
  90. package/dist/cli/ink-cli/components/SlashCommandAutocomplete.d.ts.map +1 -1
  91. package/dist/cli/ink-cli/components/SlashCommandAutocomplete.js +47 -67
  92. package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
  93. package/dist/cli/ink-cli/components/StatusBar.js +20 -10
  94. package/dist/cli/ink-cli/components/TodoPanel.js +1 -1
  95. package/dist/cli/ink-cli/components/base/BaseSelector.d.ts +2 -1
  96. package/dist/cli/ink-cli/components/base/BaseSelector.d.ts.map +1 -1
  97. package/dist/cli/ink-cli/components/base/BaseSelector.js +37 -27
  98. package/dist/cli/ink-cli/components/chat/Header.d.ts.map +1 -1
  99. package/dist/cli/ink-cli/components/chat/Header.js +1 -1
  100. package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
  101. package/dist/cli/ink-cli/components/chat/MessageItem.js +3 -1
  102. package/dist/cli/ink-cli/components/chat/ToolIcon.d.ts.map +1 -1
  103. package/dist/cli/ink-cli/components/chat/ToolIcon.js +5 -15
  104. package/dist/cli/ink-cli/components/chat/styled-boxes/ConfigBox.js +1 -1
  105. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.d.ts.map +1 -1
  106. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +1 -1
  107. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts +3 -1
  108. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
  109. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +5 -3
  110. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts +3 -1
  111. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
  112. package/dist/cli/ink-cli/components/modes/StaticCLI.js +10 -3
  113. package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.d.ts +13 -0
  114. package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.d.ts.map +1 -0
  115. package/dist/cli/ink-cli/components/overlays/CommandOutputOverlay.js +60 -0
  116. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +1 -1
  117. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
  118. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +213 -100
  119. package/dist/cli/ink-cli/components/overlays/PromptList.d.ts.map +1 -1
  120. package/dist/cli/ink-cli/components/overlays/PromptList.js +12 -16
  121. package/dist/cli/ink-cli/components/overlays/SoundsSelector.d.ts +21 -0
  122. package/dist/cli/ink-cli/components/overlays/SoundsSelector.d.ts.map +1 -0
  123. package/dist/cli/ink-cli/components/overlays/SoundsSelector.js +566 -0
  124. package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts +1 -1
  125. package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts.map +1 -1
  126. package/dist/cli/ink-cli/components/overlays/ToolBrowser.js +100 -45
  127. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts.map +1 -1
  128. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.js +8 -13
  129. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts +3 -3
  130. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts.map +1 -1
  131. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.js +6 -5
  132. package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts +3 -1
  133. package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts.map +1 -1
  134. package/dist/cli/ink-cli/components/renderers/FileRenderer.js +18 -7
  135. package/dist/cli/ink-cli/components/renderers/ShellRenderer.d.ts.map +1 -1
  136. package/dist/cli/ink-cli/components/renderers/ShellRenderer.js +7 -17
  137. package/dist/cli/ink-cli/components/renderers/index.d.ts.map +1 -1
  138. package/dist/cli/ink-cli/components/renderers/index.js +1 -1
  139. package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.d.ts +7 -0
  140. package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.d.ts.map +1 -0
  141. package/dist/cli/ink-cli/components/shared/FocusOverlayFrame.js +8 -0
  142. package/dist/cli/ink-cli/components/shared/HintBar.d.ts +6 -0
  143. package/dist/cli/ink-cli/components/shared/HintBar.d.ts.map +1 -0
  144. package/dist/cli/ink-cli/components/shared/HintBar.js +6 -0
  145. package/dist/cli/ink-cli/constants/spinnerFrames.d.ts +2 -0
  146. package/dist/cli/ink-cli/constants/spinnerFrames.d.ts.map +1 -0
  147. package/dist/cli/ink-cli/constants/spinnerFrames.js +1 -0
  148. package/dist/cli/ink-cli/constants/tips.d.ts.map +1 -1
  149. package/dist/cli/ink-cli/constants/tips.js +2 -1
  150. package/dist/cli/ink-cli/containers/InputContainer.d.ts +4 -0
  151. package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
  152. package/dist/cli/ink-cli/containers/InputContainer.js +47 -21
  153. package/dist/cli/ink-cli/containers/OverlayContainer.d.ts +2 -0
  154. package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
  155. package/dist/cli/ink-cli/containers/OverlayContainer.js +101 -40
  156. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts.map +1 -1
  157. package/dist/cli/ink-cli/hooks/useAgentEvents.js +15 -16
  158. package/dist/cli/ink-cli/hooks/useAnimationTick.d.ts +11 -0
  159. package/dist/cli/ink-cli/hooks/useAnimationTick.d.ts.map +1 -0
  160. package/dist/cli/ink-cli/hooks/useAnimationTick.js +54 -0
  161. package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
  162. package/dist/cli/ink-cli/hooks/useCLIState.js +1 -0
  163. package/dist/cli/ink-cli/hooks/useTokenCounter.d.ts.map +1 -1
  164. package/dist/cli/ink-cli/hooks/useTokenCounter.js +7 -4
  165. package/dist/cli/ink-cli/services/CommandService.d.ts +1 -1
  166. package/dist/cli/ink-cli/services/CommandService.d.ts.map +1 -1
  167. package/dist/cli/ink-cli/services/CommandService.js +2 -2
  168. package/dist/cli/ink-cli/services/processStream.d.ts +2 -2
  169. package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
  170. package/dist/cli/ink-cli/services/processStream.js +27 -19
  171. package/dist/cli/ink-cli/state/initialState.d.ts.map +1 -1
  172. package/dist/cli/ink-cli/state/initialState.js +1 -0
  173. package/dist/cli/ink-cli/state/types.d.ts +15 -3
  174. package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
  175. package/dist/cli/ink-cli/utils/commandOverlays.d.ts.map +1 -1
  176. package/dist/cli/ink-cli/utils/commandOverlays.js +1 -0
  177. package/dist/cli/ink-cli/utils/elicitationSchema.d.ts +11 -0
  178. package/dist/cli/ink-cli/utils/elicitationSchema.d.ts.map +1 -0
  179. package/dist/cli/ink-cli/utils/elicitationSchema.js +80 -0
  180. package/dist/cli/ink-cli/utils/index.d.ts +1 -1
  181. package/dist/cli/ink-cli/utils/index.d.ts.map +1 -1
  182. package/dist/cli/ink-cli/utils/index.js +1 -1
  183. package/dist/cli/ink-cli/utils/messageFormatting.d.ts +10 -19
  184. package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
  185. package/dist/cli/ink-cli/utils/messageFormatting.js +43 -262
  186. package/dist/cli/ink-cli/utils/overlayPresentation.d.ts +19 -0
  187. package/dist/cli/ink-cli/utils/overlayPresentation.d.ts.map +1 -0
  188. package/dist/cli/ink-cli/utils/overlayPresentation.js +33 -0
  189. package/dist/cli/ink-cli/utils/overlaySizing.d.ts +19 -0
  190. package/dist/cli/ink-cli/utils/overlaySizing.d.ts.map +1 -0
  191. package/dist/cli/ink-cli/utils/overlaySizing.js +11 -0
  192. package/dist/cli/ink-cli/utils/soundNotification.d.ts +19 -13
  193. package/dist/cli/ink-cli/utils/soundNotification.d.ts.map +1 -1
  194. package/dist/cli/ink-cli/utils/soundNotification.js +120 -97
  195. package/dist/cli/ink-cli/utils/toolUtils.d.ts.map +1 -1
  196. package/dist/cli/ink-cli/utils/toolUtils.js +2 -9
  197. package/dist/cli/utils/config-validation.d.ts +11 -11
  198. package/dist/cli/utils/config-validation.d.ts.map +1 -1
  199. package/dist/cli/utils/config-validation.js +56 -290
  200. package/dist/cli/utils/image-store.d.ts +16 -0
  201. package/dist/cli/utils/image-store.d.ts.map +1 -0
  202. package/dist/cli/utils/image-store.js +289 -0
  203. package/dist/cli/utils/scaffolding-utils.d.ts +5 -0
  204. package/dist/cli/utils/scaffolding-utils.d.ts.map +1 -1
  205. package/dist/cli/utils/scaffolding-utils.js +46 -4
  206. package/dist/cli/utils/template-engine.d.ts +28 -16
  207. package/dist/cli/utils/template-engine.d.ts.map +1 -1
  208. package/dist/cli/utils/template-engine.js +339 -479
  209. package/dist/config/cli-overrides.d.ts +4 -3
  210. package/dist/config/cli-overrides.d.ts.map +1 -1
  211. package/dist/config/cli-overrides.js +7 -9
  212. package/dist/index-main.d.ts +2 -0
  213. package/dist/index-main.d.ts.map +1 -0
  214. package/dist/index-main.js +1554 -0
  215. package/dist/index.js +2 -1589
  216. package/dist/utils/session-logger-factory.d.ts +3 -0
  217. package/dist/utils/session-logger-factory.d.ts.map +1 -0
  218. package/dist/utils/session-logger-factory.js +34 -0
  219. package/dist/webui/assets/{index-Cz2z7NQ8.js → index-CKhumsZA.js} +231 -231
  220. package/dist/webui/index.html +1 -1
  221. package/package.json +11 -8
  222. package/dist/cli/cli-subscriber.d.ts +0 -45
  223. package/dist/cli/cli-subscriber.d.ts.map +0 -1
  224. package/dist/cli/cli-subscriber.js +0 -204
@@ -25,10 +25,17 @@ import { getStartupInfo } from './utils/messageFormatting.js';
25
25
  // Toggle this to switch between modes for testing
26
26
  //const USE_ALTERNATE_BUFFER = true;
27
27
  const USE_ALTERNATE_BUFFER = false;
28
+ function formatCost(c) {
29
+ if (c < 0.01)
30
+ return `$${c.toFixed(4)}`;
31
+ if (c < 1)
32
+ return `$${c.toFixed(3)}`;
33
+ return `$${c.toFixed(2)}`;
34
+ }
28
35
  /**
29
36
  * Inner component that wraps the mode-specific component with providers
30
37
  */
31
- function InkCLIInner({ agent, initialSessionId, startupInfo, soundService }) {
38
+ function InkCLIInner({ agent, initialSessionId, initialPrompt, startupInfo, soundService, configFilePath, }) {
32
39
  // Selection hint callback for alternate buffer mode
33
40
  const [, setSelectionHintShown] = useState(false);
34
41
  // Streaming mode - can be toggled via /stream command
@@ -37,10 +44,10 @@ function InkCLIInner({ agent, initialSessionId, startupInfo, soundService }) {
37
44
  setSelectionHintShown(true);
38
45
  }, []);
39
46
  if (USE_ALTERNATE_BUFFER) {
40
- return (_jsx(SoundProvider, { soundService: soundService, children: _jsx(ScrollProvider, { onSelectionAttempt: handleSelectionAttempt, children: _jsx(AlternateBufferCLI, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, onSelectionAttempt: handleSelectionAttempt, useStreaming: streaming }) }) }));
47
+ return (_jsx(SoundProvider, { soundService: soundService, children: _jsx(ScrollProvider, { onSelectionAttempt: handleSelectionAttempt, children: _jsx(AlternateBufferCLI, { agent: agent, initialSessionId: initialSessionId, initialPrompt: initialPrompt, startupInfo: startupInfo, onSelectionAttempt: handleSelectionAttempt, useStreaming: streaming, configFilePath: configFilePath }) }) }));
41
48
  }
42
49
  // Static mode - no ScrollProvider needed
43
- return (_jsx(SoundProvider, { soundService: soundService, children: _jsx(StaticCLI, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, useStreaming: streaming }) }));
50
+ return (_jsx(SoundProvider, { soundService: soundService, children: _jsx(StaticCLI, { agent: agent, initialSessionId: initialSessionId, initialPrompt: initialPrompt, startupInfo: startupInfo, useStreaming: streaming, configFilePath: configFilePath }) }));
44
51
  }
45
52
  /**
46
53
  * Modern CLI interface using React Ink
@@ -50,8 +57,8 @@ function InkCLIInner({ agent, initialSessionId, startupInfo, soundService }) {
50
57
  * - KeypressProvider for unified keyboard input
51
58
  * - MouseProvider (only in alternate buffer mode)
52
59
  */
53
- export function InkCLIRefactored({ agent, initialSessionId, startupInfo, soundService, }) {
54
- return (_jsx(ErrorBoundary, { children: _jsx(KeypressProvider, { children: _jsx(MouseProvider, { mouseEventsEnabled: USE_ALTERNATE_BUFFER, children: _jsx(InkCLIInner, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, soundService: soundService }) }) }) }));
60
+ export function InkCLIRefactored({ agent, initialSessionId, initialPrompt, startupInfo, soundService, configFilePath, }) {
61
+ return (_jsx(ErrorBoundary, { children: _jsx(KeypressProvider, { children: _jsx(MouseProvider, { mouseEventsEnabled: USE_ALTERNATE_BUFFER, children: _jsx(InkCLIInner, { agent: agent, initialSessionId: initialSessionId, initialPrompt: initialPrompt, startupInfo: startupInfo, soundService: soundService, configFilePath: configFilePath }) }) }) }));
55
62
  }
56
63
  /**
57
64
  * Start the modern Ink-based CLI
@@ -68,53 +75,157 @@ export async function startInkCliRefactored(agent, initialSessionId, options = {
68
75
  updateInfo: options.updateInfo,
69
76
  needsAgentSync: options.needsAgentSync,
70
77
  };
71
- // Initialize sound service from preferences
72
- const { SoundNotificationService } = await import('./utils/soundNotification.js');
73
- const { globalPreferencesExist, loadGlobalPreferences, agentPreferencesExist, loadAgentPreferences, } = await import('@dexto/agent-management');
78
+ // Load preferences helpers (non-fatal if unavailable)
79
+ let globalPreferencesExistFn = () => false;
80
+ let loadGlobalPreferencesFn = null;
81
+ let agentPreferencesExistFn = () => false;
82
+ let loadAgentPreferencesFn = null;
83
+ try {
84
+ const agentManagement = await import('@dexto/agent-management');
85
+ globalPreferencesExistFn = agentManagement.globalPreferencesExist;
86
+ loadGlobalPreferencesFn = agentManagement.loadGlobalPreferences;
87
+ agentPreferencesExistFn = agentManagement.agentPreferencesExist;
88
+ loadAgentPreferencesFn = agentManagement.loadAgentPreferences;
89
+ }
90
+ catch (error) {
91
+ agent.logger.debug(`Preferences module could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
92
+ }
74
93
  let soundService = null;
75
94
  // Initialize sound config with defaults (enabled by default even without preferences file)
76
95
  let soundConfig = {
77
96
  enabled: true,
97
+ onStartup: false,
98
+ startupSoundFile: undefined,
78
99
  onApprovalRequired: true,
100
+ approvalSoundFile: undefined,
79
101
  onTaskComplete: true,
102
+ completeSoundFile: undefined,
80
103
  };
81
- // Override with user preferences if they exist
82
- if (globalPreferencesExist()) {
83
- try {
84
- const preferences = await loadGlobalPreferences();
85
- soundConfig = {
86
- enabled: preferences.sounds?.enabled ?? soundConfig.enabled,
87
- onApprovalRequired: preferences.sounds?.onApprovalRequired ?? soundConfig.onApprovalRequired,
88
- onTaskComplete: preferences.sounds?.onTaskComplete ?? soundConfig.onTaskComplete,
89
- };
90
- }
91
- catch (error) {
92
- // Log at debug level to help troubleshoot sound configuration issues
93
- // Continue with default sounds - this is non-critical functionality
94
- agent.logger.debug(`Sound preferences could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
104
+ // Initialize sound service from preferences (non-fatal)
105
+ try {
106
+ const { SoundNotificationService: SoundNotificationServiceImpl } = await import('./utils/soundNotification.js');
107
+ // Override with user preferences if they exist
108
+ if (globalPreferencesExistFn() && loadGlobalPreferencesFn) {
109
+ try {
110
+ const preferences = await loadGlobalPreferencesFn();
111
+ soundConfig = {
112
+ enabled: preferences.sounds?.enabled ?? soundConfig.enabled,
113
+ onStartup: preferences.sounds?.onStartup ?? soundConfig.onStartup,
114
+ startupSoundFile: preferences.sounds?.startupSoundFile ?? soundConfig.startupSoundFile,
115
+ onApprovalRequired: preferences.sounds?.onApprovalRequired ?? soundConfig.onApprovalRequired,
116
+ approvalSoundFile: preferences.sounds?.approvalSoundFile ?? soundConfig.approvalSoundFile,
117
+ onTaskComplete: preferences.sounds?.onTaskComplete ?? soundConfig.onTaskComplete,
118
+ completeSoundFile: preferences.sounds?.completeSoundFile ?? soundConfig.completeSoundFile,
119
+ };
120
+ }
121
+ catch (error) {
122
+ // Continue with default sounds - this is non-critical functionality
123
+ agent.logger.debug(`Sound preferences could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
124
+ }
95
125
  }
126
+ // Always create the service so sound settings can be toggled at runtime (service gates playback by config)
127
+ soundService = new SoundNotificationServiceImpl(soundConfig);
128
+ soundService.playStartupSound();
96
129
  }
97
- if (soundConfig.enabled) {
98
- soundService = new SoundNotificationService(soundConfig);
130
+ catch (error) {
131
+ agent.logger.debug(`Sound initialization failed: ${error instanceof Error ? error.message : String(error)}`);
132
+ soundService = null;
99
133
  }
100
134
  // Initialize tool preferences (per-agent)
101
- if (agentPreferencesExist(agent.config.agentId)) {
135
+ if (agentPreferencesExistFn(agent.config.agentId) && loadAgentPreferencesFn) {
102
136
  try {
103
- const preferences = await loadAgentPreferences(agent.config.agentId);
137
+ const preferences = await loadAgentPreferencesFn(agent.config.agentId);
104
138
  agent.setGlobalDisabledTools(preferences.tools?.disabled ?? []);
105
139
  }
106
140
  catch (error) {
107
141
  agent.logger.debug(`Agent tool preferences could not be loaded: ${error instanceof Error ? error.message : String(error)}`);
108
142
  }
109
143
  }
110
- const inkApp = render(_jsx(InkCLIRefactored, { agent: agent, initialSessionId: initialSessionId, startupInfo: startupInfo, soundService: soundService }), {
144
+ // Import exit handler before render to avoid race condition
145
+ const { registerExitHandler } = await import('../commands/interactive-commands/exit-handler.js');
146
+ const inkApp = render(_jsx(InkCLIRefactored, { agent: agent, initialSessionId: initialSessionId, initialPrompt: options.initialPrompt, startupInfo: startupInfo, soundService: soundService, configFilePath: options.configFilePath ?? null }), {
111
147
  exitOnCtrlC: false,
112
148
  alternateBuffer: USE_ALTERNATE_BUFFER,
113
149
  // Incremental rendering works better with VirtualizedList
114
150
  // Static pattern doesn't need it (and may work better without)
115
151
  incrementalRendering: USE_ALTERNATE_BUFFER,
116
152
  });
153
+ // Register exit handler immediately after render (synchronous, before any await)
154
+ registerExitHandler(() => inkApp.unmount());
117
155
  await inkApp.waitUntilExit();
118
156
  // Disable bracketed paste mode to restore normal terminal behavior
119
157
  disableBracketedPaste();
158
+ // Display session stats if available (after Ink has unmounted)
159
+ const chalk = (await import('chalk')).default;
160
+ const { getExitStats, clearExitStats } = await import('../commands/interactive-commands/exit-stats.js');
161
+ const exitStats = getExitStats();
162
+ if (exitStats) {
163
+ // Add visual separation - clear space like Gemini CLI does
164
+ // This creates a clean slate showing only the exit command and summary
165
+ process.stdout.write('\n'.repeat(1));
166
+ process.stdout.write(chalk.bold.cyan('📊 Session Summary') + '\n');
167
+ process.stdout.write(chalk.dim('─'.repeat(50)) + '\n');
168
+ // Session ID
169
+ if (exitStats.sessionId) {
170
+ process.stdout.write(chalk.gray(` Session ID: ${exitStats.sessionId}`) + '\n');
171
+ }
172
+ // Duration
173
+ if (exitStats.duration) {
174
+ process.stdout.write(chalk.gray(` Duration: ${exitStats.duration}`) + '\n');
175
+ }
176
+ // Message count
177
+ if (exitStats.messageCount.total > 0) {
178
+ process.stdout.write(chalk.gray(` Messages: ${exitStats.messageCount.total} total (${exitStats.messageCount.user} user, ${exitStats.messageCount.assistant} assistant)`) + '\n');
179
+ }
180
+ // Multi-model breakdown (if multiple models were used)
181
+ if (exitStats.modelStats && exitStats.modelStats.length > 1) {
182
+ process.stdout.write(chalk.gray('\n Models Used:') + '\n');
183
+ for (const modelStat of exitStats.modelStats) {
184
+ const modelLabel = `${modelStat.model} (${modelStat.messageCount} msgs)`;
185
+ process.stdout.write(chalk.gray(` • ${modelLabel}`) + '\n');
186
+ // Detailed token breakdown per model
187
+ const tokens = modelStat.tokenUsage;
188
+ process.stdout.write(chalk.gray(` Input tokens: ${tokens.inputTokens.toLocaleString()}`) +
189
+ '\n');
190
+ process.stdout.write(chalk.gray(` Output tokens: ${tokens.outputTokens.toLocaleString()}`) + '\n');
191
+ process.stdout.write(chalk.gray(` Reasoning tokens: ${tokens.reasoningTokens.toLocaleString()}`) + '\n');
192
+ process.stdout.write(chalk.gray(` Cache read tokens: ${tokens.cacheReadTokens.toLocaleString()}`) + '\n');
193
+ process.stdout.write(chalk.gray(` Cache write tokens: ${tokens.cacheWriteTokens.toLocaleString()}`) + '\n');
194
+ process.stdout.write(chalk.gray(` Total tokens: ${tokens.totalTokens.toLocaleString()}`) +
195
+ '\n');
196
+ if (modelStat.estimatedCost !== undefined) {
197
+ process.stdout.write(chalk.gray(` Cost: ${formatCost(modelStat.estimatedCost)}`) + '\n');
198
+ }
199
+ }
200
+ }
201
+ // Token usage - label depends on whether multi-model was shown
202
+ if (exitStats.tokenUsage) {
203
+ const { inputTokens, outputTokens, reasoningTokens, cacheReadTokens, cacheWriteTokens, totalTokens, } = exitStats.tokenUsage;
204
+ // Calculate cache savings percentage
205
+ const totalInputWithCache = inputTokens + cacheReadTokens;
206
+ const cacheSavingsPercent = totalInputWithCache > 0
207
+ ? ((cacheReadTokens / totalInputWithCache) * 100).toFixed(1)
208
+ : '0.0';
209
+ const tokenSectionLabel = exitStats.modelStats && exitStats.modelStats.length > 1
210
+ ? '\n Total Token Usage:'
211
+ : '\n Token Usage:';
212
+ process.stdout.write(chalk.gray(tokenSectionLabel) + '\n');
213
+ process.stdout.write(chalk.gray(` Input tokens: ${inputTokens.toLocaleString()}`) + '\n');
214
+ process.stdout.write(chalk.gray(` Output tokens: ${outputTokens.toLocaleString()}`) + '\n');
215
+ process.stdout.write(chalk.gray(` Reasoning tokens: ${reasoningTokens.toLocaleString()}`) + '\n');
216
+ const cacheReadLabel = cacheReadTokens > 0
217
+ ? `${cacheReadTokens.toLocaleString()} (💰 ${cacheSavingsPercent}% savings)`
218
+ : cacheReadTokens.toLocaleString();
219
+ process.stdout.write(chalk.gray(` Cache read tokens: ${cacheReadLabel}`) + '\n');
220
+ process.stdout.write(chalk.gray(` Cache write tokens: ${cacheWriteTokens.toLocaleString()}`) + '\n');
221
+ process.stdout.write(chalk.gray(` Total tokens: ${totalTokens.toLocaleString()}`) + '\n');
222
+ }
223
+ // Estimated cost
224
+ if (exitStats.estimatedCost !== undefined) {
225
+ process.stdout.write(chalk.green(`\n Estimated Cost: ${formatCost(exitStats.estimatedCost)}`) + '\n');
226
+ }
227
+ clearExitStats();
228
+ }
229
+ process.stdout.write(chalk.dim('─'.repeat(50)) + '\n');
230
+ process.stdout.write('\n' + chalk.rgb(255, 165, 0)('Exiting Dexto CLI. Goodbye!') + '\n');
120
231
  }
@@ -17,7 +17,7 @@ export interface ApprovalPromptHandle {
17
17
  export interface ApprovalOptions {
18
18
  /** Remember this tool for the entire session (approves ALL uses) */
19
19
  rememberChoice?: boolean;
20
- /** Remember a specific command pattern for bash (e.g., "git *") */
20
+ /** Remember an approval pattern (e.g., "git *") */
21
21
  rememberPattern?: string;
22
22
  /** Form data for elicitation requests */
23
23
  formData?: Record<string, unknown>;
@@ -36,7 +36,7 @@ interface ApprovalPromptProps {
36
36
  * Compact approval prompt component that displays above the input area
37
37
  * Shows options based on approval type:
38
38
  * - Tool confirmation: Yes, Yes (Session), No
39
- * - Bash with patterns: Yes (once), pattern options, Yes (all bash), No
39
+ * - Tool with patterns: Yes (once), pattern options, Yes (session), No
40
40
  * - Elicitation: Form with input fields
41
41
  */
42
42
  export declare const ApprovalPrompt: React.ForwardRefExoticComponent<ApprovalPromptProps & React.RefAttributes<ApprovalPromptHandle>>;
@@ -1 +1 @@
1
- {"version":3,"file":"ApprovalPrompt.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/ApprovalPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAM5D,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,oEAAoE;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,gFAAgF;IAChF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,UAAU,mBAAmB;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAgBD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,kGAkY1B,CAAC"}
1
+ {"version":3,"file":"ApprovalPrompt.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/ApprovalPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAM5D,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,oEAAoE;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mDAAmD;IACnD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,gFAAgF;IAChF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,UAAU,mBAAmB;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAiBD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,kGAwe1B,CAAC"}
@@ -4,36 +4,71 @@ import { Box, Text } from 'ink';
4
4
  import { ElicitationForm } from './ElicitationForm.js';
5
5
  import { DiffPreview, CreateFilePreview } from './renderers/index.js';
6
6
  import { isEditWriteTool } from '../utils/toolUtils.js';
7
- import { formatToolHeader } from '../utils/messageFormatting.js';
7
+ import { formatPathForDisplay, formatToolHeader } from '../utils/messageFormatting.js';
8
8
  /**
9
9
  * Compact approval prompt component that displays above the input area
10
10
  * Shows options based on approval type:
11
11
  * - Tool confirmation: Yes, Yes (Session), No
12
- * - Bash with patterns: Yes (once), pattern options, Yes (all bash), No
12
+ * - Tool with patterns: Yes (once), pattern options, Yes (session), No
13
13
  * - Elicitation: Form with input fields
14
14
  */
15
15
  export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCancel }, ref) => {
16
16
  const isCommandConfirmation = approval.type === 'command_confirmation';
17
17
  const isElicitation = approval.type === 'elicitation';
18
18
  const isDirectoryAccess = approval.type === 'directory_access';
19
+ const directoryAccess = approval.metadata.directoryAccess;
20
+ const hasToolDirectoryAccess = approval.type === 'tool_confirmation' &&
21
+ directoryAccess !== undefined &&
22
+ typeof directoryAccess === 'object' &&
23
+ directoryAccess !== null;
24
+ const directoryAccessParentDir = hasToolDirectoryAccess && typeof directoryAccess.parentDir === 'string'
25
+ ? directoryAccess.parentDir
26
+ : null;
19
27
  // Extract tool metadata
20
28
  const toolName = approval.metadata.toolName;
21
29
  const toolArgs = approval.metadata.args || {};
30
+ const callDescriptionRaw = typeof approval.metadata.description === 'string'
31
+ ? approval.metadata.description
32
+ : undefined;
33
+ const callDescription = useMemo(() => {
34
+ if (!callDescriptionRaw)
35
+ return null;
36
+ const singleLine = callDescriptionRaw.replace(/\s+/g, ' ').trim();
37
+ if (!singleLine)
38
+ return null;
39
+ const maxLength = 120;
40
+ if (singleLine.length <= maxLength)
41
+ return singleLine;
42
+ return `${singleLine.slice(0, Math.max(0, maxLength - 1))}…`;
43
+ }, [callDescriptionRaw]);
22
44
  // Check if this is a plan_review tool (shows custom approval options)
23
- const isPlanReview = toolName === 'custom--plan_review' ||
24
- toolName === 'internal--plan_review' ||
25
- toolName === 'plan_review';
26
- // Extract suggested patterns for bash tools
45
+ const isPlanReview = toolName === 'plan_review';
46
+ // Extract suggested patterns for tools that support pattern-based approvals
27
47
  const suggestedPatterns = approval.metadata.suggestedPatterns ?? [];
28
- const hasBashPatterns = suggestedPatterns.length > 0;
48
+ const hasSuggestedPatterns = suggestedPatterns.length > 0;
29
49
  // Check if this is an edit/write file tool
30
50
  const isEditOrWriteTool = isEditWriteTool(toolName);
31
51
  // Format tool header using shared utility (same format as tool messages)
52
+ const presentationSnapshot = useMemo(() => {
53
+ const raw = approval.metadata
54
+ .presentationSnapshot;
55
+ if (typeof raw !== 'object' || raw === null) {
56
+ return undefined;
57
+ }
58
+ if (raw.version !== 1) {
59
+ return undefined;
60
+ }
61
+ return raw;
62
+ }, [approval.metadata]);
32
63
  const formattedTool = useMemo(() => {
33
64
  if (!toolName)
34
65
  return null;
35
- return formatToolHeader(toolName, toolArgs);
36
- }, [toolName, toolArgs]);
66
+ return formatToolHeader({
67
+ toolName,
68
+ args: toolArgs,
69
+ ...(presentationSnapshot !== undefined && { presentationSnapshot }),
70
+ });
71
+ }, [toolName, toolArgs, presentationSnapshot]);
37
72
  const [selectedIndex, setSelectedIndex] = useState(0);
38
73
  // State for plan review feedback input
39
74
  const [showFeedbackInput, setShowFeedbackInput] = useState(false);
@@ -50,8 +85,17 @@ export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCance
50
85
  options.push({ id: 'plan-approve-accept-edits', label: 'Approve + Accept All Edits' });
51
86
  // Third "option" is the feedback input (handled specially in render)
52
87
  }
53
- else if (hasBashPatterns) {
54
- // Bash tool with pattern suggestions
88
+ else if (hasToolDirectoryAccess) {
89
+ // Tool approval that includes directory access - offer session-scoped dir allow
90
+ const dirLabel = directoryAccessParentDir
91
+ ? ` ${formatPathForDisplay(directoryAccessParentDir)}`
92
+ : '';
93
+ options.push({ id: 'yes', label: 'Yes (once)' });
94
+ options.push({ id: 'yes-directory-session', label: `Yes, allow${dirLabel} (session)` });
95
+ options.push({ id: 'no', label: 'No' });
96
+ }
97
+ else if (hasSuggestedPatterns) {
98
+ // Tool with pattern suggestions
55
99
  options.push({ id: 'yes', label: 'Yes (once)' });
56
100
  suggestedPatterns.forEach((pattern, i) => {
57
101
  options.push({
@@ -59,7 +103,7 @@ export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCance
59
103
  label: `Yes, allow "${pattern}"`,
60
104
  });
61
105
  });
62
- options.push({ id: 'yes-session', label: 'Yes, allow all bash' });
106
+ options.push({ id: 'yes-session', label: 'Yes, allow this tool (session)' });
63
107
  options.push({ id: 'no', label: 'No' });
64
108
  }
65
109
  else if (isCommandConfirmation) {
@@ -70,7 +114,7 @@ export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCance
70
114
  else if (isDirectoryAccess) {
71
115
  // Directory access - offer session-scoped access
72
116
  const parentDir = approval.metadata.parentDir;
73
- const dirLabel = parentDir ? ` "${parentDir}"` : '';
117
+ const dirLabel = parentDir ? ` ${formatPathForDisplay(parentDir)}` : '';
74
118
  options.push({ id: 'yes', label: 'Yes (once)' });
75
119
  options.push({ id: 'yes-session', label: `Yes, allow${dirLabel} (session)` });
76
120
  options.push({ id: 'no', label: 'No' });
@@ -166,6 +210,9 @@ export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCance
166
210
  onApprove({ rememberChoice: true });
167
211
  }
168
212
  }
213
+ else if (option.id === 'yes-directory-session') {
214
+ onApprove({ rememberDirectory: true });
215
+ }
169
216
  else if (option.id === 'yes-accept-edits') {
170
217
  // Approve and enable "accept all edits" mode
171
218
  onApprove({ enableAcceptEditsMode: true });
@@ -201,6 +248,7 @@ export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCance
201
248
  isElicitation,
202
249
  isEditOrWriteTool,
203
250
  isDirectoryAccess,
251
+ hasToolDirectoryAccess,
204
252
  isPlanReview,
205
253
  options,
206
254
  suggestedPatterns,
@@ -222,26 +270,16 @@ export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCance
222
270
  if (!displayPreview)
223
271
  return null;
224
272
  switch (displayPreview.type) {
225
- case 'diff': {
226
- const isOverwrite = toolName === 'custom--write_file' ||
227
- toolName === 'internal--write_file' ||
228
- toolName === 'write_file';
229
- return (_jsx(DiffPreview, { data: displayPreview, headerType: isOverwrite ? 'overwrite' : 'edit' }));
230
- }
273
+ case 'diff':
274
+ return _jsx(DiffPreview, { data: displayPreview });
231
275
  case 'shell':
232
- // For shell preview, just show the command (no output yet)
233
- return (_jsxs(Box, { marginBottom: 1, flexDirection: "row", children: [_jsx(Text, { color: "gray", children: "$ " }), _jsx(Text, { color: "yellowBright", children: displayPreview.command }), displayPreview.isBackground && _jsx(Text, { color: "gray", children: " (background)" })] }));
276
+ // For shell preview, show the command + optional description (no output yet)
277
+ return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(Box, { marginBottom: 0, children: _jsx(Text, { color: "cyan", bold: true, children: displayPreview.title ?? 'Bash' }) }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: [displayPreview.command.split('\n').map((line, i) => (_jsxs(Text, { color: "yellowBright", wrap: "wrap", children: [i === 0 ? '$ ' : ' ', line] }, i))), displayPreview.isBackground && (_jsx(Text, { color: "gray", children: "(background)" }))] }), callDescription && (_jsx(Box, { marginTop: 0, children: _jsx(Text, { color: "gray", children: callDescription }) }))] }));
234
278
  case 'file':
235
- // Use enhanced file preview with full content for file creation
236
- if (displayPreview.operation === 'create' && displayPreview.content) {
279
+ // If content is provided, show the full content (create/review flows)
280
+ if (displayPreview.content) {
237
281
  return _jsx(CreateFilePreview, { data: displayPreview });
238
282
  }
239
- // For plan_review (read operation with content), show full content for review
240
- if (displayPreview.operation === 'read' &&
241
- displayPreview.content &&
242
- isPlanReview) {
243
- return _jsx(CreateFilePreview, { data: displayPreview, header: "Review plan" });
244
- }
245
283
  // Fallback for other file operations
246
284
  return (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "gray", children: [displayPreview.operation === 'read' &&
247
285
  `Read ${displayPreview.lineCount ?? 'file'} lines`, displayPreview.operation === 'write' &&
@@ -255,7 +293,24 @@ export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCance
255
293
  const directoryPath = approval.metadata.path;
256
294
  const parentDir = approval.metadata.parentDir;
257
295
  const operation = approval.metadata.operation;
258
- return (_jsxs(Box, { paddingX: 0, paddingY: 0, flexDirection: "column", children: [_jsx(Box, { flexDirection: "column", marginBottom: 0, children: isDirectoryAccess ? (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellowBright", bold: true, children: ["\uD83D\uDD10 Directory Access:", ' '] }), _jsx(Text, { color: "cyan", children: parentDir || directoryPath })] }), _jsxs(Box, { flexDirection: "row", marginTop: 0, children: [_jsx(Text, { color: "gray", children: ' ' }), _jsxs(Text, { color: "gray", children: [formattedTool ? `"${formattedTool.displayName}"` : 'Tool', ' ', "wants to ", operation || 'access', " files outside working directory"] })] })] })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellowBright", bold: true, children: ["\uD83D\uDD10 Approval:", ' '] }), formattedTool && _jsx(Text, { color: "cyan", children: formattedTool.header })] }), isCommandConfirmation && command && (_jsxs(Box, { flexDirection: "row", marginTop: 0, children: [_jsx(Text, { color: "gray", children: ' Command: ' }), _jsx(Text, { color: "red", children: command })] }))] })) }), renderPreview(), _jsxs(Box, { flexDirection: "column", marginTop: 0, children: [options.map((option, index) => {
296
+ const directoryAccessTitle = !isDirectoryAccess
297
+ ? null
298
+ : operation === 'read'
299
+ ? 'Read file'
300
+ : operation === 'write'
301
+ ? 'Write file'
302
+ : operation === 'edit'
303
+ ? 'Edit file'
304
+ : 'Directory access';
305
+ const directoryAccessToolHeader = !isDirectoryAccess || !toolName
306
+ ? null
307
+ : formatToolHeader({
308
+ toolName,
309
+ args: (directoryPath ?? parentDir) ? { path: directoryPath ?? parentDir } : {},
310
+ ...(presentationSnapshot !== undefined && { presentationSnapshot }),
311
+ }).header;
312
+ const showHeaderBlock = isDirectoryAccess || isCommandConfirmation || !displayPreview;
313
+ return (_jsxs(Box, { paddingX: 0, paddingY: 0, flexDirection: "column", children: [showHeaderBlock && (_jsx(Box, { flexDirection: "column", marginBottom: 0, children: isDirectoryAccess ? (_jsxs(_Fragment, { children: [_jsx(Box, { marginBottom: 0, children: _jsx(Text, { color: "cyan", bold: true, children: directoryAccessTitle ?? 'Directory access' }) }), directoryAccessToolHeader && (_jsx(Box, { marginBottom: 0, children: _jsx(Text, { wrap: "wrap", children: directoryAccessToolHeader }) }))] })) : isCommandConfirmation ? (_jsxs(_Fragment, { children: [_jsx(Box, { flexDirection: "row", children: _jsxs(Text, { color: "yellowBright", bold: true, children: ["Confirm command:", ' '] }) }), command && (_jsx(Box, { flexDirection: "column", marginTop: 0, children: _jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: "gray", paddingX: 1, children: command.split('\n').map((line, i) => (_jsx(Text, { color: "red", wrap: "wrap", children: line }, i))) }) }))] })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellowBright", bold: true, children: ["Confirm:", ' '] }), formattedTool && (_jsx(Text, { color: "cyan", children: formattedTool.header }))] }), callDescription && (_jsxs(Box, { flexDirection: "row", marginTop: 0, children: [_jsx(Text, { color: "gray", children: ' ' }), _jsx(Text, { color: "gray", children: callDescription })] }))] })) })), renderPreview(), _jsxs(Box, { flexDirection: "column", marginTop: 0, children: [options.map((option, index) => {
259
314
  const isSelected = index === selectedIndex;
260
315
  const isNo = option.id === 'no';
261
316
  return (_jsx(Box, { children: isSelected ? (_jsxs(Text, { color: isNo ? 'red' : 'green', bold: true, children: [' ▶ ', option.label] })) : (_jsxs(Text, { color: "gray", children: [' ', option.label] })) }, option.id));
@@ -40,7 +40,7 @@ export function BackgroundTasksPanel({ tasks, isExpanded, isProcessing = false,
40
40
  const statusWidth = 10;
41
41
  const idWidth = 14;
42
42
  const descWidth = 48;
43
- return (_jsxs(Box, { flexDirection: "column", borderStyle: isProcessing ? undefined : 'round', borderColor: "gray", paddingX: 1, marginX: 1, marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: headerText }), _jsxs(Text, { color: "gray", dimColor: true, children: [' ', "\u00B7 ctrl+b to hide tasks"] })] }), _jsx(Box, { children: _jsxs(Text, { color: "gray", children: [padText('status', statusWidth), padText('task id', idWidth), padText('description', descWidth)] }) }), sortedTasks.map((task) => {
43
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: isProcessing ? undefined : 'round', borderColor: "gray", paddingX: 1, marginX: 1, marginBottom: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: headerText }), _jsxs(Text, { color: "gray", dimColor: true, children: [' ', "\u00B7 ctrl+b to hide bg tasks"] })] }), _jsx(Box, { children: _jsxs(Text, { color: "gray", children: [padText('status', statusWidth), padText('task id', idWidth), padText('description', descWidth)] }) }), sortedTasks.map((task) => {
44
44
  const status = formatStatus(task.status);
45
45
  const desc = task.description ?? '';
46
46
  return (_jsx(Box, { children: _jsxs(Text, { color: task.status === 'running' ? 'yellow' : 'gray', children: [padText(status, statusWidth), padText(task.taskId, idWidth), padText(desc, descWidth)] }) }, task.taskId));
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * ElicitationForm Component
3
- * Renders a form for ask_user/elicitation requests in the CLI
4
- * Supports string, number, boolean, and enum field types
3
+ * Renders a form for ask_user/elicitation requests in the CLI.
4
+ *
5
+ * Uses a wizard flow (one question at a time) to avoid huge modals and improve
6
+ * usability on small terminals.
5
7
  */
6
8
  import React from 'react';
7
- import type { Key } from '../hooks/useInputOrchestrator.js';
8
9
  import type { ElicitationMetadata } from '@dexto/core';
10
+ import type { Key } from '../hooks/useInputOrchestrator.js';
9
11
  export interface ElicitationFormHandle {
10
12
  handleInput: (input: string, key: Key) => boolean;
11
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ElicitationForm.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/ElicitationForm.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAA0E,MAAM,OAAO,CAAC;AAE/F,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,WAAW,qBAAqB;IAClC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED,UAAU,oBAAoB;IAC1B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACtD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAWD;;GAEG;AACH,eAAO,MAAM,eAAe,oGAygB3B,CAAC"}
1
+ {"version":3,"file":"ElicitationForm.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/ElicitationForm.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAA0E,MAAM,OAAO,CAAC;AAG/F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAI5D,MAAM,WAAW,qBAAqB;IAClC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED,UAAU,oBAAoB;IAC1B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IACtD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAkBD;;GAEG;AACH,eAAO,MAAM,eAAe,oGA6uB3B,CAAC"}