dexto 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +62 -7
  2. package/dist/agents/agent-template.yml +2 -2
  3. package/dist/agents/coding-agent/coding-agent.yml +22 -16
  4. package/dist/agents/database-agent/database-agent.yml +2 -2
  5. package/dist/agents/default-agent.yml +7 -5
  6. package/dist/agents/github-agent/github-agent.yml +2 -2
  7. package/dist/agents/product-name-researcher/product-name-researcher.yml +2 -2
  8. package/dist/agents/talk2pdf-agent/talk2pdf-agent.yml +2 -2
  9. package/dist/analytics/events.d.ts +13 -6
  10. package/dist/analytics/events.d.ts.map +1 -1
  11. package/dist/analytics/index.d.ts +1 -1
  12. package/dist/analytics/index.d.ts.map +1 -1
  13. package/dist/analytics/index.js +6 -2
  14. package/dist/api/server-hono.d.ts.map +1 -1
  15. package/dist/api/server-hono.js +27 -5
  16. package/dist/cli/cli-subscriber.d.ts +4 -0
  17. package/dist/cli/cli-subscriber.d.ts.map +1 -1
  18. package/dist/cli/cli-subscriber.js +40 -2
  19. package/dist/cli/commands/create-app.d.ts +16 -14
  20. package/dist/cli/commands/create-app.d.ts.map +1 -1
  21. package/dist/cli/commands/create-app.js +626 -102
  22. package/dist/cli/commands/create-image.d.ts +7 -0
  23. package/dist/cli/commands/create-image.d.ts.map +1 -0
  24. package/dist/cli/commands/create-image.js +201 -0
  25. package/dist/cli/commands/helpers/formatters.js +7 -7
  26. package/dist/cli/commands/index.d.ts +2 -1
  27. package/dist/cli/commands/index.d.ts.map +1 -1
  28. package/dist/cli/commands/index.js +2 -1
  29. package/dist/cli/commands/init-app.js +7 -7
  30. package/dist/cli/commands/install.d.ts +0 -3
  31. package/dist/cli/commands/install.d.ts.map +1 -1
  32. package/dist/cli/commands/install.js +10 -35
  33. package/dist/cli/commands/interactive-commands/command-parser.d.ts +1 -1
  34. package/dist/cli/commands/interactive-commands/command-parser.d.ts.map +1 -1
  35. package/dist/cli/commands/interactive-commands/command-parser.js +18 -8
  36. package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
  37. package/dist/cli/commands/interactive-commands/general-commands.js +64 -1
  38. package/dist/cli/commands/interactive-commands/prompt-commands.js +11 -11
  39. package/dist/cli/commands/interactive-commands/system/system-commands.d.ts.map +1 -1
  40. package/dist/cli/commands/interactive-commands/system/system-commands.js +6 -5
  41. package/dist/cli/commands/list-agents.js +2 -2
  42. package/dist/cli/commands/session-commands.js +16 -16
  43. package/dist/cli/commands/setup.d.ts +13 -5
  44. package/dist/cli/commands/setup.d.ts.map +1 -1
  45. package/dist/cli/commands/setup.js +995 -65
  46. package/dist/cli/commands/which.js +1 -1
  47. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts +2 -0
  48. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
  49. package/dist/cli/ink-cli/components/ApprovalPrompt.js +29 -7
  50. package/dist/cli/ink-cli/components/CustomInput.js +1 -1
  51. package/dist/cli/ink-cli/components/EditableMultiLineInput.js +4 -4
  52. package/dist/cli/ink-cli/components/ElicitationForm.d.ts.map +1 -1
  53. package/dist/cli/ink-cli/components/ElicitationForm.js +6 -6
  54. package/dist/cli/ink-cli/components/ErrorBoundary.d.ts.map +1 -1
  55. package/dist/cli/ink-cli/components/ErrorBoundary.js +1 -1
  56. package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
  57. package/dist/cli/ink-cli/components/Footer.js +1 -1
  58. package/dist/cli/ink-cli/components/HistorySearchBar.d.ts.map +1 -1
  59. package/dist/cli/ink-cli/components/HistorySearchBar.js +1 -1
  60. package/dist/cli/ink-cli/components/MultiLineInput.d.ts.map +1 -1
  61. package/dist/cli/ink-cli/components/MultiLineInput.js +3 -3
  62. package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
  63. package/dist/cli/ink-cli/components/ResourceAutocomplete.js +4 -4
  64. package/dist/cli/ink-cli/components/SlashCommandAutocomplete.js +3 -3
  65. package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
  66. package/dist/cli/ink-cli/components/StatusBar.js +7 -5
  67. package/dist/cli/ink-cli/components/TextBufferInput.d.ts.map +1 -1
  68. package/dist/cli/ink-cli/components/TextBufferInput.js +13 -9
  69. package/dist/cli/ink-cli/components/base/BaseAutocomplete.js +4 -4
  70. package/dist/cli/ink-cli/components/base/BaseSelector.js +2 -2
  71. package/dist/cli/ink-cli/components/chat/Footer.js +1 -1
  72. package/dist/cli/ink-cli/components/chat/Header.d.ts.map +1 -1
  73. package/dist/cli/ink-cli/components/chat/Header.js +2 -4
  74. package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
  75. package/dist/cli/ink-cli/components/chat/MessageItem.js +9 -6
  76. package/dist/cli/ink-cli/components/chat/MessageList.js +1 -1
  77. package/dist/cli/ink-cli/components/chat/QueuedMessagesDisplay.js +1 -1
  78. package/dist/cli/ink-cli/components/chat/ToolIcon.d.ts +1 -1
  79. package/dist/cli/ink-cli/components/chat/ToolIcon.js +4 -4
  80. package/dist/cli/ink-cli/components/chat/styled-boxes/ConfigBox.js +1 -1
  81. package/dist/cli/ink-cli/components/chat/styled-boxes/HelpBox.js +1 -1
  82. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.d.ts.map +1 -1
  83. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +2 -2
  84. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionHistoryBox.js +5 -5
  85. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionListBox.js +2 -2
  86. package/dist/cli/ink-cli/components/chat/styled-boxes/ShortcutsBox.js +1 -1
  87. package/dist/cli/ink-cli/components/chat/styled-boxes/StatsBox.js +1 -1
  88. package/dist/cli/ink-cli/components/chat/styled-boxes/StyledBox.js +2 -2
  89. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
  90. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +1 -1
  91. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
  92. package/dist/cli/ink-cli/components/modes/StaticCLI.js +1 -1
  93. package/dist/cli/ink-cli/components/overlays/ApiKeyInput.js +1 -1
  94. package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts +10 -2
  95. package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts.map +1 -1
  96. package/dist/cli/ink-cli/components/overlays/CustomModelWizard.js +209 -89
  97. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.d.ts.map +1 -1
  98. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +2 -2
  99. package/dist/cli/ink-cli/components/overlays/McpAddChoice.d.ts.map +1 -1
  100. package/dist/cli/ink-cli/components/overlays/McpAddChoice.js +1 -1
  101. package/dist/cli/ink-cli/components/overlays/McpAddSelector.js +1 -1
  102. package/dist/cli/ink-cli/components/overlays/McpCustomTypeSelector.d.ts.map +1 -1
  103. package/dist/cli/ink-cli/components/overlays/McpCustomTypeSelector.js +2 -2
  104. package/dist/cli/ink-cli/components/overlays/McpCustomWizard.js +1 -1
  105. package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.d.ts.map +1 -1
  106. package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.js +1 -1
  107. package/dist/cli/ink-cli/components/overlays/McpSelector.d.ts.map +1 -1
  108. package/dist/cli/ink-cli/components/overlays/McpSelector.js +1 -1
  109. package/dist/cli/ink-cli/components/overlays/McpServerActions.d.ts.map +1 -1
  110. package/dist/cli/ink-cli/components/overlays/McpServerActions.js +2 -2
  111. package/dist/cli/ink-cli/components/overlays/McpServerList.d.ts.map +1 -1
  112. package/dist/cli/ink-cli/components/overlays/McpServerList.js +1 -1
  113. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts +6 -5
  114. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
  115. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +284 -68
  116. package/dist/cli/ink-cli/components/overlays/PromptAddChoice.d.ts.map +1 -1
  117. package/dist/cli/ink-cli/components/overlays/PromptAddChoice.js +2 -2
  118. package/dist/cli/ink-cli/components/overlays/PromptAddWizard.js +1 -1
  119. package/dist/cli/ink-cli/components/overlays/PromptDeleteSelector.d.ts.map +1 -1
  120. package/dist/cli/ink-cli/components/overlays/PromptDeleteSelector.js +2 -2
  121. package/dist/cli/ink-cli/components/overlays/PromptList.d.ts.map +1 -1
  122. package/dist/cli/ink-cli/components/overlays/PromptList.js +2 -2
  123. package/dist/cli/ink-cli/components/overlays/SearchOverlay.d.ts.map +1 -1
  124. package/dist/cli/ink-cli/components/overlays/SearchOverlay.js +4 -4
  125. package/dist/cli/ink-cli/components/overlays/SessionSubcommandSelector.d.ts.map +1 -1
  126. package/dist/cli/ink-cli/components/overlays/SessionSubcommandSelector.js +1 -1
  127. package/dist/cli/ink-cli/components/overlays/StreamSelector.d.ts.map +1 -1
  128. package/dist/cli/ink-cli/components/overlays/StreamSelector.js +1 -1
  129. package/dist/cli/ink-cli/components/overlays/ToolBrowser.js +12 -12
  130. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts +25 -0
  131. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts.map +1 -0
  132. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.js +609 -0
  133. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.d.ts +15 -0
  134. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.d.ts.map +1 -0
  135. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.js +14 -0
  136. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts +33 -0
  137. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts.map +1 -0
  138. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.js +462 -0
  139. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.d.ts +25 -0
  140. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.d.ts.map +1 -0
  141. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.js +29 -0
  142. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.d.ts +17 -0
  143. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.d.ts.map +1 -0
  144. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.js +11 -0
  145. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.d.ts +20 -0
  146. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.d.ts.map +1 -0
  147. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.js +10 -0
  148. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.d.ts +30 -0
  149. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.d.ts.map +1 -0
  150. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.js +13 -0
  151. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.d.ts +8 -0
  152. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.d.ts.map +1 -0
  153. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.js +7 -0
  154. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts +85 -0
  155. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts.map +1 -0
  156. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.js +38 -0
  157. package/dist/cli/ink-cli/components/renderers/DiffRenderer.js +2 -2
  158. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.js +1 -1
  159. package/dist/cli/ink-cli/components/renderers/FileRenderer.js +4 -4
  160. package/dist/cli/ink-cli/components/renderers/GenericRenderer.js +2 -2
  161. package/dist/cli/ink-cli/components/renderers/SearchRenderer.js +1 -1
  162. package/dist/cli/ink-cli/components/renderers/ShellRenderer.js +3 -3
  163. package/dist/cli/ink-cli/components/renderers/diff-shared.js +1 -1
  164. package/dist/cli/ink-cli/components/shared/MarkdownText.d.ts.map +1 -1
  165. package/dist/cli/ink-cli/components/shared/MarkdownText.js +8 -6
  166. package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
  167. package/dist/cli/ink-cli/containers/InputContainer.js +23 -1
  168. package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
  169. package/dist/cli/ink-cli/containers/OverlayContainer.js +81 -25
  170. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts +9 -2
  171. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts.map +1 -1
  172. package/dist/cli/ink-cli/hooks/useAgentEvents.js +148 -6
  173. package/dist/cli/ink-cli/hooks/useCLIState.d.ts +1 -1
  174. package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
  175. package/dist/cli/ink-cli/hooks/useCLIState.js +7 -2
  176. package/dist/cli/ink-cli/hooks/useTokenCounter.d.ts +11 -7
  177. package/dist/cli/ink-cli/hooks/useTokenCounter.d.ts.map +1 -1
  178. package/dist/cli/ink-cli/hooks/useTokenCounter.js +41 -18
  179. package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
  180. package/dist/cli/ink-cli/services/processStream.js +97 -17
  181. package/dist/cli/ink-cli/state/types.d.ts +5 -4
  182. package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
  183. package/dist/cli/ink-cli/utils/messageFormatting.d.ts +5 -0
  184. package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
  185. package/dist/cli/ink-cli/utils/messageFormatting.js +59 -1
  186. package/dist/cli/ink-cli/utils/toolUtils.d.ts.map +1 -1
  187. package/dist/cli/ink-cli/utils/toolUtils.js +2 -0
  188. package/dist/cli/utils/api-key-setup.d.ts +54 -4
  189. package/dist/cli/utils/api-key-setup.d.ts.map +1 -1
  190. package/dist/cli/utils/api-key-setup.js +433 -107
  191. package/dist/cli/utils/api-key-verification.d.ts +17 -0
  192. package/dist/cli/utils/api-key-verification.d.ts.map +1 -0
  193. package/dist/cli/utils/api-key-verification.js +211 -0
  194. package/dist/cli/utils/config-validation.d.ts +22 -2
  195. package/dist/cli/utils/config-validation.d.ts.map +1 -1
  196. package/dist/cli/utils/config-validation.js +354 -25
  197. package/dist/cli/utils/local-model-setup.d.ts +46 -0
  198. package/dist/cli/utils/local-model-setup.d.ts.map +1 -0
  199. package/dist/cli/utils/local-model-setup.js +662 -0
  200. package/dist/cli/utils/options.js +1 -1
  201. package/dist/cli/utils/prompt-helpers.d.ts +47 -0
  202. package/dist/cli/utils/prompt-helpers.d.ts.map +1 -0
  203. package/dist/cli/utils/prompt-helpers.js +66 -0
  204. package/dist/cli/utils/provider-setup.d.ts +66 -8
  205. package/dist/cli/utils/provider-setup.d.ts.map +1 -1
  206. package/dist/cli/utils/provider-setup.js +324 -84
  207. package/dist/cli/utils/scaffolding-utils.d.ts +76 -0
  208. package/dist/cli/utils/scaffolding-utils.d.ts.map +1 -0
  209. package/dist/cli/utils/scaffolding-utils.js +246 -0
  210. package/dist/cli/utils/setup-utils.d.ts +16 -0
  211. package/dist/cli/utils/setup-utils.d.ts.map +1 -1
  212. package/dist/cli/utils/setup-utils.js +72 -21
  213. package/dist/cli/utils/template-engine.d.ts +65 -0
  214. package/dist/cli/utils/template-engine.d.ts.map +1 -0
  215. package/dist/cli/utils/template-engine.js +1089 -0
  216. package/dist/config/cli-overrides.d.ts +44 -1
  217. package/dist/config/cli-overrides.d.ts.map +1 -1
  218. package/dist/config/cli-overrides.js +102 -0
  219. package/dist/index.js +339 -56
  220. package/dist/webui/assets/index-8j-KMkX1.js +2054 -0
  221. package/dist/webui/assets/index-c_AX24V4.css +1 -0
  222. package/dist/webui/index.html +3 -9
  223. package/dist/webui/logos/aws-color.svg +1 -0
  224. package/dist/webui/logos/dexto/dexto_logo.svg +1 -1
  225. package/dist/webui/logos/dexto/dexto_logo_light.svg +6 -6
  226. package/dist/webui/logos/glama.svg +7 -0
  227. package/dist/webui/logos/litellm.svg +7 -0
  228. package/dist/webui/logos/openrouter.svg +1 -0
  229. package/package.json +8 -7
  230. package/dist/webui/assets/index-BkwPkZpd.css +0 -1
  231. package/dist/webui/assets/index-D9u1XfyH.js +0 -2025
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Consistent prompt helpers for CLI flows.
3
+ *
4
+ * These helpers wrap @clack/prompts with automatic cancel handling.
5
+ * Use for linear flows where cancel should exit the process.
6
+ */
7
+ import * as p from '@clack/prompts';
8
+ type SelectOptions = Parameters<typeof p.select>[0];
9
+ type TextOptions = Parameters<typeof p.text>[0];
10
+ type ConfirmOptions = Parameters<typeof p.confirm>[0];
11
+ /**
12
+ * Select prompt that exits on cancel.
13
+ * Use for linear flows where cancel should abort the entire operation.
14
+ *
15
+ * @example
16
+ * const choice = await selectOrExit<'a' | 'b'>({
17
+ * message: 'Pick one',
18
+ * options: [{ value: 'a', label: 'A' }, { value: 'b', label: 'B' }]
19
+ * }, 'Operation cancelled');
20
+ */
21
+ export declare function selectOrExit<T extends string>(options: SelectOptions, cancelMessage?: string): Promise<T>;
22
+ /**
23
+ * Text prompt that exits on cancel.
24
+ * Use for linear flows where cancel should abort the entire operation.
25
+ *
26
+ * @example
27
+ * const name = await textOrExit({
28
+ * message: 'Enter your name',
29
+ * placeholder: 'John Doe'
30
+ * }, 'Operation cancelled');
31
+ */
32
+ export declare function textOrExit(options: TextOptions, cancelMessage?: string): Promise<string>;
33
+ /**
34
+ * Confirm prompt that exits on cancel.
35
+ * Use for linear flows where cancel should abort the entire operation.
36
+ *
37
+ * Note: This only exits on cancel (Ctrl+C), not when user selects "No".
38
+ * For "must confirm or abort" behavior, check the return value separately.
39
+ *
40
+ * @example
41
+ * const confirmed = await confirmOrExit({
42
+ * message: 'Are you sure?'
43
+ * }, 'Operation cancelled');
44
+ */
45
+ export declare function confirmOrExit(options: ConfirmOptions, cancelMessage?: string): Promise<boolean>;
46
+ export {};
47
+ //# sourceMappingURL=prompt-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-helpers.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/prompt-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAMpC,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAMtD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,EAC/C,OAAO,EAAE,aAAa,EACtB,aAAa,SAAc,GAC5B,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC5B,OAAO,EAAE,WAAW,EACpB,aAAa,SAAc,GAC5B,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAC/B,OAAO,EAAE,cAAc,EACvB,aAAa,SAAc,GAC5B,OAAO,CAAC,OAAO,CAAC,CAOlB"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Consistent prompt helpers for CLI flows.
3
+ *
4
+ * These helpers wrap @clack/prompts with automatic cancel handling.
5
+ * Use for linear flows where cancel should exit the process.
6
+ */
7
+ import * as p from '@clack/prompts';
8
+ // =============================================================================
9
+ // LINEAR FLOW HELPERS (cancel = exit)
10
+ // =============================================================================
11
+ /**
12
+ * Select prompt that exits on cancel.
13
+ * Use for linear flows where cancel should abort the entire operation.
14
+ *
15
+ * @example
16
+ * const choice = await selectOrExit<'a' | 'b'>({
17
+ * message: 'Pick one',
18
+ * options: [{ value: 'a', label: 'A' }, { value: 'b', label: 'B' }]
19
+ * }, 'Operation cancelled');
20
+ */
21
+ export async function selectOrExit(options, cancelMessage = 'Cancelled') {
22
+ const result = await p.select(options);
23
+ if (p.isCancel(result)) {
24
+ p.cancel(cancelMessage);
25
+ process.exit(0);
26
+ }
27
+ return result;
28
+ }
29
+ /**
30
+ * Text prompt that exits on cancel.
31
+ * Use for linear flows where cancel should abort the entire operation.
32
+ *
33
+ * @example
34
+ * const name = await textOrExit({
35
+ * message: 'Enter your name',
36
+ * placeholder: 'John Doe'
37
+ * }, 'Operation cancelled');
38
+ */
39
+ export async function textOrExit(options, cancelMessage = 'Cancelled') {
40
+ const result = await p.text(options);
41
+ if (p.isCancel(result)) {
42
+ p.cancel(cancelMessage);
43
+ process.exit(0);
44
+ }
45
+ return result;
46
+ }
47
+ /**
48
+ * Confirm prompt that exits on cancel.
49
+ * Use for linear flows where cancel should abort the entire operation.
50
+ *
51
+ * Note: This only exits on cancel (Ctrl+C), not when user selects "No".
52
+ * For "must confirm or abort" behavior, check the return value separately.
53
+ *
54
+ * @example
55
+ * const confirmed = await confirmOrExit({
56
+ * message: 'Are you sure?'
57
+ * }, 'Operation cancelled');
58
+ */
59
+ export async function confirmOrExit(options, cancelMessage = 'Cancelled') {
60
+ const result = await p.confirm(options);
61
+ if (p.isCancel(result)) {
62
+ p.cancel(cancelMessage);
63
+ process.exit(0);
64
+ }
65
+ return result;
66
+ }
@@ -1,23 +1,62 @@
1
1
  import { type LLMProvider } from '@dexto/core';
