dexto 1.3.0 → 1.5.0

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 (494) hide show
  1. package/README.md +87 -22
  2. package/dist/agents/agent-registry.json +9 -0
  3. package/dist/agents/agent-template.yml +2 -2
  4. package/dist/agents/coding-agent/coding-agent.yml +27 -16
  5. package/dist/agents/database-agent/database-agent.yml +2 -2
  6. package/dist/agents/default-agent.yml +9 -7
  7. package/dist/agents/github-agent/github-agent.yml +2 -2
  8. package/dist/agents/product-name-researcher/product-name-researcher.yml +2 -2
  9. package/dist/agents/talk2pdf-agent/talk2pdf-agent.yml +2 -2
  10. package/dist/analytics/events.d.ts +13 -6
  11. package/dist/analytics/events.d.ts.map +1 -1
  12. package/dist/analytics/index.d.ts +1 -1
  13. package/dist/analytics/index.d.ts.map +1 -1
  14. package/dist/analytics/index.js +6 -2
  15. package/dist/api/server-hono.d.ts.map +1 -1
  16. package/dist/api/server-hono.js +65 -9
  17. package/dist/cli/cli-subscriber.d.ts +4 -0
  18. package/dist/cli/cli-subscriber.d.ts.map +1 -1
  19. package/dist/cli/cli-subscriber.js +47 -3
  20. package/dist/cli/commands/create-app.d.ts +16 -14
  21. package/dist/cli/commands/create-app.d.ts.map +1 -1
  22. package/dist/cli/commands/create-app.js +626 -102
  23. package/dist/cli/commands/create-image.d.ts +7 -0
  24. package/dist/cli/commands/create-image.d.ts.map +1 -0
  25. package/dist/cli/commands/create-image.js +201 -0
  26. package/dist/cli/commands/helpers/formatters.d.ts.map +1 -1
  27. package/dist/cli/commands/helpers/formatters.js +9 -8
  28. package/dist/cli/commands/index.d.ts +2 -1
  29. package/dist/cli/commands/index.d.ts.map +1 -1
  30. package/dist/cli/commands/index.js +2 -1
  31. package/dist/cli/commands/init-app.js +7 -7
  32. package/dist/cli/commands/install.d.ts +0 -3
  33. package/dist/cli/commands/install.d.ts.map +1 -1
  34. package/dist/cli/commands/install.js +19 -70
  35. package/dist/cli/commands/interactive-commands/command-parser.d.ts +17 -14
  36. package/dist/cli/commands/interactive-commands/command-parser.d.ts.map +1 -1
  37. package/dist/cli/commands/interactive-commands/command-parser.js +7 -22
  38. package/dist/cli/commands/interactive-commands/commands.d.ts +4 -4
  39. package/dist/cli/commands/interactive-commands/commands.d.ts.map +1 -1
  40. package/dist/cli/commands/interactive-commands/commands.js +34 -42
  41. package/dist/cli/commands/interactive-commands/documentation-commands.d.ts.map +1 -1
  42. package/dist/cli/commands/interactive-commands/documentation-commands.js +4 -7
  43. package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
  44. package/dist/cli/commands/interactive-commands/general-commands.js +159 -117
  45. package/dist/cli/commands/interactive-commands/mcp/index.d.ts +9 -3
  46. package/dist/cli/commands/interactive-commands/mcp/index.d.ts.map +1 -1
  47. package/dist/cli/commands/interactive-commands/mcp/index.js +18 -3
  48. package/dist/cli/commands/interactive-commands/model/index.d.ts +8 -6
  49. package/dist/cli/commands/interactive-commands/model/index.d.ts.map +1 -1
  50. package/dist/cli/commands/interactive-commands/model/index.js +18 -6
  51. package/dist/cli/commands/interactive-commands/prompt-commands.d.ts +3 -2
  52. package/dist/cli/commands/interactive-commands/prompt-commands.d.ts.map +1 -1
  53. package/dist/cli/commands/interactive-commands/prompt-commands.js +77 -60
  54. package/dist/cli/commands/interactive-commands/session/index.d.ts +7 -12
  55. package/dist/cli/commands/interactive-commands/session/index.d.ts.map +1 -1
  56. package/dist/cli/commands/interactive-commands/session/index.js +7 -14
  57. package/dist/cli/commands/interactive-commands/session/session-commands.d.ts +10 -24
  58. package/dist/cli/commands/interactive-commands/session/session-commands.d.ts.map +1 -1
  59. package/dist/cli/commands/interactive-commands/session/session-commands.js +16 -371
  60. package/dist/cli/commands/interactive-commands/system/system-commands.d.ts +1 -0
  61. package/dist/cli/commands/interactive-commands/system/system-commands.d.ts.map +1 -1
  62. package/dist/cli/commands/interactive-commands/system/system-commands.js +106 -77
  63. package/dist/cli/commands/interactive-commands/tool-commands.d.ts +1 -1
  64. package/dist/cli/commands/interactive-commands/tool-commands.d.ts.map +1 -1
  65. package/dist/cli/commands/interactive-commands/tool-commands.js +5 -62
  66. package/dist/cli/commands/interactive-commands/utils/command-output.d.ts +13 -17
  67. package/dist/cli/commands/interactive-commands/utils/command-output.d.ts.map +1 -1
  68. package/dist/cli/commands/interactive-commands/utils/command-output.js +18 -37
  69. package/dist/cli/commands/list-agents.d.ts +2 -2
  70. package/dist/cli/commands/list-agents.d.ts.map +1 -1
  71. package/dist/cli/commands/list-agents.js +38 -34
  72. package/dist/cli/commands/session-commands.js +16 -16
  73. package/dist/cli/commands/setup.d.ts +13 -5
  74. package/dist/cli/commands/setup.d.ts.map +1 -1
  75. package/dist/cli/commands/setup.js +860 -65
  76. package/dist/cli/commands/uninstall.d.ts.map +1 -1
  77. package/dist/cli/commands/uninstall.js +4 -6
  78. package/dist/cli/commands/which.d.ts.map +1 -1
  79. package/dist/cli/commands/which.js +18 -4
  80. package/dist/cli/ink-cli/InkCLIRefactored.d.ts +9 -22
  81. package/dist/cli/ink-cli/InkCLIRefactored.d.ts.map +1 -1
  82. package/dist/cli/ink-cli/InkCLIRefactored.js +50 -133
  83. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts +26 -3
  84. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
  85. package/dist/cli/ink-cli/components/ApprovalPrompt.js +182 -45
  86. package/dist/cli/ink-cli/components/CustomInput.js +1 -1
  87. package/dist/cli/ink-cli/components/EditableMultiLineInput.js +4 -4
  88. package/dist/cli/ink-cli/components/ElicitationForm.d.ts +22 -0
  89. package/dist/cli/ink-cli/components/ElicitationForm.d.ts.map +1 -0
  90. package/dist/cli/ink-cli/components/ElicitationForm.js +358 -0
  91. package/dist/cli/ink-cli/components/ErrorBoundary.d.ts.map +1 -1
  92. package/dist/cli/ink-cli/components/ErrorBoundary.js +1 -1
  93. package/dist/cli/ink-cli/components/Footer.d.ts +16 -0
  94. package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -0
  95. package/dist/cli/ink-cli/components/Footer.js +27 -0
  96. package/dist/cli/ink-cli/components/HistorySearchBar.d.ts +17 -0
  97. package/dist/cli/ink-cli/components/HistorySearchBar.d.ts.map +1 -0
  98. package/dist/cli/ink-cli/components/HistorySearchBar.js +8 -0
  99. package/dist/cli/ink-cli/components/MultiLineInput.d.ts.map +1 -1
  100. package/dist/cli/ink-cli/components/MultiLineInput.js +3 -3
  101. package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts +15 -2
  102. package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
  103. package/dist/cli/ink-cli/components/ResourceAutocomplete.js +126 -82
  104. package/dist/cli/ink-cli/components/SlashCommandAutocomplete.d.ts +15 -2
  105. package/dist/cli/ink-cli/components/SlashCommandAutocomplete.d.ts.map +1 -1
  106. package/dist/cli/ink-cli/components/SlashCommandAutocomplete.js +228 -122
  107. package/dist/cli/ink-cli/components/StatusBar.d.ts +15 -2
  108. package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
  109. package/dist/cli/ink-cli/components/StatusBar.js +50 -10
  110. package/dist/cli/ink-cli/components/TextBufferInput.d.ts +52 -0
  111. package/dist/cli/ink-cli/components/TextBufferInput.d.ts.map +1 -0
  112. package/dist/cli/ink-cli/components/TextBufferInput.js +471 -0
  113. package/dist/cli/ink-cli/components/base/BaseAutocomplete.js +4 -4
  114. package/dist/cli/ink-cli/components/base/BaseSelector.d.ts +11 -1
  115. package/dist/cli/ink-cli/components/base/BaseSelector.d.ts.map +1 -1
  116. package/dist/cli/ink-cli/components/base/BaseSelector.js +90 -49
  117. package/dist/cli/ink-cli/components/chat/Footer.js +1 -1
  118. package/dist/cli/ink-cli/components/chat/Header.d.ts +1 -0
  119. package/dist/cli/ink-cli/components/chat/Header.d.ts.map +1 -1
  120. package/dist/cli/ink-cli/components/chat/Header.js +6 -3
  121. package/dist/cli/ink-cli/components/chat/MessageItem.d.ts +3 -0
  122. package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
  123. package/dist/cli/ink-cli/components/chat/MessageItem.js +95 -9
  124. package/dist/cli/ink-cli/components/chat/MessageList.js +1 -1
  125. package/dist/cli/ink-cli/components/chat/QueuedMessagesDisplay.d.ts +16 -0
  126. package/dist/cli/ink-cli/components/chat/QueuedMessagesDisplay.d.ts.map +1 -0
  127. package/dist/cli/ink-cli/components/chat/QueuedMessagesDisplay.js +27 -0
  128. package/dist/cli/ink-cli/components/chat/ToolIcon.d.ts +5 -3
  129. package/dist/cli/ink-cli/components/chat/ToolIcon.d.ts.map +1 -1
  130. package/dist/cli/ink-cli/components/chat/ToolIcon.js +21 -7
  131. package/dist/cli/ink-cli/components/chat/styled-boxes/ConfigBox.d.ts +10 -0
  132. package/dist/cli/ink-cli/components/chat/styled-boxes/ConfigBox.d.ts.map +1 -0
  133. package/dist/cli/ink-cli/components/chat/styled-boxes/ConfigBox.js +6 -0
  134. package/dist/cli/ink-cli/components/chat/styled-boxes/HelpBox.d.ts +10 -0
  135. package/dist/cli/ink-cli/components/chat/styled-boxes/HelpBox.d.ts.map +1 -0
  136. package/dist/cli/ink-cli/components/chat/styled-boxes/HelpBox.js +15 -0
  137. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.d.ts +10 -0
  138. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.d.ts.map +1 -0
  139. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +9 -0
  140. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionHistoryBox.d.ts +10 -0
  141. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionHistoryBox.d.ts.map +1 -0
  142. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionHistoryBox.js +37 -0
  143. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionListBox.d.ts +10 -0
  144. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionListBox.d.ts.map +1 -0
  145. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionListBox.js +9 -0
  146. package/dist/cli/ink-cli/components/chat/styled-boxes/ShortcutsBox.d.ts +10 -0
  147. package/dist/cli/ink-cli/components/chat/styled-boxes/ShortcutsBox.d.ts.map +1 -0
  148. package/dist/cli/ink-cli/components/chat/styled-boxes/ShortcutsBox.js +6 -0
  149. package/dist/cli/ink-cli/components/chat/styled-boxes/StatsBox.d.ts +10 -0
  150. package/dist/cli/ink-cli/components/chat/styled-boxes/StatsBox.d.ts.map +1 -0
  151. package/dist/cli/ink-cli/components/chat/styled-boxes/StatsBox.js +29 -0
  152. package/dist/cli/ink-cli/components/chat/styled-boxes/StyledBox.d.ts +45 -0
  153. package/dist/cli/ink-cli/components/chat/styled-boxes/StyledBox.d.ts.map +1 -0
  154. package/dist/cli/ink-cli/components/chat/styled-boxes/StyledBox.js +38 -0
  155. package/dist/cli/ink-cli/components/chat/styled-boxes/SyspromptBox.d.ts +10 -0
  156. package/dist/cli/ink-cli/components/chat/styled-boxes/SyspromptBox.d.ts.map +1 -0
  157. package/dist/cli/ink-cli/components/chat/styled-boxes/SyspromptBox.js +6 -0
  158. package/dist/cli/ink-cli/components/chat/styled-boxes/index.d.ts +13 -0
  159. package/dist/cli/ink-cli/components/chat/styled-boxes/index.d.ts.map +1 -0
  160. package/dist/cli/ink-cli/components/chat/styled-boxes/index.js +12 -0
  161. package/dist/cli/ink-cli/components/input/InputArea.d.ts +36 -8
  162. package/dist/cli/ink-cli/components/input/InputArea.d.ts.map +1 -1
  163. package/dist/cli/ink-cli/components/input/InputArea.js +3 -3
  164. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts +25 -0
  165. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -0
  166. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +166 -0
  167. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts +27 -0
  168. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -0
  169. package/dist/cli/ink-cli/components/modes/StaticCLI.js +95 -0
  170. package/dist/cli/ink-cli/components/modes/index.d.ts +10 -0
  171. package/dist/cli/ink-cli/components/modes/index.d.ts.map +1 -0
  172. package/dist/cli/ink-cli/components/modes/index.js +9 -0
  173. package/dist/cli/ink-cli/components/overlays/ApiKeyInput.d.ts +26 -0
  174. package/dist/cli/ink-cli/components/overlays/ApiKeyInput.d.ts.map +1 -0
  175. package/dist/cli/ink-cli/components/overlays/ApiKeyInput.js +92 -0
  176. package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts +29 -0
  177. package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts.map +1 -0
  178. package/dist/cli/ink-cli/components/overlays/CustomModelWizard.js +286 -0
  179. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.d.ts +22 -0
  180. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.d.ts.map +1 -0
  181. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +59 -0
  182. package/dist/cli/ink-cli/components/overlays/McpAddChoice.d.ts +22 -0
  183. package/dist/cli/ink-cli/components/overlays/McpAddChoice.d.ts.map +1 -0
  184. package/dist/cli/ink-cli/components/overlays/McpAddChoice.js +59 -0
  185. package/dist/cli/ink-cli/components/overlays/McpAddSelector.d.ts +26 -0
  186. package/dist/cli/ink-cli/components/overlays/McpAddSelector.d.ts.map +1 -0
  187. package/dist/cli/ink-cli/components/overlays/McpAddSelector.js +73 -0
  188. package/dist/cli/ink-cli/components/overlays/McpCustomTypeSelector.d.ts +21 -0
  189. package/dist/cli/ink-cli/components/overlays/McpCustomTypeSelector.d.ts.map +1 -0
  190. package/dist/cli/ink-cli/components/overlays/McpCustomTypeSelector.js +51 -0
  191. package/dist/cli/ink-cli/components/overlays/McpCustomWizard.d.ts +29 -0
  192. package/dist/cli/ink-cli/components/overlays/McpCustomWizard.d.ts.map +1 -0
  193. package/dist/cli/ink-cli/components/overlays/McpCustomWizard.js +215 -0
  194. package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.d.ts +22 -0
  195. package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.d.ts.map +1 -0
  196. package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.js +74 -0
  197. package/dist/cli/ink-cli/components/overlays/McpSelector.d.ts +21 -0
  198. package/dist/cli/ink-cli/components/overlays/McpSelector.d.ts.map +1 -0
  199. package/dist/cli/ink-cli/components/overlays/McpSelector.js +52 -0
  200. package/dist/cli/ink-cli/components/overlays/McpServerActions.d.ts +28 -0
  201. package/dist/cli/ink-cli/components/overlays/McpServerActions.d.ts.map +1 -0
  202. package/dist/cli/ink-cli/components/overlays/McpServerActions.js +84 -0
  203. package/dist/cli/ink-cli/components/overlays/McpServerList.d.ts +29 -0
  204. package/dist/cli/ink-cli/components/overlays/McpServerList.d.ts.map +1 -0
  205. package/dist/cli/ink-cli/components/overlays/McpServerList.js +109 -0
  206. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts +15 -8
  207. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
  208. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +400 -23
  209. package/dist/cli/ink-cli/components/overlays/PromptAddChoice.d.ts +22 -0
  210. package/dist/cli/ink-cli/components/overlays/PromptAddChoice.d.ts.map +1 -0
  211. package/dist/cli/ink-cli/components/overlays/PromptAddChoice.js +52 -0
  212. package/dist/cli/ink-cli/components/overlays/PromptAddWizard.d.ts +29 -0
  213. package/dist/cli/ink-cli/components/overlays/PromptAddWizard.d.ts.map +1 -0
  214. package/dist/cli/ink-cli/components/overlays/PromptAddWizard.js +166 -0
  215. package/dist/cli/ink-cli/components/overlays/PromptDeleteSelector.d.ts +27 -0
  216. package/dist/cli/ink-cli/components/overlays/PromptDeleteSelector.d.ts.map +1 -0
  217. package/dist/cli/ink-cli/components/overlays/PromptDeleteSelector.js +119 -0
  218. package/dist/cli/ink-cli/components/overlays/PromptList.d.ts +33 -0
  219. package/dist/cli/ink-cli/components/overlays/PromptList.d.ts.map +1 -0
  220. package/dist/cli/ink-cli/components/overlays/PromptList.js +144 -0
  221. package/dist/cli/ink-cli/components/overlays/SearchOverlay.d.ts +23 -0
  222. package/dist/cli/ink-cli/components/overlays/SearchOverlay.d.ts.map +1 -0
  223. package/dist/cli/ink-cli/components/overlays/SearchOverlay.js +189 -0
  224. package/dist/cli/ink-cli/components/overlays/SessionSelectorRefactored.d.ts +7 -2
  225. package/dist/cli/ink-cli/components/overlays/SessionSelectorRefactored.d.ts.map +1 -1
  226. package/dist/cli/ink-cli/components/overlays/SessionSelectorRefactored.js +19 -5
  227. package/dist/cli/ink-cli/components/overlays/SessionSubcommandSelector.d.ts +21 -0
  228. package/dist/cli/ink-cli/components/overlays/SessionSubcommandSelector.d.ts.map +1 -0
  229. package/dist/cli/ink-cli/components/overlays/SessionSubcommandSelector.js +42 -0
  230. package/dist/cli/ink-cli/components/overlays/StreamSelector.d.ts +20 -0
  231. package/dist/cli/ink-cli/components/overlays/StreamSelector.d.ts.map +1 -0
  232. package/dist/cli/ink-cli/components/overlays/StreamSelector.js +58 -0
  233. package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts +25 -0
  234. package/dist/cli/ink-cli/components/overlays/ToolBrowser.d.ts.map +1 -0
  235. package/dist/cli/ink-cli/components/overlays/ToolBrowser.js +400 -0
  236. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts +25 -0
  237. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts.map +1 -0
  238. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.js +609 -0
  239. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.d.ts +15 -0
  240. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.d.ts.map +1 -0
  241. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.js +14 -0
  242. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts +33 -0
  243. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts.map +1 -0
  244. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.js +419 -0
  245. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.d.ts +25 -0
  246. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.d.ts.map +1 -0
  247. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.js +29 -0
  248. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.d.ts +17 -0
  249. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.d.ts.map +1 -0
  250. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.js +11 -0
  251. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.d.ts +20 -0
  252. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.d.ts.map +1 -0
  253. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.js +10 -0
  254. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.d.ts +30 -0
  255. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.d.ts.map +1 -0
  256. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.js +13 -0
  257. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.d.ts +8 -0
  258. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.d.ts.map +1 -0
  259. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.js +7 -0
  260. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts +79 -0
  261. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts.map +1 -0
  262. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.js +38 -0
  263. package/dist/cli/ink-cli/components/renderers/DiffRenderer.d.ts +21 -0
  264. package/dist/cli/ink-cli/components/renderers/DiffRenderer.d.ts.map +1 -0
  265. package/dist/cli/ink-cli/components/renderers/DiffRenderer.js +65 -0
  266. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts +28 -0
  267. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.d.ts.map +1 -0
  268. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.js +66 -0
  269. package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts +19 -0
  270. package/dist/cli/ink-cli/components/renderers/FileRenderer.d.ts.map +1 -0
  271. package/dist/cli/ink-cli/components/renderers/FileRenderer.js +26 -0
  272. package/dist/cli/ink-cli/components/renderers/GenericRenderer.d.ts +21 -0
  273. package/dist/cli/ink-cli/components/renderers/GenericRenderer.d.ts.map +1 -0
  274. package/dist/cli/ink-cli/components/renderers/GenericRenderer.js +26 -0
  275. package/dist/cli/ink-cli/components/renderers/SearchRenderer.d.ts +20 -0
  276. package/dist/cli/ink-cli/components/renderers/SearchRenderer.d.ts.map +1 -0
  277. package/dist/cli/ink-cli/components/renderers/SearchRenderer.js +12 -0
  278. package/dist/cli/ink-cli/components/renderers/ShellRenderer.d.ts +21 -0
  279. package/dist/cli/ink-cli/components/renderers/ShellRenderer.d.ts.map +1 -0
  280. package/dist/cli/ink-cli/components/renderers/ShellRenderer.js +25 -0
  281. package/dist/cli/ink-cli/components/renderers/diff-shared.d.ts +61 -0
  282. package/dist/cli/ink-cli/components/renderers/diff-shared.d.ts.map +1 -0
  283. package/dist/cli/ink-cli/components/renderers/diff-shared.js +158 -0
  284. package/dist/cli/ink-cli/components/renderers/index.d.ts +28 -0
  285. package/dist/cli/ink-cli/components/renderers/index.d.ts.map +1 -0
  286. package/dist/cli/ink-cli/components/renderers/index.js +36 -0
  287. package/dist/cli/ink-cli/components/shared/MarkdownText.d.ts +38 -0
  288. package/dist/cli/ink-cli/components/shared/MarkdownText.d.ts.map +1 -0
  289. package/dist/cli/ink-cli/components/shared/MarkdownText.js +362 -0
  290. package/dist/cli/ink-cli/components/shared/VirtualizedList.d.ts +44 -0
  291. package/dist/cli/ink-cli/components/shared/VirtualizedList.d.ts.map +1 -0
  292. package/dist/cli/ink-cli/components/shared/VirtualizedList.js +300 -0
  293. package/dist/cli/ink-cli/components/shared/text-buffer.d.ts +185 -0
  294. package/dist/cli/ink-cli/components/shared/text-buffer.d.ts.map +1 -0
  295. package/dist/cli/ink-cli/components/shared/text-buffer.js +1338 -0
  296. package/dist/cli/ink-cli/constants/processingPhrases.d.ts +10 -0
  297. package/dist/cli/ink-cli/constants/processingPhrases.d.ts.map +1 -0
  298. package/dist/cli/ink-cli/constants/processingPhrases.js +64 -0
  299. package/dist/cli/ink-cli/constants/tips.d.ts +15 -0
  300. package/dist/cli/ink-cli/constants/tips.d.ts.map +1 -0
  301. package/dist/cli/ink-cli/constants/tips.js +53 -0
  302. package/dist/cli/ink-cli/containers/InputContainer.d.ts +42 -8
  303. package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
  304. package/dist/cli/ink-cli/containers/InputContainer.js +513 -85
  305. package/dist/cli/ink-cli/containers/OverlayContainer.d.ts +23 -5
  306. package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
  307. package/dist/cli/ink-cli/containers/OverlayContainer.js +1214 -132
  308. package/dist/cli/ink-cli/containers/index.d.ts +1 -1
  309. package/dist/cli/ink-cli/containers/index.d.ts.map +1 -1
  310. package/dist/cli/ink-cli/contexts/KeypressContext.d.ts +36 -0
  311. package/dist/cli/ink-cli/contexts/KeypressContext.d.ts.map +1 -0
  312. package/dist/cli/ink-cli/contexts/KeypressContext.js +461 -0
  313. package/dist/cli/ink-cli/contexts/MouseContext.d.ts +27 -0
  314. package/dist/cli/ink-cli/contexts/MouseContext.d.ts.map +1 -0
  315. package/dist/cli/ink-cli/contexts/MouseContext.js +102 -0
  316. package/dist/cli/ink-cli/contexts/ScrollProvider.d.ts +33 -0
  317. package/dist/cli/ink-cli/contexts/ScrollProvider.d.ts.map +1 -0
  318. package/dist/cli/ink-cli/contexts/ScrollProvider.js +170 -0
  319. package/dist/cli/ink-cli/contexts/index.d.ts +7 -0
  320. package/dist/cli/ink-cli/contexts/index.d.ts.map +1 -0
  321. package/dist/cli/ink-cli/contexts/index.js +6 -0
  322. package/dist/cli/ink-cli/hooks/index.d.ts +5 -0
  323. package/dist/cli/ink-cli/hooks/index.d.ts.map +1 -1
  324. package/dist/cli/ink-cli/hooks/index.js +6 -1
  325. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts +26 -9
  326. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts.map +1 -1
  327. package/dist/cli/ink-cli/hooks/useAgentEvents.js +90 -198
  328. package/dist/cli/ink-cli/hooks/useBatchedScroll.d.ts +14 -0
  329. package/dist/cli/ink-cli/hooks/useBatchedScroll.d.ts.map +1 -0
  330. package/dist/cli/ink-cli/hooks/useBatchedScroll.js +25 -0
  331. package/dist/cli/ink-cli/hooks/useCLIState.d.ts +50 -0
  332. package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -0
  333. package/dist/cli/ink-cli/hooks/useCLIState.js +190 -0
  334. package/dist/cli/ink-cli/hooks/useElapsedTime.d.ts +24 -0
  335. package/dist/cli/ink-cli/hooks/useElapsedTime.d.ts.map +1 -0
  336. package/dist/cli/ink-cli/hooks/useElapsedTime.js +69 -0
  337. package/dist/cli/ink-cli/hooks/useHistorySearch.d.ts +61 -0
  338. package/dist/cli/ink-cli/hooks/useHistorySearch.d.ts.map +1 -0
  339. package/dist/cli/ink-cli/hooks/useHistorySearch.js +210 -0
  340. package/dist/cli/ink-cli/hooks/useInputOrchestrator.d.ts +136 -0
  341. package/dist/cli/ink-cli/hooks/useInputOrchestrator.d.ts.map +1 -0
  342. package/dist/cli/ink-cli/hooks/useInputOrchestrator.js +663 -0
  343. package/dist/cli/ink-cli/hooks/useKeyboardShortcuts.d.ts.map +1 -1
  344. package/dist/cli/ink-cli/hooks/useKeyboardShortcuts.js +7 -26
  345. package/dist/cli/ink-cli/hooks/useKeypress.d.ts +18 -0
  346. package/dist/cli/ink-cli/hooks/useKeypress.d.ts.map +1 -0
  347. package/dist/cli/ink-cli/hooks/useKeypress.js +26 -0
  348. package/dist/cli/ink-cli/hooks/usePhraseCycler.d.ts +30 -0
  349. package/dist/cli/ink-cli/hooks/usePhraseCycler.d.ts.map +1 -0
  350. package/dist/cli/ink-cli/hooks/usePhraseCycler.js +68 -0
  351. package/dist/cli/ink-cli/hooks/useStreaming.d.ts +19 -0
  352. package/dist/cli/ink-cli/hooks/useStreaming.d.ts.map +1 -0
  353. package/dist/cli/ink-cli/hooks/useStreaming.js +26 -0
  354. package/dist/cli/ink-cli/hooks/useTerminalSize.d.ts +14 -0
  355. package/dist/cli/ink-cli/hooks/useTerminalSize.d.ts.map +1 -0
  356. package/dist/cli/ink-cli/hooks/useTerminalSize.js +31 -0
  357. package/dist/cli/ink-cli/hooks/useTokenCounter.d.ts +42 -0
  358. package/dist/cli/ink-cli/hooks/useTokenCounter.d.ts.map +1 -0
  359. package/dist/cli/ink-cli/hooks/useTokenCounter.js +96 -0
  360. package/dist/cli/ink-cli/services/CommandService.d.ts +32 -1
  361. package/dist/cli/ink-cli/services/CommandService.d.ts.map +1 -1
  362. package/dist/cli/ink-cli/services/CommandService.js +36 -5
  363. package/dist/cli/ink-cli/services/InputService.d.ts +1 -5
  364. package/dist/cli/ink-cli/services/InputService.d.ts.map +1 -1
  365. package/dist/cli/ink-cli/services/InputService.js +1 -8
  366. package/dist/cli/ink-cli/services/index.d.ts +2 -1
  367. package/dist/cli/ink-cli/services/index.d.ts.map +1 -1
  368. package/dist/cli/ink-cli/services/index.js +2 -1
  369. package/dist/cli/ink-cli/services/processStream.d.ts +69 -0
  370. package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -0
  371. package/dist/cli/ink-cli/services/processStream.js +742 -0
  372. package/dist/cli/ink-cli/state/actions.d.ts +30 -60
  373. package/dist/cli/ink-cli/state/actions.d.ts.map +1 -1
  374. package/dist/cli/ink-cli/state/actions.js +3 -0
  375. package/dist/cli/ink-cli/state/index.d.ts +5 -3
  376. package/dist/cli/ink-cli/state/index.d.ts.map +1 -1
  377. package/dist/cli/ink-cli/state/index.js +4 -3
  378. package/dist/cli/ink-cli/state/initialState.d.ts +4 -3
  379. package/dist/cli/ink-cli/state/initialState.d.ts.map +1 -1
  380. package/dist/cli/ink-cli/state/initialState.js +20 -4
  381. package/dist/cli/ink-cli/state/reducer.d.ts +3 -0
  382. package/dist/cli/ink-cli/state/reducer.d.ts.map +1 -1
  383. package/dist/cli/ink-cli/state/reducer.js +62 -168
  384. package/dist/cli/ink-cli/state/streaming-state.d.ts +27 -0
  385. package/dist/cli/ink-cli/state/streaming-state.d.ts.map +1 -0
  386. package/dist/cli/ink-cli/state/streaming-state.js +39 -0
  387. package/dist/cli/ink-cli/state/types.d.ts +223 -6
  388. package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
  389. package/dist/cli/ink-cli/utils/bracketedPaste.d.ts +22 -0
  390. package/dist/cli/ink-cli/utils/bracketedPaste.d.ts.map +1 -0
  391. package/dist/cli/ink-cli/utils/bracketedPaste.js +27 -0
  392. package/dist/cli/ink-cli/utils/clipboardUtils.d.ts +49 -0
  393. package/dist/cli/ink-cli/utils/clipboardUtils.d.ts.map +1 -0
  394. package/dist/cli/ink-cli/utils/clipboardUtils.js +356 -0
  395. package/dist/cli/ink-cli/utils/commandOverlays.d.ts +33 -0
  396. package/dist/cli/ink-cli/utils/commandOverlays.d.ts.map +1 -0
  397. package/dist/cli/ink-cli/utils/commandOverlays.js +78 -0
  398. package/dist/cli/ink-cli/utils/debugLog.d.ts +38 -0
  399. package/dist/cli/ink-cli/utils/debugLog.d.ts.map +1 -0
  400. package/dist/cli/ink-cli/utils/debugLog.js +66 -0
  401. package/dist/cli/ink-cli/utils/index.d.ts +2 -1
  402. package/dist/cli/ink-cli/utils/index.d.ts.map +1 -1
  403. package/dist/cli/ink-cli/utils/index.js +3 -1
  404. package/dist/cli/ink-cli/utils/input.d.ts +25 -0
  405. package/dist/cli/ink-cli/utils/input.d.ts.map +1 -0
  406. package/dist/cli/ink-cli/utils/input.js +56 -0
  407. package/dist/cli/ink-cli/utils/inputParsing.d.ts +0 -9
  408. package/dist/cli/ink-cli/utils/inputParsing.d.ts.map +1 -1
  409. package/dist/cli/ink-cli/utils/inputParsing.js +0 -27
  410. package/dist/cli/ink-cli/utils/messageFormatting.d.ts +59 -3
  411. package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
  412. package/dist/cli/ink-cli/utils/messageFormatting.js +348 -20
  413. package/dist/cli/ink-cli/utils/mouse.d.ts +61 -0
  414. package/dist/cli/ink-cli/utils/mouse.d.ts.map +1 -0
  415. package/dist/cli/ink-cli/utils/mouse.js +209 -0
  416. package/dist/cli/ink-cli/utils/streamSplitter.d.ts +44 -0
  417. package/dist/cli/ink-cli/utils/streamSplitter.d.ts.map +1 -0
  418. package/dist/cli/ink-cli/utils/streamSplitter.js +154 -0
  419. package/dist/cli/ink-cli/utils/textUtils.d.ts +63 -0
  420. package/dist/cli/ink-cli/utils/textUtils.d.ts.map +1 -0
  421. package/dist/cli/ink-cli/utils/textUtils.js +248 -0
  422. package/dist/cli/ink-cli/utils/toolUtils.d.ts +9 -0
  423. package/dist/cli/ink-cli/utils/toolUtils.d.ts.map +1 -0
  424. package/dist/cli/ink-cli/utils/toolUtils.js +15 -0
  425. package/dist/cli/utils/api-key-setup.d.ts +54 -4
  426. package/dist/cli/utils/api-key-setup.d.ts.map +1 -1
  427. package/dist/cli/utils/api-key-setup.js +433 -107
  428. package/dist/cli/utils/api-key-verification.d.ts +17 -0
  429. package/dist/cli/utils/api-key-verification.d.ts.map +1 -0
  430. package/dist/cli/utils/api-key-verification.js +211 -0
  431. package/dist/cli/utils/config-validation.d.ts +22 -2
  432. package/dist/cli/utils/config-validation.d.ts.map +1 -1
  433. package/dist/cli/utils/config-validation.js +354 -25
  434. package/dist/cli/utils/local-model-setup.d.ts +46 -0
  435. package/dist/cli/utils/local-model-setup.d.ts.map +1 -0
  436. package/dist/cli/utils/local-model-setup.js +662 -0
  437. package/dist/cli/utils/options.d.ts.map +1 -1
  438. package/dist/cli/utils/options.js +1 -3
  439. package/dist/cli/utils/prompt-helpers.d.ts +47 -0
  440. package/dist/cli/utils/prompt-helpers.d.ts.map +1 -0
  441. package/dist/cli/utils/prompt-helpers.js +66 -0
  442. package/dist/cli/utils/provider-setup.d.ts +66 -8
  443. package/dist/cli/utils/provider-setup.d.ts.map +1 -1
  444. package/dist/cli/utils/provider-setup.js +324 -84
  445. package/dist/cli/utils/scaffolding-utils.d.ts +76 -0
  446. package/dist/cli/utils/scaffolding-utils.d.ts.map +1 -0
  447. package/dist/cli/utils/scaffolding-utils.js +246 -0
  448. package/dist/cli/utils/setup-utils.d.ts +16 -0
  449. package/dist/cli/utils/setup-utils.d.ts.map +1 -1
  450. package/dist/cli/utils/setup-utils.js +72 -21
  451. package/dist/cli/utils/template-engine.d.ts +65 -0
  452. package/dist/cli/utils/template-engine.d.ts.map +1 -0
  453. package/dist/cli/utils/template-engine.js +1089 -0
  454. package/dist/config/cli-overrides.d.ts +45 -2
  455. package/dist/config/cli-overrides.d.ts.map +1 -1
  456. package/dist/config/cli-overrides.js +107 -10
  457. package/dist/index.js +379 -99
  458. package/dist/utils/agent-helpers.d.ts +95 -0
  459. package/dist/utils/agent-helpers.d.ts.map +1 -0
  460. package/dist/utils/agent-helpers.js +117 -0
  461. package/dist/webui/assets/index-8j-KMkX1.js +2054 -0
  462. package/dist/webui/assets/index-c_AX24V4.css +1 -0
  463. package/dist/webui/assets/{tanstack-DgxBONJY.js → tanstack-Br79RQ-n.js} +1 -1
  464. package/dist/webui/index.html +4 -10
  465. package/dist/webui/logos/aws-color.svg +1 -0
  466. package/dist/webui/logos/dexto/dexto_logo.svg +1 -1
  467. package/dist/webui/logos/dexto/dexto_logo_light.svg +6 -6
  468. package/dist/webui/logos/glama.svg +7 -0
  469. package/dist/webui/logos/litellm.svg +7 -0
  470. package/dist/webui/logos/openrouter.svg +1 -0
  471. package/package.json +18 -15
  472. package/dist/cli/commands/interactive-commands/index.d.ts +0 -63
  473. package/dist/cli/commands/interactive-commands/index.d.ts.map +0 -1
  474. package/dist/cli/commands/interactive-commands/index.js +0 -73
  475. package/dist/cli/commands/interactive-commands/mcp/mcp-add-utils.d.ts +0 -34
  476. package/dist/cli/commands/interactive-commands/mcp/mcp-add-utils.d.ts.map +0 -1
  477. package/dist/cli/commands/interactive-commands/mcp/mcp-add-utils.js +0 -178
  478. package/dist/cli/commands/interactive-commands/mcp/mcp-commands.d.ts +0 -9
  479. package/dist/cli/commands/interactive-commands/mcp/mcp-commands.d.ts.map +0 -1
  480. package/dist/cli/commands/interactive-commands/mcp/mcp-commands.js +0 -325
  481. package/dist/cli/commands/interactive-commands/model/model-commands.d.ts +0 -21
  482. package/dist/cli/commands/interactive-commands/model/model-commands.d.ts.map +0 -1
  483. package/dist/cli/commands/interactive-commands/model/model-commands.js +0 -190
  484. package/dist/cli/ink-cli/components/MultiLineTextInput.d.ts +0 -26
  485. package/dist/cli/ink-cli/components/MultiLineTextInput.d.ts.map +0 -1
  486. package/dist/cli/ink-cli/components/MultiLineTextInput.js +0 -220
  487. package/dist/discord/bot.d.ts +0 -4
  488. package/dist/discord/bot.d.ts.map +0 -1
  489. package/dist/discord/bot.js +0 -193
  490. package/dist/telegram/bot.d.ts +0 -5
  491. package/dist/telegram/bot.d.ts.map +0 -1
  492. package/dist/telegram/bot.js +0 -251
  493. package/dist/webui/assets/index-DKq5Xng1.js +0 -687
  494. package/dist/webui/assets/index-D_0_GBu5.css +0 -1