2
2
  /**
3
- * Standardized provider options used across all setup flows
3
+ * Provider category for organizing the selection menu
4
+ */
5
+ type ProviderCategory = 'recommended' | 'local' | 'cloud' | 'gateway' | 'enterprise';
6
+ /**
7
+ * Extended provider information for setup
8
+ */
9
+ interface ProviderOption {
10
+ value: LLMProvider;
11
+ label: string;
12
+ hint: string;
13
+ category: ProviderCategory;
14
+ apiKeyUrl?: string;
15
+ apiKeyPrefix?: string;
16
+ apiKeyMinLength?: number;
17
+ requiresBaseURL?: boolean;
18
+ envVar: string;
19
+ free?: boolean;
20
+ }
21
+ /**
22
+ * Provider configuration registry
23
+ * Organized by category for better UX
24
+ */
25
+ export declare const PROVIDER_REGISTRY: Partial<Record<LLMProvider, ProviderOption>>;
26
+ /**
27
+ * Interactive provider selection with back option.
28
+ * @returns Selected provider, '_back' if back selected, or null if cancelled
29
+ */
30
+ export declare function selectProvider(): Promise<LLMProvider | '_back' | null>;
31
+ /**
32
+ * Get provider display name
33
+ */
34
+ export declare function getProviderDisplayName(provider: LLMProvider): string;
35
+ /**
36
+ * Get provider option info
37
+ */
38
+ export declare function getProviderInfo(provider: LLMProvider): ProviderOption | undefined;
39
+ /**
40
+ * Legacy PROVIDER_OPTIONS for backwards compatibility with init-app
4
41
  */