@@ -3,38 +3,164 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
3
3
  * OverlayContainer Component
4
4
  * Smart container for managing all overlays (selectors, autocomplete, approval)
5
5
  */
6
- import { useCallback } from 'react';
6
+ import { useCallback, useRef, useImperativeHandle, forwardRef, useState } from 'react';
7
7
  import { Box } from 'ink';
8
8
  import { ApprovalStatus, DenialReason } from '@dexto/core';
9
- import { ApprovalPrompt } from '../components/ApprovalPrompt.js';
10
- import SlashCommandAutocomplete from '../components/SlashCommandAutocomplete.js';
9
+ import { ApprovalPrompt, } from '../components/ApprovalPrompt.js';
10
+ import { SlashCommandAutocomplete, } from '../components/SlashCommandAutocomplete.js';
11
11
  import ResourceAutocomplete from '../components/ResourceAutocomplete.js';
12
12
  import ModelSelectorRefactored from '../components/overlays/ModelSelectorRefactored.js';
13
13
  import SessionSelectorRefactored from '../components/overlays/SessionSelectorRefactored.js';
14
+ import LogLevelSelector from '../components/overlays/LogLevelSelector.js';
15
+ import StreamSelector from '../components/overlays/StreamSelector.js';
16
+ import ToolBrowser from '../components/overlays/ToolBrowser.js';
17
+ import McpServerList from '../components/overlays/McpServerList.js';
18
+ import McpServerActions from '../components/overlays/McpServerActions.js';
19
+ import McpAddChoice from '../components/overlays/McpAddChoice.js';
20
+ import McpAddSelector from '../components/overlays/McpAddSelector.js';
21
+ import SessionSubcommandSelector from '../components/overlays/SessionSubcommandSelector.js';
22
+ import McpCustomTypeSelector from '../components/overlays/McpCustomTypeSelector.js';
23
+ import McpCustomWizard from '../components/overlays/McpCustomWizard.js';
24
+ import CustomModelWizard from '../components/overlays/CustomModelWizard.js';
25
+ import ApiKeyInput from '../components/overlays/ApiKeyInput.js';
26
+ import SearchOverlay from '../components/overlays/SearchOverlay.js';
27
+ import PromptList from '../components/overlays/PromptList.js';
28
+ import PromptAddChoice from '../components/overlays/PromptAddChoice.js';
29
+ import PromptAddWizard from '../components/overlays/PromptAddWizard.js';
30
+ import PromptDeleteSelector from '../components/overlays/PromptDeleteSelector.js';
31
+ import { DextoValidationError, LLMErrorCode } from '@dexto/core';
14
32
  import { createUserMessage, convertHistoryToUIMessages } from '../utils/messageFormatting.js';