5
42
  export declare const PROVIDER_OPTIONS: {
6
- value: string;
43
+ value: LLMProvider;
7
44
  label: string;
8
45
  hint: string;
9
46
  }[];
10
47
  /**
11
- * Interactive provider selection using standardized options
12
- * @returns Selected provider or null if cancelled
48
+ * Get API key format hint for a provider
13
49
  */
14
- export declare function selectProvider(): Promise<LLMProvider>;
50
+ export declare function getApiKeyFormatHint(provider: LLMProvider): string | null;
15
51
  /**
16
- * Gets display name for a provider
52
+ * Validates API key format for a provider with detailed error messages
17
53
  */
18
- export declare function getProviderDisplayName(provider: LLMProvider): string;
54
+ export declare function validateApiKeyFormat(apiKey: string, provider: LLMProvider): {
55
+ valid: boolean;
56
+ error?: string;
57
+ };
19
58
  /**
20
- * Validates API key format for a provider
59
+ * Legacy validation function for backwards compatibility
21
60
  */
22
61
  export declare function isValidApiKeyFormat(apiKey: string, provider: LLMProvider): boolean;
23
62
  /**
@@ -26,5 +65,24 @@ export declare function isValidApiKeyFormat(apiKey: string, provider: LLMProvide
26
65
  export declare function getProviderInstructions(provider: LLMProvider): {
27
66
  title: string;
28
67
  content: string;
68
+ url?: string | undefined;
29
69
  } | null;
70
+ /**
71
+ * Open the API key URL in the browser
72
+ */
73
+ export declare function openApiKeyUrl(provider: LLMProvider): Promise<boolean>;
74
+ /**
75
+ * Check if provider requires a base URL
76
+ */
77
+ export declare function providerRequiresBaseURL(provider: LLMProvider): boolean;
78
+ /**
79
+ * Get default model for provider, with fallback for custom providers
80
+ */
81
+ export declare function getDefaultModel(provider: LLMProvider): string;
82
+ /**
83
+ * Get environment variable name for provider's API key.
84
+ * Uses the canonical env var from the core api-key-resolver.
85
+ */
86
+ export declare function getProviderEnvVar(provider: LLMProvider): string;
87
+ export {};
30
88
  //# sourceMappingURL=provider-setup.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider-setup.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/provider-setup.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;GAqB5B,CAAC;AAEF;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAY3D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAapE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAalF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACnC,QAAQ,EAAE,WAAW,GACtB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA6C3C"}