15
33
  import { generateMessageId } from '../utils/idGenerator.js';
34
+ import { capture } from '../../../analytics/index.js';
16
35
  /**
17
36
  * Smart container for managing overlays
18
37
  * Handles all modal interactions (selectors, autocomplete, approval)
19
38
  */
20
- export function OverlayContainer({ state, dispatch, agent, inputService }) {
21
- const { ui, input, approval } = state;
39
+ export const OverlayContainer = forwardRef(function OverlayContainer({ ui, input, session, approval, setInput, setUi, setSession, setMessages, setApproval, setApprovalQueue, agent, inputService, buffer, refreshStatic, onSubmitPromptCommand, }, ref) {
22
40
  const eventBus = agent.agentEventBus;
41
+ // Refs to overlay components for input handling
42
+ const approvalRef = useRef(null);
43
+ const slashAutocompleteRef = useRef(null);
44
+ const resourceAutocompleteRef = useRef(null);
45
+ const modelSelectorRef = useRef(null);
46
+ const sessionSelectorRef = useRef(null);
47
+ const logLevelSelectorRef = useRef(null);
48
+ const streamSelectorRef = useRef(null);
49
+ const toolBrowserRef = useRef(null);
50
+ const mcpServerListRef = useRef(null);
51
+ const mcpServerActionsRef = useRef(null);
52
+ const mcpAddChoiceRef = useRef(null);
53
+ const mcpAddSelectorRef = useRef(null);
54
+ const mcpCustomTypeSelectorRef = useRef(null);
55
+ const mcpCustomWizardRef = useRef(null);
56
+ const customModelWizardRef = useRef(null);
57
+ const sessionSubcommandSelectorRef = useRef(null);
58
+ const apiKeyInputRef = useRef(null);
59
+ const searchOverlayRef = useRef(null);
60
+ const promptListRef = useRef(null);
61
+ const promptAddChoiceRef = useRef(null);
62
+ const promptAddWizardRef = useRef(null);
63
+ const promptDeleteSelectorRef = useRef(null);
64
+ // Expose handleInput method via ref - routes to appropriate overlay
65
+ useImperativeHandle(ref, () => ({
66
+ handleInput: (inputStr, key) => {
67
+ // Route to approval first (highest priority)
68
+ if (approval && approvalRef.current) {
69
+ return approvalRef.current.handleInput(inputStr, key);
70
+ }
71
+ // Route to active overlay based on type
72
+ switch (ui.activeOverlay) {
73
+ case 'slash-autocomplete':
74
+ return (slashAutocompleteRef.current?.handleInput(inputStr, key) ?? false);
75
+ case 'resource-autocomplete':
76
+ return (resourceAutocompleteRef.current?.handleInput(inputStr, key) ?? false);
77
+ case 'model-selector':
78
+ return modelSelectorRef.current?.handleInput(inputStr, key) ?? false;
79
+ case 'session-selector':
80
+ return sessionSelectorRef.current?.handleInput(inputStr, key) ?? false;
81
+ case 'log-level-selector':
82
+ return logLevelSelectorRef.current?.handleInput(inputStr, key) ?? false;
83
+ case 'stream-selector':
84
+ return streamSelectorRef.current?.handleInput(inputStr, key) ?? false;
85
+ case 'tool-browser':
86
+ return toolBrowserRef.current?.handleInput(inputStr, key) ?? false;
87
+ case 'mcp-server-list':
88
+ return mcpServerListRef.current?.handleInput(inputStr, key) ?? false;
89
+ case 'mcp-server-actions':
90
+ return mcpServerActionsRef.current?.handleInput(inputStr, key) ?? false;
91
+ case 'mcp-add-choice':
92
+ return mcpAddChoiceRef.current?.handleInput(inputStr, key) ?? false;
93
+ case 'mcp-add-selector':
94
+ return mcpAddSelectorRef.current?.handleInput(inputStr, key) ?? false;
95
+ case 'mcp-custom-type-selector':
96
+ return (mcpCustomTypeSelectorRef.current?.handleInput(inputStr, key) ??
97
+ false);
98
+ case 'mcp-custom-wizard':
99
+ return mcpCustomWizardRef.current?.handleInput(inputStr, key) ?? false;
100
+ case 'custom-model-wizard':
101
+ return (customModelWizardRef.current?.handleInput(inputStr, key) ?? false);
102
+ case 'session-subcommand-selector':
103
+ return (sessionSubcommandSelectorRef.current?.handleInput(inputStr, key) ??
104
+ false);
105
+ case 'api-key-input':
106
+ return apiKeyInputRef.current?.handleInput(inputStr, key) ?? false;
107
+ case 'search':
108
+ return searchOverlayRef.current?.handleInput(inputStr, key) ?? false;
109
+ case 'prompt-list':
110
+ return promptListRef.current?.handleInput(inputStr, key) ?? false;
111
+ case 'prompt-add-choice':
112
+ return promptAddChoiceRef.current?.handleInput(inputStr, key) ?? false;
113
+ case 'prompt-add-wizard':
114
+ return promptAddWizardRef.current?.handleInput(inputStr, key) ?? false;
115
+ case 'prompt-delete-selector':
116
+ return (promptDeleteSelectorRef.current?.handleInput(inputStr, key) ?? false);
117
+ default:
118
+ return false;
119
+ }
120
+ },
121
+ }), [approval, ui.activeOverlay]);
23
122
  // NOTE: Automatic overlay detection removed to prevent infinite loop
24
- // Overlays are now shown explicitly via SHOW_OVERLAY actions from InputContainer
123
+ // Overlays are now shown explicitly via setUi from InputContainer
25
124
  // or from the main component's input detection logic
125
+ // Helper: Complete approval and process queue
126
+ const completeApproval = useCallback(() => {
127
+ setApprovalQueue((queue) => {
128
+ if (queue.length > 0) {
129
+ // Show next approval from queue
130
+ const [next, ...rest] = queue;
131
+ setApproval(next);
132
+ setUi((prev) => ({ ...prev, activeOverlay: 'approval' }));
133
+ return rest;
134
+ }
135
+ else {
136
+ // No more approvals
137
+ setApproval(null);
138
+ setUi((prev) => ({ ...prev, activeOverlay: 'none' }));
139
+ return [];
140
+ }
141
+ });
142
+ }, [setApproval, setApprovalQueue, setUi]);
26
143
  // Handle approval responses
27
- const handleApprove = useCallback((rememberChoice) => {
144
+ const handleApprove = useCallback((options) => {
28
145
  if (!approval || !eventBus)
29
146
  return;
147
+ // Enable "accept all edits" mode if requested
148
+ if (options.enableAcceptEditsMode) {
149
+ setUi((prev) => ({ ...prev, autoApproveEdits: true }));
150
+ }
30
151
  eventBus.emit('approval:response', {
31
152
  approvalId: approval.approvalId,
32
153
  status: ApprovalStatus.APPROVED,
33
154
  sessionId: approval.sessionId,
34
- data: { rememberChoice },
155
+ data: {
156
+ rememberChoice: options.rememberChoice,
157
+ rememberPattern: options.rememberPattern,
158
+ formData: options.formData,
159
+ rememberDirectory: options.rememberDirectory,
160
+ },
35
161
  });
36
- dispatch({ type: 'APPROVAL_COMPLETE' });
37
- }, [approval, eventBus, dispatch]);
162
+ completeApproval();
163
+ }, [approval, eventBus, completeApproval, setUi]);
38
164
  const handleDeny = useCallback(() => {
39
165
  if (!approval || !eventBus)
40
166
  return;
@@ -45,8 +171,8 @@ export function OverlayContainer({ state, dispatch, agent, inputService }) {
45
171
  reason: DenialReason.USER_DENIED,
46
172
  message: 'User denied the tool execution',
47
173
  });
48
- dispatch({ type: 'APPROVAL_COMPLETE' });
49
- }, [approval, eventBus, dispatch]);
174
+ completeApproval();
175
+ }, [approval, eventBus, completeApproval]);
50
176
  const handleCancelApproval = useCallback(() => {
51
177
  if (!approval || !eventBus)
52
178
  return;
@@ -57,193 +183,464 @@ export function OverlayContainer({ state, dispatch, agent, inputService }) {
57
183
  reason: DenialReason.USER_CANCELLED,
58
184
  message: 'User cancelled the approval request',
59
185
  });
60
- dispatch({ type: 'APPROVAL_COMPLETE' });
61
- }, [approval, eventBus, dispatch]);
186
+ completeApproval();
187
+ }, [approval, eventBus, completeApproval]);
188
+ // Helper: Check if error is due to missing API key
189
+ const isApiKeyMissingError = (error) => {
190
+ if (error instanceof DextoValidationError) {
191
+ const apiKeyIssue = error.issues.find((issue) => issue.code === LLMErrorCode.API_KEY_MISSING);
192
+ if (apiKeyIssue && apiKeyIssue.context) {
193
+ // Extract provider from context
194
+ const context = apiKeyIssue.context;
195
+ if (context.provider) {
196
+ return context.provider;
197
+ }
198
+ }
199
+ }
200
+ return null;
201
+ };
62
202
  // Handle model selection