1
+ {"version":3,"file":"provider-setup.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/provider-setup.ts"],"names":[],"mappings":"AAKA,OAAO,EACH,KAAK,WAAW,EAInB,MAAM,aAAa,CAAC;AAGrB;;GAEG;AACH,KAAK,gBAAgB,GAAG,aAAa,GAAG,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,YAAY,CAAC;AAErF;;GAEG;AACH,UAAU,cAAc;IACpB,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,CA8H1E,CAAC;AA0FF;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,OAAO,GAAG,IAAI,CAAC,CAoB5E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAEpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,WAAW,GAAG,cAAc,GAAG,SAAS,CAEjF;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;WA1GmB,WAAW;WAAS,MAAM;UAAQ,MAAM;GA0GlC,CAAC;AAEvD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,GAAG,IAAI,CAIxE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,WAAW,GACtB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CA0BpC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAElF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACnC,QAAQ,EAAE,WAAW,GACtB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,IAAI,CAwBrE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAU3E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAEtE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAY7D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,WAAW,GAAG,MAAM,CAE/D"}
@@ -1,122 +1,362 @@
1
1
  // packages/cli/src/cli/utils/provider-setup.ts
2
2
  import * as p from '@clack/prompts';
3
3
  import chalk from 'chalk';
4
+ import open from 'open';
5
+ import { LLM_PROVIDERS, LLM_REGISTRY, getDefaultModelForProvider, } from '@dexto/core';
6
+ import { getPrimaryApiKeyEnvVar } from '@dexto/agent-management';
4
7
  /**
5
- * Standardized provider options used across all setup flows
8
+ * Provider configuration registry
9
+ * Organized by category for better UX
6
10
  */
7
- export const PROVIDER_OPTIONS = [
8
- {
11
+ export const PROVIDER_REGISTRY = {
12
+ google: {
9
13
  value: 'google',
10
- label: '🟢 Google Gemini',
11
- hint: 'Free tier available - Recommended for beginners',
14
+ label: 'Google Gemini',
15
+ hint: 'Free tier, 1M+ context, multimodal',
16
+ category: 'recommended',
17
+ apiKeyUrl: 'https://aistudio.google.com/apikey',
18
+ apiKeyPrefix: 'AIza',
19
+ apiKeyMinLength: 20,
20
+ envVar: 'GOOGLE_API_KEY',
21
+ free: true,
12
22
  },
13
- {
23
+ groq: {
14
24
  value: 'groq',
15
- label: '🟢 Groq',
16
- hint: 'Free tier available - Very fast responses',
25
+ label: 'Groq',
26
+ hint: 'Free tier, ultra-fast inference',
27
+ category: 'recommended',
28
+ apiKeyUrl: 'https://console.groq.com/keys',
29
+ apiKeyPrefix: 'gsk_',
30
+ apiKeyMinLength: 40,
31
+ envVar: 'GROQ_API_KEY',
32
+ free: true,
17
33
  },
18
- {
34
+ // Local providers - run AI completely on your machine
35
+ local: {
36
+ value: 'local',
37
+ label: 'Local Models',
38
+ hint: 'Run Llama, Qwen, Mistral locally - Free, private, offline',
39
+ category: 'local',
40
+ envVar: '', // No API key required
41
+ free: true,
42
+ },
43
+ ollama: {
44
+ value: 'ollama',
45
+ label: 'Ollama',
46
+ hint: 'Use Ollama server for local inference',
47
+ category: 'local',
48
+ envVar: '', // No API key required (optional OLLAMA_API_KEY for remote)
49
+ free: true,
50
+ },
51
+ openai: {
19
52
  value: 'openai',
20
- label: '🟡 OpenAI',
21
- hint: 'Most popular, requires payment',
53
+ label: 'OpenAI',
54
+ hint: 'GPT-4o, GPT-5, o1/o3 reasoning',
55
+ category: 'cloud',
56
+ apiKeyUrl: 'https://platform.openai.com/api-keys',
57
+ apiKeyPrefix: 'sk-',
58
+ apiKeyMinLength: 40,
59
+ envVar: 'OPENAI_API_KEY',
22
60
  },
23
- {
61
+ anthropic: {
24
62
  value: 'anthropic',
25
- label: '🟡 Anthropic',
26
- hint: 'High quality models, requires payment',
63
+ label: 'Anthropic',
64
+ hint: 'Claude 4.5, best for coding',
65
+ category: 'cloud',
66
+ apiKeyUrl: 'https://console.anthropic.com/settings/keys',
67
+ apiKeyPrefix: 'sk-ant-',
68
+ apiKeyMinLength: 40,
69
+ envVar: 'ANTHROPIC_API_KEY',
70
+ },
71
+ xai: {
72
+ value: 'xai',
73
+ label: 'xAI',
74
+ hint: 'Grok models',
75
+ category: 'cloud',
76
+ apiKeyUrl: 'https://console.x.ai/team/default/api-keys',
77
+ envVar: 'XAI_API_KEY',
78
+ },
79
+ cohere: {
80
+ value: 'cohere',
81
+ label: 'Cohere',
82
+ hint: 'Command models, RAG-optimized',
83
+ category: 'cloud',
84
+ apiKeyUrl: 'https://dashboard.cohere.com/api-keys',
85
+ envVar: 'COHERE_API_KEY',
86
+ },
87
+ openrouter: {
88
+ value: 'openrouter',
89
+ label: 'OpenRouter',
90
+ hint: '100+ models, unified API',
91
+ category: 'gateway',
92
+ apiKeyUrl: 'https://openrouter.ai/keys',
93
+ apiKeyPrefix: 'sk-or-',
94
+ apiKeyMinLength: 40,
95
+ envVar: 'OPENROUTER_API_KEY',
96
+ },
97
+ glama: {
98
+ value: 'glama',
99
+ label: 'Glama',
100
+ hint: 'OpenAI-compatible gateway',
101
+ category: 'gateway',
102
+ apiKeyUrl: 'https://glama.ai/settings/api-keys',
103
+ envVar: 'GLAMA_API_KEY',
104
+ },
105
+ litellm: {
106
+ value: 'litellm',
107
+ label: 'LiteLLM',
108
+ hint: 'Self-hosted proxy for 100+ providers',
109
+ category: 'gateway',
110
+ requiresBaseURL: true,
111
+ envVar: 'LITELLM_API_KEY',
27
112
  },
28
- ];
113
+ 'openai-compatible': {
114
+ value: 'openai-compatible',
115
+ label: 'OpenAI-Compatible',
116
+ hint: 'Ollama, vLLM, LocalAI, or any OpenAI-format API',
117
+ category: 'gateway',
118
+ requiresBaseURL: true,
119
+ envVar: 'OPENAI_COMPATIBLE_API_KEY',
120
+ },
121
+ vertex: {
122
+ value: 'vertex',
123
+ label: 'Google Vertex AI',
124
+ hint: 'GCP-hosted Gemini & Claude (uses ADC)',
125
+ category: 'enterprise',
126
+ apiKeyUrl: 'https://console.cloud.google.com/apis/credentials',
127
+ envVar: 'GOOGLE_VERTEX_PROJECT',
128
+ },
129
+ bedrock: {
130
+ value: 'bedrock',
131
+ label: 'AWS Bedrock',
132
+ hint: 'AWS-hosted Claude & Nova (uses AWS creds)',
133
+ category: 'enterprise',
134
+ apiKeyUrl: 'https://console.aws.amazon.com/bedrock',
135
+ envVar: 'AWS_ACCESS_KEY_ID',
136
+ },
137
+ };
138
+ /**
139
+ * Get providers organized by category
140
+ */
141
+ function getProvidersByCategory() {
142
+ const categories = {
143
+ recommended: [],
144
+ local: [],
145
+ cloud: [],
146
+ gateway: [],
147
+ enterprise: [],
148
+ };
149
+ for (const provider of LLM_PROVIDERS) {
150
+ const option = PROVIDER_REGISTRY[provider];
151
+ if (option) {
152
+ categories[option.category].push(option);
153
+ }
154
+ }
155
+ return categories;
156
+ }
29
157
  /**
30
- * Interactive provider selection using standardized options
31
- * @returns Selected provider or null if cancelled
158
+ * Build provider selection options with categories
159
+ */
160
+ function buildProviderOptions() {
161
+ const categories = getProvidersByCategory();
162
+ const options = [];
163
+ // Recommended (free) providers first
164
+ if (categories.recommended.length > 0) {
165
+ for (const p of categories.recommended) {
166
+ options.push({
167
+ value: p.value,
168
+ label: `${chalk.green('●')} ${p.label}`,
169
+ hint: `${p.hint} ${chalk.green('(free)')}`,
170
+ });
171
+ }
172
+ }
173
+ // Local providers - run AI on your machine
174
+ if (categories.local.length > 0) {
175
+ for (const p of categories.local) {
176
+ options.push({
177
+ value: p.value,
178
+ label: `${chalk.cyan('●')} ${p.label}`,
179
+ hint: `${p.hint} ${chalk.cyan('(local)')}`,
180
+ });
181
+ }
182
+ }
183
+ // Cloud providers
184
+ if (categories.cloud.length > 0) {
185
+ for (const p of categories.cloud) {
186
+ options.push({
187
+ value: p.value,
188
+ label: `${chalk.blue('●')} ${p.label}`,
189
+ hint: p.hint,
190
+ });
191
+ }
192
+ }
193
+ // Gateway providers
194
+ if (categories.gateway.length > 0) {
195
+ for (const p of categories.gateway) {
196
+ const suffix = p.requiresBaseURL ? chalk.gray(' (requires URL)') : '';
197
+ options.push({
198
+ value: p.value,
199
+ label: `${chalk.rgb(255, 165, 0)('●')} ${p.label}`,
200
+ hint: `${p.hint}${suffix}`,
201
+ });
202
+ }
203
+ }
204
+ // Enterprise providers
205
+ if (categories.enterprise.length > 0) {
206
+ for (const p of categories.enterprise) {
207
+ options.push({
208
+ value: p.value,
209
+ label: `${chalk.cyan('●')} ${p.label}`,
210
+ hint: p.hint,
211
+ });
212
+ }
213
+ }
214
+ return options;
215
+ }
216
+ /**
217
+ * Interactive provider selection with back option.
218
+ * @returns Selected provider, '_back' if back selected, or null if cancelled
32
219
  */
33
220
  export async function selectProvider() {
221
+ const options = buildProviderOptions();
34
222
  const choice = await p.select({
35
223
  message: 'Choose your AI provider',
36
- options: PROVIDER_OPTIONS,
224
+ options: [
225
+ ...options,
226
+ {
227
+ value: '_back',
228
+ label: chalk.gray('← Back'),
229
+ hint: 'Return to previous menu',
230
+ },
231
+ ],
37
232
  });
38
233
  if (p.isCancel(choice)) {
39
- p.cancel('Setup cancelled');
40
- process.exit(1);
234
+ return null;
41
235
  }
42
236
  return choice;
43
237
  }
44
238
  /**
45
- * Gets display name for a provider
239
+ * Get provider display name
46
240
  */
47
241
  export function getProviderDisplayName(provider) {
48
- switch (provider) {
49
- case 'google':
50
- return 'Google Gemini';
51
- case 'openai':
52
- return 'OpenAI';
53
- case 'anthropic':
54
- return 'Anthropic';
55
- case 'groq':
56
- return 'Groq';
57
- default:
58
- return provider;
242
+ return PROVIDER_REGISTRY[provider]?.label || provider;
243
+ }
244
+ /**
245
+ * Get provider option info
246
+ */
247
+ export function getProviderInfo(provider) {
248
+ return PROVIDER_REGISTRY[provider];
249
+ }
250
+ /**
251
+ * Legacy PROVIDER_OPTIONS for backwards compatibility with init-app
252
+ */
253
+ export const PROVIDER_OPTIONS = buildProviderOptions();
254
+ /**
255
+ * Get API key format hint for a provider
256
+ */
257
+ export function getApiKeyFormatHint(provider) {
258
+ const info = PROVIDER_REGISTRY[provider];
259
+ if (!info?.apiKeyPrefix)
260
+ return null;
261
+ return `Key should start with "${info.apiKeyPrefix}"`;
262
+ }
263
+ /**
264
+ * Validates API key format for a provider with detailed error messages
265
+ */
266
+ export function validateApiKeyFormat(apiKey, provider) {
267
+ const info = PROVIDER_REGISTRY[provider];
268
+ const trimmed = apiKey.trim();
269
+ if (!trimmed) {
270
+ return { valid: false, error: 'API key cannot be empty' };
271
+ }
272
+ // Check minimum length if specified
273
+ if (info?.apiKeyMinLength && trimmed.length < info.apiKeyMinLength) {
274
+ return {
275
+ valid: false,
276
+ error: `API key seems too short (expected ${info.apiKeyMinLength}+ characters, got ${trimmed.length})`,
277
+ };
59
278
  }
279
+ // Check prefix if specified
280
+ if (info?.apiKeyPrefix && !trimmed.startsWith(info.apiKeyPrefix)) {
281
+ const prefixLen = info.apiKeyPrefix.length;
282
+ return {
283
+ valid: false,
284
+ error: `Invalid format: ${getProviderDisplayName(provider)} keys start with "${info.apiKeyPrefix}" (got "${trimmed.slice(0, prefixLen)}...")`,
285
+ };
286
+ }
287
+ return { valid: true };
60
288
  }
61
289
  /**
62
- * Validates API key format for a provider
290
+ * Legacy validation function for backwards compatibility
63
291
  */
64
292
  export function isValidApiKeyFormat(apiKey, provider) {
65
- switch (provider) {
66
- case 'google':
67
- return apiKey.startsWith('AIza') && apiKey.length > 20;
68
- case 'openai':
69
- return apiKey.startsWith('sk-') && apiKey.length > 40;
70
- case 'anthropic':
71
- return apiKey.startsWith('sk-ant-') && apiKey.length > 40;
72
- case 'groq':
73
- return apiKey.startsWith('gsk_') && apiKey.length > 40;
74
- default:
75
- return apiKey.length > 10; // Basic length check
76
- }
293
+ return validateApiKeyFormat(apiKey, provider).valid;
77
294
  }
78
295
  /**
79
296
  * Gets provider-specific instructions for API key setup
80
297
  */
81
298
  export function getProviderInstructions(provider) {
82
- switch (provider) {
83
- case 'google':
84
- return {
85
- title: chalk.green('Google Gemini - Free API Key'),
86
- content: `1. Visit: ${chalk.cyan('https://aistudio.google.com/apikey')}\n` +
87
- `2. Sign in with your Google account\n` +
88
- `3. Click "Create API Key"\n` +
89
- `4. Copy the key\n\n` +
90
- `${chalk.dim('✨ Free tier included')}`,
91
- };
92
- case 'openai':
93
- return {
94
- title: chalk.blue('OpenAI API Key'),
95
- content: `1. Visit: ${chalk.cyan('https://platform.openai.com/api-keys')}\n` +
96
- `2. Sign in to your OpenAI account\n` +
97
- `3. Click "Create new secret key"\n` +
98
- `4. Copy the key\n\n` +
99
- `${chalk.dim('💰 Requires payment')}`,
100
- };
101
- case 'anthropic':
102
- return {
103
- title: chalk.magenta('Anthropic API Key'),
104
- content: `1. Visit: ${chalk.cyan('https://console.anthropic.com/settings/keys')}\n` +
105
- `2. Sign in to your Anthropic account\n` +
106
- `3. Click "Create Key"\n` +
107
- `4. Copy the key\n\n` +
108
- `${chalk.dim('💰 Requires payment')}`,
109
- };
110
- case 'groq':
111
- return {
112
- title: chalk.yellow('Groq API Key'),
113
- content: `1. Visit: ${chalk.cyan('https://console.groq.com/keys')}\n` +
114
- `2. Sign in with your account\n` +
115
- `3. Click "Create API Key"\n` +
116
- `4. Copy the key\n\n` +
117
- `${chalk.dim('🆓 Free tier included')}`,
118
- };
119
- default:
120
- return null;
299
+ const info = PROVIDER_REGISTRY[provider];
300
+ if (!info)
301
+ return null;
302
+ const freeTag = info.free ? chalk.green(' (Free)') : '';
303
+ const title = `${getProviderDisplayName(provider)} API Key${freeTag}`;
304
+ let content = '';
305
+ if (info.apiKeyUrl) {
306
+ content += `1. Visit: ${chalk.cyan(info.apiKeyUrl)}\n`;
307
+ content += `2. Sign in to your account\n`;
308
+ content += `3. Create a new API key\n`;
309
+ content += `4. Copy and paste it below\n`;
310
+ }
311
+ else if (info.requiresBaseURL) {
312
+ content += `This provider requires a custom endpoint URL.\n`;
313
+ content += `You'll configure both the URL and API key in the next steps.\n`;
314
+ }
315
+ if (info.apiKeyPrefix) {
316
+ content += `\n${chalk.gray(`Key format: ${info.apiKeyPrefix}...`)}`;
317
+ }
318
+ return { title, content, url: info.apiKeyUrl };
319
+ }
320
+ /**
321
+ * Open the API key URL in the browser
322
+ */
323
+ export async function openApiKeyUrl(provider) {
324
+ const info = PROVIDER_REGISTRY[provider];
325
+ if (!info?.apiKeyUrl)
326
+ return false;
327
+ try {
328
+ await open(info.apiKeyUrl);
329
+ return true;
121
330
  }
331
+ catch {
332
+ return false;
333
+ }
334
+ }
335
+ /**
336
+ * Check if provider requires a base URL
337
+ */
338
+ export function providerRequiresBaseURL(provider) {
339
+ return PROVIDER_REGISTRY[provider]?.requiresBaseURL === true;
340
+ }
341
+ /**
342
+ * Get default model for provider, with fallback for custom providers
343
+ */
344
+ export function getDefaultModel(provider) {
345
+ const defaultModel = getDefaultModelForProvider(provider);
346
+ if (defaultModel)
347
+ return defaultModel;
348
+ // Fallback for providers without a default (custom providers)
349
+ const providerInfo = LLM_REGISTRY[provider];
350
+ if (providerInfo?.models && providerInfo.models.length > 0) {
351
+ return providerInfo.models[0].name;
352
+ }
353
+ // For providers that accept any model, return empty to prompt user
354
+ return '';
355
+ }
356
+ /**
357
+ * Get environment variable name for provider's API key.
358
+ * Uses the canonical env var from the core api-key-resolver.
359
+ */
360
+ export function getProviderEnvVar(provider) {
361
+ return getPrimaryApiKeyEnvVar(provider);
122
362
  }