63
- const handleModelSelect = useCallback(async (provider, model) => {
64
- dispatch({ type: 'CLOSE_OVERLAY' });
65
- dispatch({ type: 'INPUT_CLEAR' });
203
+ const handleModelSelect = useCallback(async (provider, model, displayName, baseURL) => {
204
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
205
+ buffer.setText('');
206
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
66
207
  try {
67
- dispatch({
68
- type: 'MESSAGE_ADD',
69
- message: {
208
+ setMessages((prev) => [
209
+ ...prev,
210
+ {
70
211
  id: generateMessageId('system'),
71
212
  role: 'system',
72
- content: `šŸ”„ Switching to ${model} (${provider})...`,
213
+ content: `šŸ”„ Switching to ${displayName || model} (${provider})...`,
73
214
  timestamp: new Date(),
74
215
  },
75
- });
76
- // Pass sessionId from state to switchLLM (WebUI pattern)
77
- const currentSessionId = state.session.id;
78
- await agent.switchLLM({ provider: provider, model }, currentSessionId || undefined);
79
- dispatch({
80
- type: 'MESSAGE_ADD',
81
- message: {
216
+ ]);
217
+ await agent.switchLLM({ provider: provider, model, baseURL }, session.id || undefined);
218
+ // Update session state with display name (fallback to model ID)
219
+ setSession((prev) => ({ ...prev, modelName: displayName || model }));
220
+ setMessages((prev) => [
221
+ ...prev,
222
+ {
82
223
  id: generateMessageId('system'),
83
224
  role: 'system',
84
- content: `āœ… Successfully switched to ${model} (${provider})`,
225
+ content: `āœ… Successfully switched to ${displayName || model} (${provider})`,
85
226
  timestamp: new Date(),
86
227
  },
87
- });
228
+ ]);
88
229
  }
89
230
  catch (error) {
90
- dispatch({
91
- type: 'ERROR',
92
- errorMessage: `Failed to switch model: ${error instanceof Error ? error.message : String(error)}`,
93
- });
231
+ // Check if error is due to missing API key
232
+ const missingProvider = isApiKeyMissingError(error);
233
+ if (missingProvider) {
234
+ // Store pending model switch and show API key input
235
+ // Use missingProvider (from error) as the authoritative source
236
+ setUi((prev) => ({
237
+ ...prev,
238
+ activeOverlay: 'api-key-input',
239
+ pendingModelSwitch: {
240
+ provider: missingProvider,
241
+ model,
242
+ ...(displayName && { displayName }),
243
+ },
244
+ }));
245
+ setMessages((prev) => [
246
+ ...prev,
247
+ {
248
+ id: generateMessageId('system'),
249
+ role: 'system',
250
+ content: `šŸ”‘ API key required for ${provider}`,
251
+ timestamp: new Date(),
252
+ },
253
+ ]);
254
+ return;
255
+ }
256
+ setMessages((prev) => [
257
+ ...prev,
258
+ {
259
+ id: generateMessageId('error'),
260
+ role: 'system',
261
+ content: `āŒ Failed to switch model: ${error instanceof Error ? error.message : String(error)}`,
262
+ timestamp: new Date(),
263
+ },
264
+ ]);
94
265
  }
95
- }, [dispatch, agent, state.session.id]);
266
+ }, [setUi, setInput, setMessages, setSession, agent, session.id, buffer]);
267
+ // State for editing custom model
268
+ const [editingModel, setEditingModel] = useState(null);
269
+ // Handle "Add custom model" from model selector
270
+ const handleAddCustomModel = useCallback(() => {
271
+ setEditingModel(null);
272
+ setUi((prev) => ({ ...prev, activeOverlay: 'custom-model-wizard' }));
273
+ }, [setUi]);
274
+ // Handle "Edit custom model" from model selector
275
+ const handleEditCustomModel = useCallback((model) => {
276
+ setEditingModel(model);
277
+ setUi((prev) => ({ ...prev, activeOverlay: 'custom-model-wizard' }));
278
+ }, [setUi]);
279
+ // Handle custom model wizard completion
280
+ const handleCustomModelComplete = useCallback(async (model) => {
281
+ const wasEditing = editingModel !== null;
282
+ setEditingModel(null);
283
+ setUi((prev) => ({ ...prev, activeOverlay: 'none' }));
284
+ buffer.setText('');
285
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
286
+ if (wasEditing) {
287
+ // For edits, just show confirmation message
288
+ setMessages((prev) => [
289
+ ...prev,
290
+ {
291
+ id: generateMessageId('system'),
292
+ role: 'system',
293
+ content: `āœ… Custom model "${model.displayName || model.name}" updated`,
294
+ timestamp: new Date(),
295
+ },
296
+ ]);
297
+ }
298
+ else {
299
+ // For new models, auto-switch to the newly created model
300
+ setMessages((prev) => [
301
+ ...prev,
302
+ {
303
+ id: generateMessageId('system'),
304
+ role: 'system',
305
+ content: `āœ… Custom model "${model.displayName || model.name}" saved`,
306
+ timestamp: new Date(),
307
+ },
308
+ ]);
309
+ // Switch to the new model
310
+ await handleModelSelect(model.provider, model.name, model.displayName, model.baseURL);
311
+ }
312
+ }, [setUi, setInput, setMessages, buffer, editingModel, handleModelSelect]);
313
+ // Handle API key saved - retry the model switch
314
+ const handleApiKeySaved = useCallback(async (meta) => {
315
+ const pending = ui.pendingModelSwitch;
316
+ if (!pending) {
317
+ // No pending switch, just close
318
+ setUi((prev) => ({
319
+ ...prev,
320
+ activeOverlay: 'none',
321
+ pendingModelSwitch: null,
322
+ }));
323
+ return;
324
+ }
325
+ setUi((prev) => ({
326
+ ...prev,
327
+ activeOverlay: 'none',
328
+ pendingModelSwitch: null,
329
+ }));
330
+ setMessages((prev) => [
331
+ ...prev,
332
+ {
333
+ id: generateMessageId('system'),
334
+ role: 'system',
335
+ content: `āœ… API key saved for ${meta.provider}`,
336
+ timestamp: new Date(),
337
+ },
338
+ ]);
339
+ // Retry the model switch
340
+ try {
341
+ const pendingDisplayName = pending.displayName || pending.model;
342
+ setMessages((prev) => [
343
+ ...prev,
344
+ {
345
+ id: generateMessageId('system'),
346
+ role: 'system',
347
+ content: `šŸ”„ Retrying switch to ${pendingDisplayName} (${pending.provider})...`,
348
+ timestamp: new Date(),
349
+ },
350
+ ]);
351
+ await agent.switchLLM({ provider: pending.provider, model: pending.model }, session.id || undefined);
352
+ // Update session state with display name (fallback to model ID)
353
+ setSession((prev) => ({ ...prev, modelName: pendingDisplayName }));
354
+ setMessages((prev) => [
355
+ ...prev,
356
+ {
357
+ id: generateMessageId('system'),
358
+ role: 'system',
359
+ content: `āœ… Successfully switched to ${pendingDisplayName} (${pending.provider})`,
360
+ timestamp: new Date(),
361
+ },
362
+ ]);
363
+ }
364
+ catch (error) {
365
+ setMessages((prev) => [
366
+ ...prev,
367
+ {
368
+ id: generateMessageId('error'),
369
+ role: 'system',
370
+ content: `āŒ Failed to switch model: ${error instanceof Error ? error.message : String(error)}`,
371
+ timestamp: new Date(),
372
+ },
373
+ ]);
374
+ }
375
+ }, [ui.pendingModelSwitch, setUi, setMessages, setSession, agent, session.id]);
376
+ // Handle API key input close (without saving)
377
+ const handleApiKeyClose = useCallback(() => {
378
+ setUi((prev) => ({
379
+ ...prev,
380
+ activeOverlay: 'none',
381
+ pendingModelSwitch: null,
382
+ }));
383
+ }, [setUi]);
384
+ // Handle search result selection - display the result context
385
+ const handleSearchResultSelect = useCallback((result) => {
386
+ setUi((prev) => ({ ...prev, activeOverlay: 'none' }));
387
+ buffer.setText('');
388
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
389
+ // Display the selected search result as a system message
390
+ const roleLabel = result.message.role === 'user'
391
+ ? 'šŸ‘¤ User'
392
+ : result.message.role === 'assistant'
393
+ ? 'šŸ¤– Assistant'
394
+ : `šŸ“‹ ${result.message.role}`;
395
+ setMessages((prev) => [
396
+ ...prev,
397
+ {
398
+ id: generateMessageId('system'),
399
+ role: 'system',
400
+ content: `šŸ” Search Result from session ${result.sessionId.slice(0, 8)}:\n\n${roleLabel}:\n${result.context}`,
401
+ timestamp: new Date(),
402
+ },
403
+ ]);
404
+ }, [setUi, setInput, setMessages, buffer]);
96
405
  // Handle session selection
97
406
  const handleSessionSelect = useCallback(async (newSessionId) => {
98
- dispatch({ type: 'CLOSE_OVERLAY' });
99
- dispatch({ type: 'INPUT_CLEAR' });
407
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
408
+ buffer.setText('');
409
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
100
410
  try {
101
- // Check if already on this session (use state, not getCurrentSessionId)
102
- const currentId = state.session.id;
103
- if (newSessionId === currentId) {
104
- dispatch({
105
- type: 'MESSAGE_ADD',
106
- message: {
411
+ // Check if already on this session
412
+ if (newSessionId === session.id) {
413
+ setMessages((prev) => [
414
+ ...prev,
415
+ {
107
416
  id: generateMessageId('system'),
108
417
  role: 'system',
109
418
  content: `ā„¹ļø Already using session ${newSessionId.slice(0, 8)}`,
110
419
  timestamp: new Date(),
111
420
  },
112
- });
421
+ ]);
113
422
  return;
114
423
  }
115
- dispatch({
116
- type: 'MESSAGE_ADD',
117
- message: {
118
- id: generateMessageId('system'),
119
- role: 'system',
120
- content: `šŸ”„ Switching to session ${newSessionId.slice(0, 8)}...`,
121
- timestamp: new Date(),
122
- },
424
+ // Track session switch analytics
425
+ capture('dexto_session_switched', {
426
+ source: 'cli',
427
+ fromSessionId: session.id || null,
428
+ toSessionId: newSessionId,
429
+ });
430
+ // Clear messages and session state before switching
431
+ setMessages([]);
432
+ setApproval(null);
433
+ setApprovalQueue([]);
434
+ setSession({
435
+ id: newSessionId,
436
+ hasActiveSession: true,
437
+ modelName: session.modelName,
123
438
  });
124
439
  // Verify session exists
125
- const session = await agent.getSession(newSessionId);
126
- if (!session) {
440
+ const sessionData = await agent.getSession(newSessionId);
441
+ if (!sessionData) {
127
442
  throw new Error(`Session ${newSessionId} not found`);
128
443
  }
129
- // Clear messages and update sessionId (WebUI pattern - no loadSessionAsDefault)
130
- dispatch({ type: 'SESSION_CLEAR' }); // Clears messages
131
- dispatch({
132
- type: 'SESSION_SET',
133
- sessionId: newSessionId,
134
- hasActiveSession: true,
135
- });
136
444
  // Load session history
137
445
  const history = await agent.getSessionHistory(newSessionId);
138
446
  if (history && history.length > 0) {
139
447
  const historyMessages = convertHistoryToUIMessages(history, newSessionId);
140
- dispatch({ type: 'MESSAGE_ADD_MULTIPLE', messages: historyMessages });
448
+ setMessages(historyMessages);
141
449
  }
142
- dispatch({
143
- type: 'MESSAGE_ADD',
144
- message: {
450
+ setMessages((prev) => [
451
+ ...prev,
452
+ {
145
453
  id: generateMessageId('system'),
146
454
  role: 'system',
147
455
  content: `āœ… Switched to session ${newSessionId.slice(0, 8)}`,
148
456
  timestamp: new Date(),
149
457
  },
150
- });
458
+ ]);
459
+ // Force Static component to re-render with the new history
460
+ refreshStatic?.();
151
461
  }
152
462
  catch (error) {
153
- dispatch({
154
- type: 'ERROR',
155
- errorMessage: `Failed to switch session: ${error instanceof Error ? error.message : String(error)}`,
156
- });
463
+ setMessages((prev) => [
464
+ ...prev,
465
+ {
466
+ id: generateMessageId('error'),
467
+ role: 'system',
468
+ content: `āŒ Failed to switch session: ${error instanceof Error ? error.message : String(error)}`,
469
+ timestamp: new Date(),
470
+ },
471
+ ]);
157
472
  }
158
- }, [dispatch, agent, state.session.id]);
473
+ }, [
474
+ setUi,
475
+ setInput,
476
+ setMessages,
477
+ setApproval,
478
+ setApprovalQueue,
479
+ setSession,
480
+ agent,
481
+ session.id,
482
+ session.modelName,
483
+ buffer,
484
+ refreshStatic,
485
+ ]);
159
486
  // Handle slash command/prompt selection
160
487
  const handlePromptSelect = useCallback(async (prompt) => {
161
- const commandText = `/${prompt.name}`;
162
- dispatch({ type: 'CLOSE_OVERLAY' });
163
- dispatch({ type: 'INPUT_CLEAR' });
488
+ // Use displayName for command text (user-friendly name without prefix)
489
+ const commandName = prompt.displayName || prompt.name;
490
+ const commandText = `/${commandName}`;
491
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
492
+ buffer.setText('');
493
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
494
+ // Route prompts through InputContainer for streaming pipeline
495
+ if (onSubmitPromptCommand) {
496
+ await onSubmitPromptCommand(commandText);
497
+ return;
498
+ }
499
+ // Fallback when callback not provided (shouldn't happen in normal usage)
164
500
  // Show user message for the executed command
165
501
  const userMessage = createUserMessage(commandText);
166
- dispatch({
167
- type: 'MESSAGE_ADD',
168
- message: userMessage,
169
- });
170
- dispatch({ type: 'PROCESSING_START' });
502
+ setMessages((prev) => [...prev, userMessage]);
503
+ setUi((prev) => ({ ...prev, isProcessing: true, isCancelling: false }));
171
504
  const { CommandService } = await import('../services/CommandService.js');
172
505
  const commandService = new CommandService();
173
506
  try {
174
- // Pass sessionId from state to command execution
175
- const currentSessionId = state.session.id;
176
- const result = await commandService.executeCommand(prompt.name, [], agent, currentSessionId || undefined);
177
- if (result.type === 'prompt') {
178
- // Prompt execution continues via event bus
179
- return;
180
- }
507
+ // Use displayName to match the registered command name
508
+ const result = await commandService.executeCommand(commandName, [], agent, session.id || undefined);
181
509
  if (result.type === 'output' && result.output) {
182
- dispatch({
183
- type: 'MESSAGE_ADD',
184
- message: {
510
+ const output = result.output;
511
+ setMessages((prev) => [
512
+ ...prev,
513
+ {
185
514
  id: generateMessageId('command'),
186
515
  role: 'system',
187
- content: result.output,
516
+ content: output,
188
517
  timestamp: new Date(),
189
518
  },
190
- });
519
+ ]);
191
520
  }
192
- dispatch({ type: 'PROCESSING_END' });
521
+ if (result.type === 'styled' && result.styled) {
522
+ const { fallbackText, styledType, styledData } = result.styled;
523
+ setMessages((prev) => [
524
+ ...prev,
525
+ {
526
+ id: generateMessageId('command'),
527
+ role: 'system',
528
+ content: fallbackText,
529
+ timestamp: new Date(),
530
+ styledType,
531
+ styledData,
532
+ },
533
+ ]);
534
+ }
535
+ setUi((prev) => ({
536
+ ...prev,
537
+ isProcessing: false,
538
+ isCancelling: false,
539
+ isThinking: false,
540
+ }));
193
541
  }
194
542
  catch (error) {
195
- dispatch({
196
- type: 'ERROR',
197
- errorMessage: error instanceof Error ? error.message : String(error),
198
- });
543
+ setMessages((prev) => [
544
+ ...prev,
545
+ {
546
+ id: generateMessageId('error'),
547
+ role: 'system',
548
+ content: `āŒ ${error instanceof Error ? error.message : String(error)}`,
549
+ timestamp: new Date(),
550
+ },
551
+ ]);
552
+ setUi((prev) => ({
553
+ ...prev,
554
+ isProcessing: false,
555
+ isCancelling: false,
556
+ isThinking: false,
557
+ }));
199
558
  }
200
- }, [dispatch, agent, state.session.id]);
559
+ }, [setUi, setInput, setMessages, agent, session.id, buffer, onSubmitPromptCommand]);
201
560
  // Handle loading command/prompt into input for editing (Tab key)
202
561
  const handleSystemCommandSelect = useCallback(async (command) => {
562
+ // Check if this command has an interactive overlay
563
+ const { getCommandOverlayForSelect } = await import('../utils/commandOverlays.js');
564
+ const overlay = getCommandOverlayForSelect(command);
565
+ if (overlay) {
566
+ buffer.setText('');
567
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
568
+ setUi((prev) => ({
569
+ ...prev,
570
+ activeOverlay: overlay,
571
+ mcpWizardServerType: null,
572
+ }));
573
+ return;
574
+ }
203
575
  const commandText = `/${command}`;
204
- dispatch({ type: 'CLOSE_OVERLAY' });
205
- dispatch({ type: 'INPUT_CLEAR' });
576
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
577
+ buffer.setText('');
578
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
206
579
  // Show user message for the executed command
207
580
  const userMessage = createUserMessage(commandText);
208
- dispatch({
209
- type: 'MESSAGE_ADD',
210
- message: userMessage,
211
- });
212
- dispatch({ type: 'PROCESSING_START' });
581
+ setMessages((prev) => [...prev, userMessage]);
582
+ setUi((prev) => ({ ...prev, isProcessing: true, isCancelling: false }));
213
583
  const { CommandService } = await import('../services/CommandService.js');
214
584
  const commandService = new CommandService();
215
585
  try {
216
- // Pass sessionId from state to command execution
217
- const currentSessionId = state.session.id;
218
- const result = await commandService.executeCommand(command, [], agent, currentSessionId || undefined);
219
- if (result.type === 'prompt') {
220
- // Prompt execution continues via event bus
221
- return;
222
- }
586
+ const result = await commandService.executeCommand(command, [], agent, session.id || undefined);
223
587
  if (result.type === 'output' && result.output) {
224
- dispatch({
225
- type: 'MESSAGE_ADD',
226
- message: {
588
+ const output = result.output;
589
+ setMessages((prev) => [
590
+ ...prev,
591
+ {
227
592
  id: generateMessageId('command'),
228
593
  role: 'system',
229
- content: result.output,
594
+ content: output,
230
595
  timestamp: new Date(),
231
596
  },
232
- });
597
+ ]);
233
598
  }
234
- dispatch({ type: 'PROCESSING_END' });
599
+ if (result.type === 'styled' && result.styled) {
600
+ const { fallbackText, styledType, styledData } = result.styled;
601
+ setMessages((prev) => [
602
+ ...prev,
603
+ {
604
+ id: generateMessageId('command'),
605
+ role: 'system',
606
+ content: fallbackText,
607
+ timestamp: new Date(),
608
+ styledType,
609
+ styledData,
610
+ },
611
+ ]);
612
+ }
613
+ setUi((prev) => ({
614
+ ...prev,
615
+ isProcessing: false,
616
+ isCancelling: false,
617
+ isThinking: false,
618
+ }));
235
619
  }
236
620
  catch (error) {
237
- dispatch({
238
- type: 'ERROR',
239
- errorMessage: error instanceof Error ? error.message : String(error),
240
- });
621
+ setMessages((prev) => [
622
+ ...prev,
623
+ {
624
+ id: generateMessageId('error'),
625
+ role: 'system',
626
+ content: `āŒ ${error instanceof Error ? error.message : String(error)}`,
627
+ timestamp: new Date(),
628
+ },
629
+ ]);
630
+ setUi((prev) => ({
631
+ ...prev,
632
+ isProcessing: false,
633
+ isCancelling: false,
634
+ isThinking: false,
635
+ }));
241
636
  }
242
- }, [dispatch, agent, state.session.id]);
637
+ }, [setInput, setUi, setMessages, agent, session.id, buffer]);
243
638
  const handleLoadIntoInput = useCallback((text) => {
244
- dispatch({ type: 'INPUT_CHANGE', value: text });
245
- dispatch({ type: 'CLOSE_OVERLAY' });
246
- }, [dispatch]);
639
+ // Update both buffer (source of truth) and state
640
+ buffer.setText(text);
641
+ setInput((prev) => ({ ...prev, value: text }));
642
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
643
+ }, [buffer, setInput, setUi]);
247
644
  // Handle resource selection
248
645
  const handleResourceSelect = useCallback((resource) => {
249
646
  // Insert resource reference into input
@@ -252,12 +649,697 @@ export function OverlayContainer({ state, dispatch, agent, inputService }) {
252
649
  const before = input.value.slice(0, atIndex + 1);
253
650
  const uriParts = resource.uri.split('/');
254
651
  const reference = resource.name || uriParts[uriParts.length - 1] || resource.uri;
255
- dispatch({ type: 'INPUT_CHANGE', value: `${before}${reference} ` });
652
+ const newValue = `${before}${reference} `;
653
+ buffer.setText(newValue);
654
+ setInput((prev) => ({ ...prev, value: newValue }));
256
655
  }
257
- dispatch({ type: 'CLOSE_OVERLAY' });
258
- }, [dispatch, input.value]);
656
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
657
+ }, [input.value, buffer, setInput, setUi]);
259
658
  const handleClose = useCallback(() => {
260
- dispatch({ type: 'CLOSE_OVERLAY' });
261
- }, [dispatch]);
262
- return (_jsxs(_Fragment, { children: [approval && (_jsx(ApprovalPrompt, { approval: approval, onApprove: handleApprove, onDeny: handleDeny, onCancel: handleCancelApproval })), ui.activeOverlay === 'slash-autocomplete' && (_jsx(Box, { marginTop: 1, children: _jsx(SlashCommandAutocomplete, { isVisible: true, searchQuery: input.value, onSelectPrompt: handlePromptSelect, onSelectSystemCommand: handleSystemCommandSelect, onLoadIntoInput: handleLoadIntoInput, onClose: handleClose, agent: agent }) })), ui.activeOverlay === 'resource-autocomplete' && (_jsx(Box, { marginTop: 1, children: _jsx(ResourceAutocomplete, { isVisible: true, searchQuery: input.value, onSelectResource: handleResourceSelect, onLoadIntoInput: handleLoadIntoInput, onClose: handleClose, agent: agent }) })), ui.activeOverlay === 'model-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(ModelSelectorRefactored, { isVisible: true, onSelectModel: handleModelSelect, onClose: handleClose, agent: agent }) })), ui.activeOverlay === 'session-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(SessionSelectorRefactored, { isVisible: true, onSelectSession: handleSessionSelect, onClose: handleClose, agent: agent, currentSessionId: state.session.id || undefined }) }))] }));
263
- }
659
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
660
+ }, [setUi]);
661
+ // Handle log level selection
662
+ const handleLogLevelSelect = useCallback((level) => {
663
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
664
+ buffer.setText('');
665
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
666
+ // Set level on agent's logger (propagates to all child loggers via shared ref)
667
+ agent.logger.setLevel(level);
668
+ setMessages((prev) => [
669
+ ...prev,
670
+ {
671
+ id: generateMessageId('system'),
672
+ role: 'system',
673
+ content: `šŸ“Š Log level set to: ${level}`,
674
+ timestamp: new Date(),
675
+ },
676
+ ]);
677
+ }, [setUi, setInput, setMessages, agent, buffer]);
678
+ // Handle stream mode selection
679
+ const handleStreamSelect = useCallback((enabled) => {
680
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
681
+ buffer.setText('');
682
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
683
+ setMessages((prev) => [
684
+ ...prev,
685
+ {
686
+ id: generateMessageId('system'),
687
+ role: 'system',
688
+ content: enabled
689
+ ? 'ā–¶ļø Streaming enabled - responses will appear as they are generated'
690
+ : 'āøļø Streaming disabled - responses will appear when complete',
691
+ timestamp: new Date(),
692
+ },
693
+ ]);
694
+ }, [setUi, setInput, setMessages, buffer]);
695
+ // Handle MCP server list actions (select server or add new)
696
+ const handleMcpServerListAction = useCallback((action) => {
697
+ if (action.type === 'select-server') {
698
+ // Show server actions overlay
699
+ setUi((prev) => ({
700
+ ...prev,
701
+ activeOverlay: 'mcp-server-actions',
702
+ selectedMcpServer: action.server,
703
+ }));
704
+ }
705
+ else if (action.type === 'add-new') {
706
+ // Show add choice overlay
707
+ setUi((prev) => ({
708
+ ...prev,
709
+ activeOverlay: 'mcp-add-choice',
710
+ }));
711
+ }
712
+ }, [setUi]);
713
+ // Handle MCP server actions (enable/disable/delete/back)
714
+ const handleMcpServerAction = useCallback(async (action) => {
715
+ const { server } = action;
716
+ if (action.type === 'back') {
717
+ // Go back to server list
718
+ setUi((prev) => ({
719
+ ...prev,
720
+ activeOverlay: 'mcp-server-list',
721
+ selectedMcpServer: null,
722
+ }));
723
+ return;
724
+ }
725
+ // Close overlay and reset input for actual actions
726
+ setUi((prev) => ({
727
+ ...prev,
728
+ activeOverlay: 'none',
729
+ selectedMcpServer: null,
730
+ mcpWizardServerType: null,
731
+ }));
732
+ buffer.setText('');
733
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
734
+ if (action.type === 'enable' || action.type === 'disable') {
735
+ const newEnabled = action.type === 'enable';
736
+ setMessages((prev) => [
737
+ ...prev,
738
+ {
739
+ id: generateMessageId('system'),
740
+ role: 'system',
741
+ content: `${newEnabled ? 'ā–¶ļø' : 'āøļø'} ${newEnabled ? 'Enabling' : 'Disabling'} ${server.name}...`,
742
+ timestamp: new Date(),
743
+ },
744
+ ]);
745
+ try {
746
+ // Enable or disable the server FIRST (before persisting)
747
+ // This ensures config only reflects successful state changes
748
+ if (newEnabled) {
749
+ try {
750
+ await agent.enableMcpServer(server.name);
751
+ }
752
+ catch (connectError) {
753
+ // Connection failed - don't persist to config
754
+ setMessages((prev) => [
755
+ ...prev,
756
+ {
757
+ id: generateMessageId('system'),
758
+ role: 'system',
759
+ content: `āš ļø Failed to enable server: ${connectError instanceof Error ? connectError.message : String(connectError)}`,
760
+ timestamp: new Date(),
761
+ },
762
+ ]);
763
+ return;
764
+ }
765
+ }
766
+ else {
767
+ await agent.disableMcpServer(server.name);
768
+ }
769
+ // Import persistence utilities
770
+ const { updateMcpServerField } = await import('@dexto/agent-management');
771
+ // Persist to config file AFTER successful enable/disable
772
+ await updateMcpServerField(agent.getAgentFilePath(), server.name, 'enabled', newEnabled);
773
+ setMessages((prev) => [
774
+ ...prev,
775
+ {
776
+ id: generateMessageId('system'),
777
+ role: 'system',
778
+ content: `āœ… ${server.name} ${newEnabled ? 'enabled' : 'disabled'}`,
779
+ timestamp: new Date(),
780
+ },
781
+ ]);
782
+ }
783
+ catch (error) {
784
+ // Format error message with details if available
785
+ let errorMessage = error instanceof Error ? error.message : String(error);
786
+ if (error instanceof DextoValidationError && error.issues.length > 0) {
787
+ const issueDetails = error.issues
788
+ .map((i) => {
789
+ const path = i.path?.length ? `[${i.path.join('.')}] ` : '';
790
+ return ` - ${path}${i.message}`;
791
+ })
792
+ .join('\n');
793
+ errorMessage = `Validation failed:\n${issueDetails}`;
794
+ }
795
+ setMessages((prev) => [
796
+ ...prev,
797
+ {
798
+ id: generateMessageId('error'),
799
+ role: 'system',
800
+ content: `āŒ Failed to ${action.type} server: ${errorMessage}`,
801
+ timestamp: new Date(),
802
+ },
803
+ ]);
804
+ }
805
+ }
806
+ else if (action.type === 'delete') {
807
+ setMessages((prev) => [
808
+ ...prev,
809
+ {
810
+ id: generateMessageId('system'),
811
+ role: 'system',
812
+ content: `šŸ—‘ļø Deleting ${server.name}...`,
813
+ timestamp: new Date(),
814
+ },
815
+ ]);
816
+ try {
817
+ // Import persistence utilities
818
+ const { removeMcpServerFromConfig } = await import('@dexto/agent-management');
819
+ // Persist to config file using surgical removal
820
+ await removeMcpServerFromConfig(agent.getAgentFilePath(), server.name);
821
+ // Also disconnect if connected
822
+ try {
823
+ await agent.removeMcpServer(server.name);
824
+ }
825
+ catch {
826
+ // Ignore - server might not be connected
827
+ }
828
+ setMessages((prev) => [
829
+ ...prev,
830
+ {
831
+ id: generateMessageId('system'),
832
+ role: 'system',
833
+ content: `āœ… Deleted ${server.name}`,
834
+ timestamp: new Date(),
835
+ },
836
+ ]);
837
+ }
838
+ catch (error) {
839
+ setMessages((prev) => [
840
+ ...prev,
841
+ {
842
+ id: generateMessageId('error'),
843
+ role: 'system',
844
+ content: `āŒ Failed to delete server: ${error instanceof Error ? error.message : String(error)}`,
845
+ timestamp: new Date(),
846
+ },
847
+ ]);
848
+ }
849
+ }
850
+ }, [setUi, setInput, setMessages, agent, buffer]);
851
+ // Handle MCP add choice (registry/custom/back)
852
+ const handleMcpAddChoice = useCallback((choice) => {
853
+ if (choice === 'back') {
854
+ // Go back to server list
855
+ setUi((prev) => ({
856
+ ...prev,
857
+ activeOverlay: 'mcp-server-list',
858
+ }));
859
+ }
860
+ else if (choice === 'registry') {
861
+ // Show registry selector (McpAddSelector)
862
+ setUi((prev) => ({
863
+ ...prev,
864
+ activeOverlay: 'mcp-add-selector',
865
+ }));
866
+ }
867
+ else if (choice === 'custom') {
868
+ // Show custom type selector
869
+ setUi((prev) => ({
870
+ ...prev,
871
+ activeOverlay: 'mcp-custom-type-selector',
872
+ }));
873
+ }
874
+ }, [setUi]);
875
+ // Handle MCP add selection (presets only)
876
+ const handleMcpAddSelect = useCallback(async (result) => {
877
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
878
+ buffer.setText('');
879
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
880
+ setUi((prev) => ({ ...prev, isProcessing: true, isCancelling: false }));
881
+ setMessages((prev) => [
882
+ ...prev,
883
+ {
884
+ id: generateMessageId('system'),
885
+ role: 'system',
886
+ content: `šŸ”Œ Connecting to ${result.entry.name}...`,
887
+ timestamp: new Date(),
888
+ },
889
+ ]);
890
+ try {
891
+ const mcpConfig = result.entry.config;
892
+ await agent.addMcpServer(result.entry.id, mcpConfig);
893
+ // Track MCP server connected analytics
894
+ capture('dexto_mcp_server_connected', {
895
+ source: 'cli',
896
+ serverName: result.entry.name,
897
+ transportType: mcpConfig.type,
898
+ });
899
+ setMessages((prev) => [
900
+ ...prev,
901
+ {
902
+ id: generateMessageId('system'),
903
+ role: 'system',
904
+ content: `āœ… Connected to ${result.entry.name}`,
905
+ timestamp: new Date(),
906
+ },
907
+ ]);
908
+ }
909
+ catch (error) {
910
+ setMessages((prev) => [
911
+ ...prev,
912
+ {
913
+ id: generateMessageId('system'),
914
+ role: 'system',
915
+ content: `āŒ Failed to connect: ${error instanceof Error ? error.message : String(error)}`,
916
+ timestamp: new Date(),
917
+ },
918
+ ]);
919
+ }
920
+ setUi((prev) => ({
921
+ ...prev,
922
+ isProcessing: false,
923
+ isCancelling: false,
924
+ isThinking: false,
925
+ }));
926
+ }, [setUi, setInput, setMessages, agent, buffer]);
927
+ // Handle MCP custom type selection
928
+ const handleMcpCustomTypeSelect = useCallback((serverType) => {
929
+ setUi((prev) => ({
930
+ ...prev,
931
+ mcpWizardServerType: serverType,
932
+ activeOverlay: 'mcp-custom-wizard',
933
+ }));
934
+ }, [setUi]);
935
+ // Handle MCP custom wizard completion
936
+ const handleMcpCustomWizardComplete = useCallback(async (config) => {
937
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
938
+ buffer.setText('');
939
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
940
+ setUi((prev) => ({ ...prev, isProcessing: true, isCancelling: false }));
941
+ setMessages((prev) => [
942
+ ...prev,
943
+ {
944
+ id: generateMessageId('system'),
945
+ role: 'system',
946
+ content: `šŸ”Œ Connecting to ${config.name}...`,
947
+ timestamp: new Date(),
948
+ },
949
+ ]);
950
+ try {
951
+ // Build the appropriate config based on server type
952
+ let serverConfig;
953
+ if (config.serverType === 'stdio') {
954
+ serverConfig = {
955
+ type: 'stdio',
956
+ command: config.command,
957
+ args: config.args || [],
958
+ };
959
+ }
960
+ else if (config.serverType === 'http') {
961
+ serverConfig = {
962
+ type: 'http',
963
+ url: config.url,
964
+ };
965
+ }
966
+ else {
967
+ // sse
968
+ serverConfig = {
969
+ type: 'sse',
970
+ url: config.url,
971
+ };
972
+ }
973
+ await agent.addMcpServer(config.name, serverConfig);
974
+ // Track MCP server connected analytics
975
+ capture('dexto_mcp_server_connected', {
976
+ source: 'cli',
977
+ serverName: config.name,
978
+ transportType: serverConfig.type,
979
+ });
980
+ setMessages((prev) => [
981
+ ...prev,
982
+ {
983
+ id: generateMessageId('system'),
984
+ role: 'system',
985
+ content: `āœ… Connected to ${config.name}`,
986
+ timestamp: new Date(),
987
+ },
988
+ ]);
989
+ }
990
+ catch (error) {
991
+ setMessages((prev) => [
992
+ ...prev,
993
+ {
994
+ id: generateMessageId('system'),
995
+ role: 'system',
996
+ content: `āŒ Failed to connect: ${error instanceof Error ? error.message : String(error)}`,
997
+ timestamp: new Date(),
998
+ },
999
+ ]);
1000
+ }
1001
+ setUi((prev) => ({
1002
+ ...prev,
1003
+ isProcessing: false,
1004
+ isCancelling: false,
1005
+ isThinking: false,
1006
+ }));
1007
+ }, [setUi, setInput, setMessages, agent, buffer]);
1008
+ // Handle session subcommand selection
1009
+ const handleSessionSubcommandSelect = useCallback(async (action) => {
1010
+ if (action === 'switch') {
1011
+ setInput((prev) => ({ ...prev, value: '/session switch' }));
1012
+ setUi((prev) => ({ ...prev, activeOverlay: 'session-selector' }));
1013
+ return;
1014
+ }
1015
+ setUi((prev) => ({ ...prev, activeOverlay: 'none', mcpWizardServerType: null }));
1016
+ buffer.setText('');
1017
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
1018
+ setUi((prev) => ({ ...prev, isProcessing: true, isCancelling: false }));
1019
+ try {
1020
+ const { CommandService } = await import('../services/CommandService.js');
1021
+ const commandService = new CommandService();
1022
+ const result = await commandService.executeCommand('session', [action], agent, session.id || undefined);
1023
+ if (result.type === 'output' && result.output) {
1024
+ const output = result.output;
1025
+ setMessages((prev) => [
1026
+ ...prev,
1027
+ {
1028
+ id: generateMessageId('command'),
1029
+ role: 'system',
1030
+ content: output,
1031
+ timestamp: new Date(),
1032
+ },
1033
+ ]);
1034
+ }
1035
+ if (result.type === 'styled' && result.styled) {
1036
+ const { fallbackText, styledType, styledData } = result.styled;
1037
+ setMessages((prev) => [
1038
+ ...prev,
1039
+ {
1040
+ id: generateMessageId('command'),
1041
+ role: 'system',
1042
+ content: fallbackText,
1043
+ timestamp: new Date(),
1044
+ styledType,
1045
+ styledData,
1046
+ },
1047
+ ]);
1048
+ }
1049
+ setUi((prev) => ({
1050
+ ...prev,
1051
+ isProcessing: false,
1052
+ isCancelling: false,
1053
+ isThinking: false,
1054
+ }));
1055
+ }
1056
+ catch (error) {
1057
+ setMessages((prev) => [
1058
+ ...prev,
1059
+ {
1060
+ id: generateMessageId('error'),
1061
+ role: 'system',
1062
+ content: `āŒ ${error instanceof Error ? error.message : String(error)}`,
1063
+ timestamp: new Date(),
1064
+ },
1065
+ ]);
1066
+ setUi((prev) => ({
1067
+ ...prev,
1068
+ isProcessing: false,
1069
+ isCancelling: false,
1070
+ isThinking: false,
1071
+ }));
1072
+ }
1073
+ }, [setInput, setUi, setMessages, agent, session.id, buffer]);
1074
+ // Handle prompt list actions (select/add/delete)
1075
+ const handlePromptListAction = useCallback(async (action) => {
1076
+ if (action.type === 'add-prompt') {
1077
+ setUi((prev) => ({
1078
+ ...prev,
1079
+ activeOverlay: 'prompt-add-choice',
1080
+ }));
1081
+ }
1082
+ else if (action.type === 'delete-prompt') {
1083
+ setUi((prev) => ({
1084
+ ...prev,
1085
+ activeOverlay: 'prompt-delete-selector',
1086
+ }));
1087
+ }
1088
+ else if (action.type === 'select-prompt') {
1089
+ // Execute the prompt
1090
+ const displayName = action.prompt.displayName || action.prompt.name;
1091
+ const commandText = `/${displayName}`;
1092
+ setUi((prev) => ({
1093
+ ...prev,
1094
+ activeOverlay: 'none',
1095
+ promptAddWizard: null,
1096
+ }));
1097
+ buffer.setText('');
1098
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
1099
+ // Route through streaming pipeline
1100
+ if (onSubmitPromptCommand) {
1101
+ await onSubmitPromptCommand(commandText);
1102
+ }
1103
+ }
1104
+ }, [setUi, setInput, buffer, onSubmitPromptCommand]);
1105
+ // Handle prompt list load into input
1106
+ const handlePromptLoadIntoInput = useCallback((text) => {
1107
+ buffer.setText(text);
1108
+ setInput((prev) => ({ ...prev, value: text }));
1109
+ setUi((prev) => ({
1110
+ ...prev,
1111
+ activeOverlay: 'none',
1112
+ promptAddWizard: null,
1113
+ }));
1114
+ }, [buffer, setInput, setUi]);
1115
+ // Handle prompt add choice (agent vs shared)
1116
+ const handlePromptAddChoice = useCallback((choice) => {
1117
+ if (choice === 'back') {
1118
+ setUi((prev) => ({
1119
+ ...prev,
1120
+ activeOverlay: 'prompt-list',
1121
+ }));
1122
+ }
1123
+ else {
1124
+ setUi((prev) => ({
1125
+ ...prev,
1126
+ activeOverlay: 'prompt-add-wizard',
1127
+ promptAddWizard: {
1128
+ scope: choice,
1129
+ step: 'name',
1130
+ name: '',
1131
+ title: '',
1132
+ description: '',
1133
+ content: '',
1134
+ },
1135
+ }));
1136
+ }
1137
+ }, [setUi]);
1138
+ // Handle prompt add wizard completion
1139
+ const handlePromptAddComplete = useCallback(async (data) => {
1140
+ const scope = ui.promptAddWizard?.scope || 'agent';
1141
+ setUi((prev) => ({
1142
+ ...prev,
1143
+ activeOverlay: 'none',
1144
+ promptAddWizard: null,
1145
+ }));
1146
+ buffer.setText('');
1147
+ setInput((prev) => ({ ...prev, historyIndex: -1 }));
1148
+ setMessages((prev) => [
1149
+ ...prev,
1150
+ {
1151
+ id: generateMessageId('system'),
1152
+ role: 'system',
1153
+ content: `šŸ“ Creating ${scope === 'shared' ? 'shared' : 'agent'} prompt "${data.name}"...`,
1154
+ timestamp: new Date(),
1155
+ },
1156
+ ]);
1157
+ try {
1158
+ const { mkdir, writeFile } = await import('fs/promises');
1159
+ const { dirname, join } = await import('path');
1160
+ // Validate prompt name to prevent path traversal
1161
+ const SAFE_NAME_PATTERN = /^[a-z0-9][a-z0-9-_]*$/i;
1162
+ if (!SAFE_NAME_PATTERN.test(data.name)) {
1163
+ throw new Error(`Invalid prompt name "${data.name}". Names must start with a letter or number and contain only letters, numbers, hyphens, and underscores.`);
1164
+ }
1165
+ // Build frontmatter
1166
+ const frontmatterLines = [
1167
+ '---',
1168
+ `id: ${data.name}`,
1169
+ data.title ? `title: "${data.title}"` : null,
1170
+ data.description ? `description: "${data.description}"` : null,
1171
+ data.argumentHint ? `argument-hint: ${data.argumentHint}` : null,
1172
+ '---',
1173
+ ].filter(Boolean);
1174
+ const fileContent = `${frontmatterLines.join('\n')}\n\n${data.content}\n`;
1175
+ let filePath;
1176
+ if (scope === 'shared') {
1177
+ // Create in commands directory based on execution context
1178
+ // Matches discovery logic in discoverCommandPrompts()
1179
+ const { getExecutionContext, findDextoSourceRoot, findDextoProjectRoot, getDextoGlobalPath, } = await import('@dexto/agent-management');
1180
+ const context = getExecutionContext();
1181
+ let commandsDir;
1182
+ if (context === 'dexto-source') {
1183
+ const isDevMode = process.env.DEXTO_DEV_MODE === 'true';
1184
+ if (isDevMode) {
1185
+ const sourceRoot = findDextoSourceRoot();
1186
+ commandsDir = sourceRoot
1187
+ ? join(sourceRoot, 'commands')
1188
+ : getDextoGlobalPath('commands');
1189
+ }
1190
+ else {
1191
+ commandsDir = getDextoGlobalPath('commands');
1192
+ }
1193
+ }
1194
+ else if (context === 'dexto-project') {
1195
+ const projectRoot = findDextoProjectRoot();
1196
+ commandsDir = projectRoot
1197
+ ? join(projectRoot, 'commands')
1198
+ : getDextoGlobalPath('commands');
1199
+ }
1200
+ else {
1201
+ // global-cli
1202
+ commandsDir = getDextoGlobalPath('commands');
1203
+ }
1204
+ filePath = join(commandsDir, `${data.name}.md`);
1205
+ await mkdir(commandsDir, { recursive: true });
1206
+ await writeFile(filePath, fileContent, 'utf-8');
1207
+ // Re-discover commands and refresh with enriched prompts
1208
+ const { reloadAgentConfigFromFile, enrichAgentConfig } = await import('@dexto/agent-management');
1209
+ const newConfig = await reloadAgentConfigFromFile(agent.getAgentFilePath());
1210
+ const enrichedConfig = enrichAgentConfig(newConfig, agent.getAgentFilePath());
1211
+ await agent.refreshPrompts(enrichedConfig.prompts);
1212
+ }
1213
+ else {
1214
+ // Create in agent's prompts directory
1215
+ const agentDir = dirname(agent.getAgentFilePath());
1216
+ const promptsDir = join(agentDir, 'prompts');
1217
+ filePath = join(promptsDir, `${data.name}.md`);
1218
+ await mkdir(promptsDir, { recursive: true });
1219
+ await writeFile(filePath, fileContent, 'utf-8');
1220
+ // Add file reference to agent config using surgical helper
1221
+ const { addPromptToAgentConfig, reloadAgentConfigFromFile, enrichAgentConfig, } = await import('@dexto/agent-management');
1222
+ await addPromptToAgentConfig(agent.getAgentFilePath(), {
1223
+ type: 'file',
1224
+ file: `\${{dexto.agent_dir}}/prompts/${data.name}.md`,
1225
+ });
1226
+ // Reload config from disk, enrich to include discovered commands, then refresh
1227
+ const newConfig = await reloadAgentConfigFromFile(agent.getAgentFilePath());
1228
+ const enrichedConfig = enrichAgentConfig(newConfig, agent.getAgentFilePath());
1229
+ await agent.refreshPrompts(enrichedConfig.prompts);
1230
+ }
1231
+ setMessages((prev) => [
1232
+ ...prev,
1233
+ {
1234
+ id: generateMessageId('system'),
1235
+ role: 'system',
1236
+ content: `āœ… Created prompt "${data.name}"\nšŸ“„ File: ${filePath}\n\nUse /${data.name} to run it.`,
1237
+ timestamp: new Date(),
1238
+ },
1239
+ ]);
1240
+ }
1241
+ catch (error) {
1242
+ setMessages((prev) => [
1243
+ ...prev,
1244
+ {
1245
+ id: generateMessageId('error'),
1246
+ role: 'system',
1247
+ content: `āŒ Failed to create prompt: ${error instanceof Error ? error.message : String(error)}`,
1248
+ timestamp: new Date(),
1249
+ },
1250
+ ]);
1251
+ }
1252
+ }, [ui.promptAddWizard?.scope, setUi, setInput, setMessages, buffer, agent]);
1253
+ // Handle prompt delete
1254
+ const handlePromptDelete = useCallback(async (deletable) => {
1255
+ const displayName = deletable.prompt.displayName || deletable.prompt.name;
1256
+ setMessages((prev) => [
1257
+ ...prev,
1258
+ {
1259
+ id: generateMessageId('system'),
1260
+ role: 'system',
1261
+ content: `šŸ—‘ļø Deleting prompt "${displayName}"...`,
1262
+ timestamp: new Date(),
1263
+ },
1264
+ ]);
1265
+ try {
1266
+ const { deletePromptByMetadata, reloadAgentConfigFromFile, enrichAgentConfig } = await import('@dexto/agent-management');
1267
+ // Use the higher-level delete function that handles file + config
1268
+ // Pass full metadata including originalId for inline prompt deletion
1269
+ const promptMetadata = deletable.prompt.metadata;
1270
+ const result = await deletePromptByMetadata(agent.getAgentFilePath(), {
1271
+ name: deletable.prompt.name,
1272
+ metadata: {
1273
+ filePath: deletable.filePath,
1274
+ originalId: promptMetadata?.originalId,
1275
+ },
1276
+ }, { deleteFile: true });
1277
+ if (!result.success) {
1278
+ throw new Error(result.error || 'Failed to delete prompt');
1279
+ }
1280
+ // Reload config from disk, enrich to include discovered commands, then refresh
1281
+ const newConfig = await reloadAgentConfigFromFile(agent.getAgentFilePath());
1282
+ const enrichedConfig = enrichAgentConfig(newConfig, agent.getAgentFilePath());
1283
+ await agent.refreshPrompts(enrichedConfig.prompts);
1284
+ setMessages((prev) => [
1285
+ ...prev,
1286
+ {
1287
+ id: generateMessageId('system'),
1288
+ role: 'system',
1289
+ content: `āœ… Deleted prompt "${displayName}"`,
1290
+ timestamp: new Date(),
1291
+ },
1292
+ ]);
1293
+ // Return to prompt list and refresh
1294
+ setUi((prev) => ({
1295
+ ...prev,
1296
+ activeOverlay: 'prompt-list',
1297
+ }));
1298
+ promptListRef.current?.refresh();
1299
+ }
1300
+ catch (error) {
1301
+ setMessages((prev) => [
1302
+ ...prev,
1303
+ {
1304
+ id: generateMessageId('error'),
1305
+ role: 'system',
1306
+ content: `āŒ Failed to delete prompt: ${error instanceof Error ? error.message : String(error)}`,
1307
+ timestamp: new Date(),
1308
+ },
1309
+ ]);
1310
+ // Return to prompt list even on error
1311
+ setUi((prev) => ({
1312
+ ...prev,
1313
+ activeOverlay: 'prompt-list',
1314
+ }));
1315
+ }
1316
+ }, [setUi, setMessages, agent]);
1317
+ // Handle prompt add wizard close
1318
+ const handlePromptAddWizardClose = useCallback(() => {
1319
+ setUi((prev) => ({
1320
+ ...prev,
1321
+ activeOverlay: 'prompt-add-choice',
1322
+ promptAddWizard: null,
1323
+ }));
1324
+ }, [setUi]);
1325
+ // Handle prompt delete selector close
1326
+ const handlePromptDeleteClose = useCallback(() => {
1327
+ setUi((prev) => ({
1328
+ ...prev,
1329
+ activeOverlay: 'prompt-list',
1330
+ }));
1331
+ // Refresh prompt list to show updated list
1332
+ promptListRef.current?.refresh();
1333
+ }, [setUi]);
1334
+ // Handle prompt add choice close
1335
+ const handlePromptAddChoiceClose = useCallback(() => {
1336
+ setUi((prev) => ({
1337
+ ...prev,
1338
+ activeOverlay: 'prompt-list',
1339
+ }));
1340
+ }, [setUi]);
1341
+ return (_jsxs(_Fragment, { children: [approval && (_jsx(ApprovalPrompt, { ref: approvalRef, approval: approval, onApprove: handleApprove, onDeny: handleDeny, onCancel: handleCancelApproval })), ui.activeOverlay === 'slash-autocomplete' && (_jsx(Box, { marginTop: 1, children: _jsx(SlashCommandAutocomplete, { ref: slashAutocompleteRef, isVisible: true, searchQuery: input.value, onSelectPrompt: handlePromptSelect, onSelectSystemCommand: handleSystemCommandSelect, onLoadIntoInput: handleLoadIntoInput, onSubmitRaw: onSubmitPromptCommand, onClose: handleClose, agent: agent }) })), ui.activeOverlay === 'resource-autocomplete' && (_jsx(Box, { marginTop: 1, children: _jsx(ResourceAutocomplete, { ref: resourceAutocompleteRef, isVisible: true, searchQuery: input.value, onSelectResource: handleResourceSelect, onLoadIntoInput: handleLoadIntoInput, onClose: handleClose, agent: agent }) })), ui.activeOverlay === 'model-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(ModelSelectorRefactored, { ref: modelSelectorRef, isVisible: true, onSelectModel: handleModelSelect, onClose: handleClose, onAddCustomModel: handleAddCustomModel, onEditCustomModel: handleEditCustomModel, agent: agent }) })), ui.activeOverlay === 'session-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(SessionSelectorRefactored, { ref: sessionSelectorRef, isVisible: true, onSelectSession: handleSessionSelect, onClose: handleClose, agent: agent, currentSessionId: session.id || undefined }) })), ui.activeOverlay === 'log-level-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(LogLevelSelector, { ref: logLevelSelectorRef, isVisible: true, onSelect: handleLogLevelSelect, onClose: handleClose, agent: agent }) })), ui.activeOverlay === 'stream-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(StreamSelector, { ref: streamSelectorRef, isVisible: true, onSelect: handleStreamSelect, onClose: handleClose }) })), ui.activeOverlay === 'tool-browser' && (_jsx(Box, { marginTop: 1, children: _jsx(ToolBrowser, { ref: toolBrowserRef, isVisible: true, onClose: handleClose, agent: agent }) })), ui.activeOverlay === 'mcp-server-list' && (_jsx(Box, { marginTop: 1, children: _jsx(McpServerList, { ref: mcpServerListRef, isVisible: true, onAction: handleMcpServerListAction, onClose: handleClose, agent: agent }) })), ui.activeOverlay === 'mcp-server-actions' && ui.selectedMcpServer && (_jsx(Box, { marginTop: 1, children: _jsx(McpServerActions, { ref: mcpServerActionsRef, isVisible: true, server: ui.selectedMcpServer, onAction: handleMcpServerAction, onClose: handleClose }) })), ui.activeOverlay === 'mcp-add-choice' && (_jsx(Box, { marginTop: 1, children: _jsx(McpAddChoice, { ref: mcpAddChoiceRef, isVisible: true, onSelect: handleMcpAddChoice, onClose: handleClose }) })), ui.activeOverlay === 'mcp-add-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(McpAddSelector, { ref: mcpAddSelectorRef, isVisible: true, onSelect: handleMcpAddSelect, onClose: handleClose }) })), ui.activeOverlay === 'mcp-custom-type-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(McpCustomTypeSelector, { ref: mcpCustomTypeSelectorRef, isVisible: true, onSelect: handleMcpCustomTypeSelect, onClose: handleClose }) })), ui.activeOverlay === 'mcp-custom-wizard' && ui.mcpWizardServerType && (_jsx(McpCustomWizard, { ref: mcpCustomWizardRef, isVisible: true, serverType: ui.mcpWizardServerType, onComplete: handleMcpCustomWizardComplete, onClose: handleClose })), ui.activeOverlay === 'custom-model-wizard' && (_jsx(CustomModelWizard, { ref: customModelWizardRef, isVisible: true, onComplete: handleCustomModelComplete, onClose: () => {
1342
+ setEditingModel(null);
1343
+ handleClose();
1344
+ }, initialModel: editingModel })), ui.activeOverlay === 'session-subcommand-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(SessionSubcommandSelector, { ref: sessionSubcommandSelectorRef, isVisible: true, onSelect: handleSessionSubcommandSelect, onClose: handleClose }) })), ui.activeOverlay === 'api-key-input' && ui.pendingModelSwitch && (_jsx(ApiKeyInput, { ref: apiKeyInputRef, isVisible: true, provider: ui.pendingModelSwitch.provider, onSaved: handleApiKeySaved, onClose: handleApiKeyClose })), ui.activeOverlay === 'search' && (_jsx(SearchOverlay, { ref: searchOverlayRef, isVisible: true, agent: agent, onClose: handleClose, onSelectResult: handleSearchResultSelect })), ui.activeOverlay === 'prompt-list' && (_jsx(Box, { marginTop: 1, children: _jsx(PromptList, { ref: promptListRef, isVisible: true, onAction: handlePromptListAction, onLoadIntoInput: handlePromptLoadIntoInput, onClose: handleClose, agent: agent }) })), ui.activeOverlay === 'prompt-add-choice' && (_jsx(Box, { marginTop: 1, children: _jsx(PromptAddChoice, { ref: promptAddChoiceRef, isVisible: true, onSelect: handlePromptAddChoice, onClose: handlePromptAddChoiceClose }) })), ui.activeOverlay === 'prompt-add-wizard' && ui.promptAddWizard && (_jsx(PromptAddWizard, { ref: promptAddWizardRef, isVisible: true, scope: ui.promptAddWizard.scope, onComplete: handlePromptAddComplete, onClose: handlePromptAddWizardClose })), ui.activeOverlay === 'prompt-delete-selector' && (_jsx(Box, { marginTop: 1, children: _jsx(PromptDeleteSelector, { ref: promptDeleteSelectorRef, isVisible: true, onDelete: handlePromptDelete, onClose: handlePromptDeleteClose, agent: agent }) }))] }));
1345
+ });