dexto 1.4.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.
- package/README.md +62 -7
- package/dist/agents/agent-template.yml +2 -2
- package/dist/agents/coding-agent/coding-agent.yml +22 -16
- package/dist/agents/database-agent/database-agent.yml +2 -2
- package/dist/agents/default-agent.yml +7 -5
- package/dist/agents/github-agent/github-agent.yml +2 -2
- package/dist/agents/product-name-researcher/product-name-researcher.yml +2 -2
- package/dist/agents/talk2pdf-agent/talk2pdf-agent.yml +2 -2
- package/dist/analytics/events.d.ts +13 -6
- package/dist/analytics/events.d.ts.map +1 -1
- package/dist/analytics/index.d.ts +1 -1
- package/dist/analytics/index.d.ts.map +1 -1
- package/dist/analytics/index.js +6 -2
- package/dist/api/server-hono.d.ts.map +1 -1
- package/dist/api/server-hono.js +27 -5
- package/dist/cli/cli-subscriber.d.ts +4 -0
- package/dist/cli/cli-subscriber.d.ts.map +1 -1
- package/dist/cli/cli-subscriber.js +40 -2
- package/dist/cli/commands/create-app.d.ts +16 -14
- package/dist/cli/commands/create-app.d.ts.map +1 -1
- package/dist/cli/commands/create-app.js +626 -102
- package/dist/cli/commands/create-image.d.ts +7 -0
- package/dist/cli/commands/create-image.d.ts.map +1 -0
- package/dist/cli/commands/create-image.js +201 -0
- package/dist/cli/commands/helpers/formatters.js +7 -7
- package/dist/cli/commands/index.d.ts +2 -1
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +2 -1
- package/dist/cli/commands/init-app.js +7 -7
- package/dist/cli/commands/install.d.ts +0 -3
- package/dist/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/commands/install.js +10 -35
- package/dist/cli/commands/interactive-commands/command-parser.js +7 -7
- package/dist/cli/commands/interactive-commands/general-commands.js +1 -1
- package/dist/cli/commands/interactive-commands/prompt-commands.js +11 -11
- package/dist/cli/commands/interactive-commands/system/system-commands.js +3 -3
- package/dist/cli/commands/list-agents.js +2 -2
- package/dist/cli/commands/session-commands.js +16 -16
- package/dist/cli/commands/setup.d.ts +13 -5
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +860 -65
- package/dist/cli/commands/which.js +1 -1
- package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts +2 -0
- package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ApprovalPrompt.js +29 -7
- package/dist/cli/ink-cli/components/CustomInput.js +1 -1
- package/dist/cli/ink-cli/components/EditableMultiLineInput.js +4 -4
- package/dist/cli/ink-cli/components/ElicitationForm.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ElicitationForm.js +6 -6
- package/dist/cli/ink-cli/components/ErrorBoundary.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ErrorBoundary.js +1 -1
- package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/Footer.js +1 -1
- package/dist/cli/ink-cli/components/HistorySearchBar.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/HistorySearchBar.js +1 -1
- package/dist/cli/ink-cli/components/MultiLineInput.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/MultiLineInput.js +3 -3
- package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ResourceAutocomplete.js +4 -4
- package/dist/cli/ink-cli/components/SlashCommandAutocomplete.js +3 -3
- package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/StatusBar.js +7 -5
- package/dist/cli/ink-cli/components/TextBufferInput.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/TextBufferInput.js +6 -6
- package/dist/cli/ink-cli/components/base/BaseAutocomplete.js +4 -4
- package/dist/cli/ink-cli/components/base/BaseSelector.js +2 -2
- package/dist/cli/ink-cli/components/chat/Footer.js +1 -1
- package/dist/cli/ink-cli/components/chat/Header.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/Header.js +2 -4
- package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.js +5 -5
- package/dist/cli/ink-cli/components/chat/MessageList.js +1 -1
- package/dist/cli/ink-cli/components/chat/QueuedMessagesDisplay.js +1 -1
- package/dist/cli/ink-cli/components/chat/ToolIcon.d.ts +1 -1
- package/dist/cli/ink-cli/components/chat/ToolIcon.js +4 -4
- package/dist/cli/ink-cli/components/chat/styled-boxes/ConfigBox.js +1 -1
- package/dist/cli/ink-cli/components/chat/styled-boxes/HelpBox.js +1 -1
- package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +2 -2
- package/dist/cli/ink-cli/components/chat/styled-boxes/SessionHistoryBox.js +5 -5
- package/dist/cli/ink-cli/components/chat/styled-boxes/SessionListBox.js +2 -2
- package/dist/cli/ink-cli/components/chat/styled-boxes/ShortcutsBox.js +1 -1
- package/dist/cli/ink-cli/components/chat/styled-boxes/StatsBox.js +1 -1
- package/dist/cli/ink-cli/components/chat/styled-boxes/StyledBox.js +2 -2
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.js +1 -1
- package/dist/cli/ink-cli/components/overlays/ApiKeyInput.js +1 -1
- package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts +10 -2
- package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/CustomModelWizard.js +198 -89
- package/dist/cli/ink-cli/components/overlays/LogLevelSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +2 -2
- package/dist/cli/ink-cli/components/overlays/McpAddChoice.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/McpAddChoice.js +1 -1
- package/dist/cli/ink-cli/components/overlays/McpAddSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/McpCustomTypeSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/McpCustomTypeSelector.js +2 -2
- package/dist/cli/ink-cli/components/overlays/McpCustomWizard.js +1 -1
- package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/McpSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/McpSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/McpServerActions.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/McpServerActions.js +2 -2
- package/dist/cli/ink-cli/components/overlays/McpServerList.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/McpServerList.js +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts +5 -5
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +222 -68
- package/dist/cli/ink-cli/components/overlays/PromptAddChoice.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/PromptAddChoice.js +2 -2
- package/dist/cli/ink-cli/components/overlays/PromptAddWizard.js +1 -1
- package/dist/cli/ink-cli/components/overlays/PromptDeleteSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/PromptDeleteSelector.js +2 -2
- package/dist/cli/ink-cli/components/overlays/PromptList.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/PromptList.js +2 -2
- package/dist/cli/ink-cli/components/overlays/SearchOverlay.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/SearchOverlay.js +4 -4
- package/dist/cli/ink-cli/components/overlays/SessionSubcommandSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/SessionSubcommandSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/StreamSelector.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/overlays/StreamSelector.js +1 -1
- package/dist/cli/ink-cli/components/overlays/ToolBrowser.js +12 -12
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts +25 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.js +609 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.d.ts +15 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.js +14 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts +33 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.js +419 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.d.ts +25 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.js +29 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.d.ts +17 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.js +11 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.d.ts +20 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.js +10 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.d.ts +30 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.js +13 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.d.ts +8 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.js +7 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts +79 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts.map +1 -0
- package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.js +38 -0
- package/dist/cli/ink-cli/components/renderers/DiffRenderer.js +2 -2
- package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.js +1 -1
- package/dist/cli/ink-cli/components/renderers/FileRenderer.js +4 -4
- package/dist/cli/ink-cli/components/renderers/GenericRenderer.js +2 -2
- package/dist/cli/ink-cli/components/renderers/SearchRenderer.js +1 -1
- package/dist/cli/ink-cli/components/renderers/ShellRenderer.js +3 -3
- package/dist/cli/ink-cli/components/renderers/diff-shared.js +1 -1
- package/dist/cli/ink-cli/components/shared/MarkdownText.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/shared/MarkdownText.js +8 -6
- package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/InputContainer.js +23 -1
- package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
- package/dist/cli/ink-cli/containers/OverlayContainer.js +80 -24
- package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts +1 -1
- package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useAgentEvents.js +5 -1
- package/dist/cli/ink-cli/hooks/useCLIState.d.ts +1 -1
- package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
- package/dist/cli/ink-cli/hooks/useCLIState.js +4 -2
- package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
- package/dist/cli/ink-cli/services/processStream.js +77 -9
- package/dist/cli/ink-cli/state/types.d.ts +3 -2
- package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts +5 -0
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.js +59 -1
- package/dist/cli/ink-cli/utils/toolUtils.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/toolUtils.js +2 -0
- package/dist/cli/utils/api-key-setup.d.ts +54 -4
- package/dist/cli/utils/api-key-setup.d.ts.map +1 -1
- package/dist/cli/utils/api-key-setup.js +433 -107
- package/dist/cli/utils/api-key-verification.d.ts +17 -0
- package/dist/cli/utils/api-key-verification.d.ts.map +1 -0
- package/dist/cli/utils/api-key-verification.js +211 -0
- package/dist/cli/utils/config-validation.d.ts +22 -2
- package/dist/cli/utils/config-validation.d.ts.map +1 -1
- package/dist/cli/utils/config-validation.js +354 -25
- package/dist/cli/utils/local-model-setup.d.ts +46 -0
- package/dist/cli/utils/local-model-setup.d.ts.map +1 -0
- package/dist/cli/utils/local-model-setup.js +662 -0
- package/dist/cli/utils/options.js +1 -1
- package/dist/cli/utils/prompt-helpers.d.ts +47 -0
- package/dist/cli/utils/prompt-helpers.d.ts.map +1 -0
- package/dist/cli/utils/prompt-helpers.js +66 -0
- package/dist/cli/utils/provider-setup.d.ts +66 -8
- package/dist/cli/utils/provider-setup.d.ts.map +1 -1
- package/dist/cli/utils/provider-setup.js +324 -84
- package/dist/cli/utils/scaffolding-utils.d.ts +76 -0
- package/dist/cli/utils/scaffolding-utils.d.ts.map +1 -0
- package/dist/cli/utils/scaffolding-utils.js +246 -0
- package/dist/cli/utils/setup-utils.d.ts +16 -0
- package/dist/cli/utils/setup-utils.d.ts.map +1 -1
- package/dist/cli/utils/setup-utils.js +72 -21
- package/dist/cli/utils/template-engine.d.ts +65 -0
- package/dist/cli/utils/template-engine.d.ts.map +1 -0
- package/dist/cli/utils/template-engine.js +1089 -0
- package/dist/config/cli-overrides.d.ts +44 -1
- package/dist/config/cli-overrides.d.ts.map +1 -1
- package/dist/config/cli-overrides.js +102 -0
- package/dist/index.js +315 -53
- package/dist/webui/assets/index-8j-KMkX1.js +2054 -0
- package/dist/webui/assets/index-c_AX24V4.css +1 -0
- package/dist/webui/index.html +3 -9
- package/dist/webui/logos/aws-color.svg +1 -0
- package/dist/webui/logos/dexto/dexto_logo.svg +1 -1
- package/dist/webui/logos/dexto/dexto_logo_light.svg +6 -6
- package/dist/webui/logos/glama.svg +7 -0
- package/dist/webui/logos/litellm.svg +7 -0
- package/dist/webui/logos/openrouter.svg +1 -0
- package/package.json +8 -7
- package/dist/webui/assets/index-BkwPkZpd.css +0 -1
- package/dist/webui/assets/index-D9u1XfyH.js +0 -2025
|
@@ -1,155 +1,481 @@
|
|
|
1
1
|
// packages/cli/src/cli/utils/api-key-setup.ts
|
|
2
2
|
import * as p from '@clack/prompts';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
|
-
import { logger,
|
|
4
|
+
import { logger, getExecutionContext } from '@dexto/core';
|
|
5
5
|
import { saveProviderApiKey } from '@dexto/agent-management';
|
|
6
6
|
import { applyLayeredEnvironmentLoading } from '../../utils/env.js';
|
|
7
|
-
import { getProviderDisplayName,
|
|
7
|
+
import { getProviderDisplayName, validateApiKeyFormat, getProviderInstructions, openApiKeyUrl, getProviderInfo, getProviderEnvVar, PROVIDER_REGISTRY, } from './provider-setup.js';
|
|
8
|
+
import { verifyApiKey } from './api-key-verification.js';
|
|
8
9
|
/**
|
|
9
10
|
* Interactively prompts the user to set up an API key for a specific provider.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* Exits the process if user cancels or setup fails.
|
|
11
|
+
* Includes browser auto-open, format validation with hints, and API key verification.
|
|
12
|
+
*
|
|
13
13
|
* @param provider - The specific provider that needs API key setup
|
|
14
|
+
* @param options - Configuration options
|
|
15
|
+
* @returns Result indicating success, cancellation, or error
|
|
14
16
|
*/
|
|
15
|
-
export async function interactiveApiKeySetup(provider) {
|
|
17
|
+
export async function interactiveApiKeySetup(provider, options = {}) {
|
|
18
|
+
const { exitOnCancel = true, skipVerification = false, model } = options;
|
|
16
19
|
try {
|
|
17
|
-
|
|
18
|
-
p.intro(chalk.cyan('🔑 API Key Setup '));
|
|
19
|
-
// Show targeted message for the required provider
|
|
20
|
+
p.intro(chalk.cyan('🔑 API Key Setup'));
|
|
20
21
|
const instructions = getProviderInstructions(provider);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
const providerInfo = getProviderInfo(provider);
|
|
23
|
+
// Show targeted message for the required provider
|
|
24
|
+
if (instructions) {
|
|
25
|
+
p.note(`Your configuration requires a ${getProviderDisplayName(provider)} API key.\n\n` +
|
|
26
|
+
instructions.content, chalk.bold(instructions.title));
|
|
27
|
+
}
|
|
28
|
+
// Ask what they want to do - with "Open in browser" option
|
|
29
|
+
const hasApiKeyUrl = Boolean(providerInfo?.apiKeyUrl);
|
|
30
|
+
const actionOptions = [
|
|
31
|
+
...(hasApiKeyUrl
|
|
32
|
+
? [
|
|
33
|
+
{
|
|
34
|
+
value: 'open-browser',
|
|
35
|
+
label: 'Open browser & set up now',
|
|
36
|
+
hint: 'Opens the API key page in your browser (recommended)',
|
|
37
|
+
},
|
|
38
|
+
]
|
|
39
|
+
: []),
|
|
40
|
+
{
|
|
41
|
+
value: 'setup',
|
|
42
|
+
label: hasApiKeyUrl ? 'I already have a key' : 'Enter API key now',
|
|
43
|
+
hint: 'Paste an existing API key',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
value: 'skip',
|
|
47
|
+
label: 'Skip for now',
|
|
48
|
+
hint: 'Continue without API key - configure later in settings',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
value: 'manual',
|
|
52
|
+
label: 'View manual instructions',
|
|
53
|
+
hint: 'See how to set up manually',
|
|
54
|
+
},
|
|
55
|
+
];
|
|
24
56
|
const action = await p.select({
|
|
25
57
|
message: 'What would you like to do?',
|
|
26
|
-
options:
|
|
27
|
-
{
|
|
28
|
-
value: 'setup',
|
|
29
|
-
label: 'Set up an API key now',
|
|
30
|
-
hint: 'Interactive setup (recommended)',
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
value: 'manual',
|
|
34
|
-
label: 'Set up manually later',
|
|
35
|
-
hint: 'Get instructions for manual setup',
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
value: 'exit',
|
|
39
|
-
label: 'Exit',
|
|
40
|
-
hint: 'Quit Dexto for now',
|
|
41
|
-
},
|
|
42
|
-
],
|
|
58
|
+
options: actionOptions,
|
|
43
59
|
});
|
|
44
|
-
if (action
|
|
45
|
-
p.cancel('Setup cancelled
|
|
46
|
-
|
|
60
|
+
if (p.isCancel(action)) {
|
|
61
|
+
p.cancel('Setup cancelled');
|
|
62
|
+
if (exitOnCancel)
|
|
63
|
+
process.exit(0);
|
|
64
|
+
return { success: false, cancelled: true };
|
|
65
|
+
}
|
|
66
|
+
if (action === 'skip') {
|
|
67
|
+
p.log.warn('Skipping API key setup. You can configure it later with: dexto setup');
|
|
68
|
+
return { success: true, skipped: true };
|
|
47
69
|
}
|
|
48
70
|
if (action === 'manual') {
|
|
49
71
|
showManualSetupInstructions(provider);
|
|
50
|
-
|
|
51
|
-
|
|
72
|
+
// Don't exit - let them continue
|
|
73
|
+
p.log.info('You can configure your API key later with: dexto setup');
|
|
74
|
+
return { success: true, skipped: true };
|
|
52
75
|
}
|
|
53
|
-
if
|
|
54
|
-
|
|
55
|
-
|
|
76
|
+
// Open browser if requested
|
|
77
|
+
if (action === 'open-browser') {
|
|
78
|
+
const spinner = p.spinner();
|
|
79
|
+
spinner.start('Opening browser...');
|
|
80
|
+
const opened = await openApiKeyUrl(provider);
|
|
81
|
+
if (opened) {
|
|
82
|
+
spinner.stop('Browser opened! Get your API key and paste it below.');
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
spinner.stop(`Could not open browser. Visit: ${providerInfo?.apiKeyUrl}`);
|
|
86
|
+
}
|
|
56
87
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
88
|
+
// Prompt for API key with improved validation
|
|
89
|
+
const apiKey = await promptForApiKey(provider);
|
|
90
|
+
if (!apiKey) {
|
|
91
|
+
if (exitOnCancel)
|
|
92
|
+
process.exit(0);
|
|
93
|
+
return { success: false, cancelled: true };
|
|
94
|
+
}
|
|
95
|
+
// Verify API key works (unless skipped)
|
|
96
|
+
if (!skipVerification) {
|
|
97
|
+
const verificationResult = await verifyApiKeyWithSpinner(provider, apiKey, model);
|
|
98
|
+
if (!verificationResult.success) {
|
|
99
|
+
p.log.error(verificationResult.error || 'API key verification failed');
|
|
100
|
+
const retryAction = await p.select({
|
|
101
|
+
message: 'What would you like to do?',
|
|
102
|
+
options: [
|
|
103
|
+
{
|
|
104
|
+
value: 'retry',
|
|
105
|
+
label: 'Try a different API key',
|
|
106
|
+
hint: 'Enter a new API key',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
value: 'save-anyway',
|
|
110
|
+
label: 'Save anyway',
|
|
111
|
+
hint: 'Key might still work - save and continue',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
value: 'skip',
|
|
115
|
+
label: 'Skip for now',
|
|
116
|
+
hint: 'Continue without saving - configure later',
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
});
|
|
120
|
+
if (p.isCancel(retryAction)) {
|
|
121
|
+
if (exitOnCancel)
|
|
122
|
+
process.exit(1);
|
|
123
|
+
const result = { success: false, cancelled: true };
|
|
124
|
+
return result;
|
|
63
125
|
}
|
|
64
|
-
if (
|
|
65
|
-
|
|
126
|
+
if (retryAction === 'retry') {
|
|
127
|
+
// Recursive retry
|
|
128
|
+
return interactiveApiKeySetup(provider, options);
|
|
66
129
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
// Update .env file
|
|
75
|
-
const spinner = p.spinner();
|
|
76
|
-
spinner.start('Saving API key...');
|
|
77
|
-
try {
|
|
78
|
-
// Update .env file with the API key using smart path detection
|
|
79
|
-
const meta = await saveProviderApiKey(provider, apiKey.trim(), process.cwd());
|
|
80
|
-
spinner.stop(`✨ API key saved successfully for ${getProviderDisplayName(provider)} in ${meta.targetEnvPath}!`);
|
|
81
|
-
p.outro(chalk.green(`✨ API key setup complete!`));
|
|
82
|
-
// Reload environment variables so the newly saved API key is available
|
|
83
|
-
await applyLayeredEnvironmentLoading();
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
spinner.stop('Failed to save API key');
|
|
87
|
-
logger.error(`Failed to update .env file: ${error}`);
|
|
88
|
-
// Provide context-aware manual setup instructions
|
|
89
|
-
let instructions;
|
|
90
|
-
if (getExecutionContext() === 'global-cli') {
|
|
91
|
-
instructions =
|
|
92
|
-
`1. Create ~/.dexto/.env file\n` +
|
|
93
|
-
`2. Add this line: ${getPrimaryApiKeyEnvVar(provider)}=your_api_key_here\n` +
|
|
94
|
-
`3. Run dexto again\n\n` +
|
|
95
|
-
`Alternatively:\n` +
|
|
96
|
-
`• Set environment variable: export ${getPrimaryApiKeyEnvVar(provider)}=your_api_key_here\n` +
|
|
97
|
-
`• Or run: dexto setup`;
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
instructions =
|
|
101
|
-
`1. Create a .env file in your project root\n` +
|
|
102
|
-
`2. Add this line: ${getPrimaryApiKeyEnvVar(provider)}=your_api_key_here\n` +
|
|
103
|
-
`3. Run dexto again`;
|
|
130
|
+
if (retryAction === 'skip') {
|
|
131
|
+
p.log.warn('Skipping API key setup. You can configure it later with: dexto setup');
|
|
132
|
+
return { success: true, skipped: true };
|
|
133
|
+
}
|
|
134
|
+
// retryAction === 'save-anyway' - fall through to save
|
|
135
|
+
p.log.info('Saving API key despite verification failure...');
|
|
104
136
|
}
|
|
105
|
-
p.note(`Manual setup required:\n\n${instructions}`, chalk.yellow('Save this API key manually'));
|
|
106
|
-
console.error(chalk.red('\n❌ API key setup required to continue.'));
|
|
107
|
-
process.exit(1);
|
|
108
137
|
}
|
|
138
|
+
// Save API key
|
|
139
|
+
const saveResult = await saveApiKeyWithSpinner(provider, apiKey);
|
|
140
|
+
if (!saveResult.success) {
|
|
141
|
+
showManualSaveInstructions(provider, apiKey);
|
|
142
|
+
p.log.warn('You can configure API key later with: dexto setup');
|
|
143
|
+
// Don't fail - return success with the API key for in-memory use
|
|
144
|
+
return { success: true, apiKey, skipped: true };
|
|
145
|
+
}
|
|
146
|
+
p.outro(chalk.green('✨ API key setup complete!'));
|
|
147
|
+
return { success: true, apiKey };
|
|
109
148
|
}
|
|
110
149
|
catch (error) {
|
|
111
150
|
if (p.isCancel(error)) {
|
|
112
151
|
p.cancel('Setup cancelled');
|
|
113
|
-
|
|
152
|
+
if (exitOnCancel)
|
|
153
|
+
process.exit(0);
|
|
154
|
+
return { success: false, cancelled: true };
|
|
114
155
|
}
|
|
115
|
-
|
|
116
|
-
|
|
156
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
157
|
+
logger.error(`API key setup failed: ${errorMessage}`);
|
|
158
|
+
if (exitOnCancel) {
|
|
159
|
+
console.error(chalk.red('\n❌ API key setup required to continue.'));
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
return { success: false, error: errorMessage };
|
|
117
163
|
}
|
|
118
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Prompt for API key with format validation and hints
|
|
167
|
+
*/
|
|
168
|
+
async function promptForApiKey(provider) {
|
|
169
|
+
const providerInfo = getProviderInfo(provider);
|
|
170
|
+
const formatHint = providerInfo?.apiKeyPrefix
|
|
171
|
+
? chalk.gray(` (starts with ${providerInfo.apiKeyPrefix})`)
|
|
172
|
+
: '';
|
|
173
|
+
const apiKey = await p.password({
|
|
174
|
+
message: `Enter your ${getProviderDisplayName(provider)} API key${formatHint}`,
|
|
175
|
+
mask: '*',
|
|
176
|
+
validate: (value) => {
|
|
177
|
+
const result = validateApiKeyFormat(value, provider);
|
|
178
|
+
if (!result.valid) {
|
|
179
|
+
return result.error;
|
|
180
|
+
}
|
|
181
|
+
return undefined;
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
if (p.isCancel(apiKey)) {
|
|
185
|
+
p.cancel('Setup cancelled');
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
return apiKey.trim();
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Verify API key with a spinner
|
|
192
|
+
*/
|
|
193
|
+
async function verifyApiKeyWithSpinner(provider, apiKey, model) {
|
|
194
|
+
const spinner = p.spinner();
|
|
195
|
+
spinner.start('Verifying API key...');
|
|
196
|
+
try {
|
|
197
|
+
const result = await verifyApiKey(provider, apiKey, model);
|
|
198
|
+
if (result.success) {
|
|
199
|
+
spinner.stop(chalk.green('✓ API key verified successfully!'));
|
|
200
|
+
return { success: true };
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
spinner.stop(chalk.red('✗ API key verification failed'));
|
|
204
|
+
const response = { success: false };
|
|
205
|
+
if (result.error)
|
|
206
|
+
response.error = result.error;
|
|
207
|
+
return response;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
212
|
+
spinner.stop(chalk.red('✗ Verification failed'));
|
|
213
|
+
return { success: false, error: errorMessage };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Save API key with a spinner
|
|
218
|
+
*/
|
|
219
|
+
async function saveApiKeyWithSpinner(provider, apiKey) {
|
|
220
|
+
const spinner = p.spinner();
|
|
221
|
+
spinner.start('Saving API key...');
|
|
222
|
+
try {
|
|
223
|
+
const meta = await saveProviderApiKey(provider, apiKey, process.cwd());
|
|
224
|
+
spinner.stop(chalk.green(`✓ API key saved to ${meta.targetEnvPath}`));
|
|
225
|
+
// Reload environment variables
|
|
226
|
+
await applyLayeredEnvironmentLoading();
|
|
227
|
+
return { success: true, path: meta.targetEnvPath };
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
231
|
+
spinner.stop(chalk.red('✗ Failed to save API key'));
|
|
232
|
+
logger.error(`Failed to save API key: ${errorMessage}`);
|
|
233
|
+
return { success: false, error: errorMessage };
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Show manual setup instructions when automatic save fails
|
|
238
|
+
*/
|
|
239
|
+
function showManualSaveInstructions(provider, apiKey) {
|
|
240
|
+
const envVar = getProviderEnvVar(provider);
|
|
241
|
+
const maskedKey = apiKey.slice(0, 8) + '...' + apiKey.slice(-4);
|
|
242
|
+
const instructions = getExecutionContext() === 'global-cli'
|
|
243
|
+
? [
|
|
244
|
+
`1. Create or edit: ${chalk.cyan('~/.dexto/.env')}`,
|
|
245
|
+
`2. Add this line: ${chalk.rgb(255, 165, 0)(`${envVar}=${maskedKey}`)}`,
|
|
246
|
+
`3. Run ${chalk.cyan('dexto')} again`,
|
|
247
|
+
]
|
|
248
|
+
: [
|
|
249
|
+
`1. Create or edit: ${chalk.cyan('.env')} in your project`,
|
|
250
|
+
`2. Add this line: ${chalk.rgb(255, 165, 0)(`${envVar}=your_api_key`)}`,
|
|
251
|
+
`3. Run ${chalk.cyan('dexto')} again`,
|
|
252
|
+
];
|
|
253
|
+
p.note(instructions.join('\n'), chalk.rgb(255, 165, 0)('Manual Setup Required'));
|
|
254
|
+
}
|
|
119
255
|
/**
|
|
120
256
|
* Shows manual setup instructions to the user
|
|
121
257
|
*/
|
|
122
258
|
function showManualSetupInstructions(provider) {
|
|
123
|
-
const envVar =
|
|
259
|
+
const envVar = getProviderEnvVar(provider);
|
|
260
|
+
const providerInfo = getProviderInfo(provider);
|
|
124
261
|
const envInstructions = getExecutionContext() === 'global-cli'
|
|
125
262
|
? [
|
|
126
|
-
`${chalk.bold('2.
|
|
127
|
-
` dexto setup`,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
` mkdir -p ~/.dexto && echo "${envVar}=your_api_key_here" > ~/.dexto/.env`,
|
|
263
|
+
`${chalk.bold('2. Save your API key:')}`,
|
|
264
|
+
` ${chalk.gray('Option A:')} Run ${chalk.cyan('dexto setup')} (interactive)`,
|
|
265
|
+
` ${chalk.gray('Option B:')} Create ${chalk.cyan('~/.dexto/.env')} with:`,
|
|
266
|
+
` ${chalk.rgb(255, 165, 0)(`${envVar}=your_api_key_here`)}`,
|
|
131
267
|
]
|
|
132
268
|
: [
|
|
133
|
-
`${chalk.bold('2.
|
|
134
|
-
`
|
|
269
|
+
`${chalk.bold('2. Save your API key:')}`,
|
|
270
|
+
` Create ${chalk.cyan('.env')} in your project with:`,
|
|
271
|
+
` ${chalk.rgb(255, 165, 0)(`${envVar}=your_api_key_here`)}`,
|
|
135
272
|
];
|
|
273
|
+
// Build provider URLs list dynamically from registry
|
|
274
|
+
const providerUrls = [];
|
|
275
|
+
// Add current provider first if it has an API key URL
|
|
276
|
+
if (providerInfo?.apiKeyUrl) {
|
|
277
|
+
providerUrls.push(` ${chalk.cyan('→')} ${chalk.cyan(getProviderDisplayName(provider))}: ${providerInfo.apiKeyUrl}`);
|
|
278
|
+
providerUrls.push(''); // Add spacing
|
|
279
|
+
}
|
|
280
|
+
// Add recommended/popular providers with API keys
|
|
281
|
+
const popularProviders = [
|
|
282
|
+
{ provider: 'google', color: chalk.green }, // Free
|
|
283
|
+
{ provider: 'groq', color: chalk.green }, // Free
|
|
284
|
+
{ provider: 'openai', color: chalk.blue },
|
|
285
|
+
{ provider: 'anthropic', color: chalk.blue },
|
|
286
|
+
{ provider: 'xai', color: chalk.blue },
|
|
287
|
+
{ provider: 'cohere', color: chalk.blue },
|
|
288
|
+
];
|
|
289
|
+
for (const { provider: p, color } of popularProviders) {
|
|
290
|
+
const info = PROVIDER_REGISTRY[p];
|
|
291
|
+
if (info?.apiKeyUrl && p !== provider) {
|
|
292
|
+
// Don't duplicate current provider
|
|
293
|
+
const freeTag = info.free ? ' (Free)' : '';
|
|
294
|
+
providerUrls.push(` ${color('●')} ${color(info.label + freeTag)}: ${info.apiKeyUrl}`);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// Add gateway providers
|
|
298
|
+
const gatewayProviders = ['openrouter', 'glama'];
|
|
299
|
+
for (const p of gatewayProviders) {
|
|
300
|
+
const info = PROVIDER_REGISTRY[p];
|
|
301
|
+
if (info?.apiKeyUrl && p !== provider) {
|
|
302
|
+
providerUrls.push(` ${chalk.rgb(255, 165, 0)('●')} ${chalk.rgb(255, 165, 0)(info.label)} (Gateway): ${info.apiKeyUrl}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
// Add enterprise providers
|
|
306
|
+
const enterpriseProviders = ['vertex', 'bedrock'];
|
|
307
|
+
for (const p of enterpriseProviders) {
|
|
308
|
+
const info = PROVIDER_REGISTRY[p];
|
|
309
|
+
if (info?.apiKeyUrl && p !== provider) {
|
|
310
|
+
providerUrls.push(` ${chalk.cyan('●')} ${chalk.cyan(info.label)} (Enterprise): ${info.apiKeyUrl}`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
136
313
|
const instructions = [
|
|
137
|
-
`${chalk.bold('1. Get an API key:')}`,
|
|
138
|
-
|
|
139
|
-
` • ${chalk.blue('OpenAI')}: https://platform.openai.com/api-keys`,
|
|
140
|
-
` • ${chalk.magenta('Anthropic')}: https://console.anthropic.com/settings/keys`,
|
|
141
|
-
` • ${chalk.yellow('Groq (Free)')}: https://console.groq.com/keys`,
|
|
314
|
+
`${chalk.bold('1. Get an API key from your provider:')}`,
|
|
315
|
+
...providerUrls,
|
|
142
316
|
``,
|
|
143
317
|
...envInstructions,
|
|
144
|
-
` # OR for other providers:`,
|
|
145
|
-
` # OPENAI_API_KEY=your_key_here`,
|
|
146
|
-
` # ANTHROPIC_API_KEY=your_key_here`,
|
|
147
|
-
` # GROQ_API_KEY=your_key_here`,
|
|
148
318
|
``,
|
|
149
319
|
`${chalk.bold('3. Run dexto again:')}`,
|
|
150
|
-
` dexto
|
|
320
|
+
` ${chalk.cyan('dexto')} or ${chalk.cyan('npx dexto')}`,
|
|
151
321
|
``,
|
|
152
|
-
`${chalk.
|
|
322
|
+
`${chalk.gray('💡 Tip: Start with Google Gemini or Groq for a free experience!')}`,
|
|
153
323
|
].join('\n');
|
|
154
324
|
p.note(instructions, chalk.bold('Manual Setup Instructions'));
|
|
155
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* Quick check if an API key is already configured for a provider
|
|
328
|
+
*/
|
|
329
|
+
export function hasApiKeyConfigured(provider) {
|
|
330
|
+
const envVar = getProviderEnvVar(provider);
|
|
331
|
+
return Boolean(process.env[envVar]);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Prompts user about pending API key setup from a previous incomplete setup.
|
|
335
|
+
* This is shown when user previously skipped API key setup and is now trying to run dexto.
|
|
336
|
+
*
|
|
337
|
+
* @param provider - The provider that needs API key setup
|
|
338
|
+
* @param model - The model configured for the provider
|
|
339
|
+
* @returns Result indicating which action the user chose
|
|
340
|
+
*/
|
|
341
|
+
export async function promptForPendingApiKey(provider, model) {
|
|
342
|
+
const providerName = getProviderDisplayName(provider);
|
|
343
|
+
p.intro(chalk.cyan('🔧 Complete Your Setup'));
|
|
344
|
+
p.note(`You previously set up Dexto with ${chalk.bold(providerName)} but skipped API key configuration.\n\n` +
|
|
345
|
+
`To use ${providerName}/${model}, you'll need to add your API key.`, 'Setup Incomplete');
|
|
346
|
+
const action = await p.select({
|
|
347
|
+
message: 'What would you like to do?',
|
|
348
|
+
options: [
|
|
349
|
+
{
|
|
350
|
+
value: 'setup',
|
|
351
|
+
label: `Set up ${providerName} API key now`,
|
|
352
|
+
hint: 'Recommended - complete your setup',
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
value: 'skip',
|
|
356
|
+
label: 'Skip for now',
|
|
357
|
+
hint: 'Continue without API key - will show error when trying to use LLM',
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
value: 'cancel',
|
|
361
|
+
label: 'Exit',
|
|
362
|
+
hint: 'Exit and set up later with: dexto setup',
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
});
|
|
366
|
+
if (p.isCancel(action)) {
|
|
367
|
+
p.cancel('Cancelled');
|
|
368
|
+
return { action: 'cancel' };
|
|
369
|
+
}
|
|
370
|
+
if (action === 'cancel') {
|
|
371
|
+
return { action: 'cancel' };
|
|
372
|
+
}
|
|
373
|
+
if (action === 'skip') {
|
|
374
|
+
p.log.warn('Continuing without API key. You may see errors when the LLM is invoked.');
|
|
375
|
+
return { action: 'skip' };
|
|
376
|
+
}
|
|
377
|
+
// action === 'setup' - use the existing API key setup flow
|
|
378
|
+
const setupResult = await interactiveApiKeySetup(provider, {
|
|
379
|
+
exitOnCancel: false,
|
|
380
|
+
model,
|
|
381
|
+
});
|
|
382
|
+
if (setupResult.cancelled) {
|
|
383
|
+
return { action: 'cancel' };
|
|
384
|
+
}
|
|
385
|
+
if (setupResult.skipped) {
|
|
386
|
+
p.log.warn('API key setup skipped. You can configure it later with: dexto setup');
|
|
387
|
+
return { action: 'skip' };
|
|
388
|
+
}
|
|
389
|
+
if (setupResult.success && setupResult.apiKey) {
|
|
390
|
+
return { action: 'setup', apiKey: setupResult.apiKey };
|
|
391
|
+
}
|
|
392
|
+
return { action: 'skip' };
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Prompts user when loading a specific agent that requires an API key they don't have.
|
|
396
|
+
* Offers options to add the API key, continue with their default LLM, or cancel.
|
|
397
|
+
*
|
|
398
|
+
* @param agentProvider - The provider the agent requires
|
|
399
|
+
* @param agentModel - The model the agent uses
|
|
400
|
+
* @param userProvider - The user's default provider (from preferences)
|
|
401
|
+
* @param userModel - The user's default model (from preferences)
|
|
402
|
+
* @returns Result indicating which action the user chose
|
|
403
|
+
*/
|
|
404
|
+
export async function promptForMissingAgentApiKey(agentProvider, agentModel, userProvider, userModel) {
|
|
405
|
+
const agentProviderName = getProviderDisplayName(agentProvider);
|
|
406
|
+
const userProviderName = getProviderDisplayName(userProvider);
|
|
407
|
+
const userDefault = `${userProviderName}/${userModel}`;
|
|
408
|
+
p.intro(chalk.cyan('🔧 Agent Configuration'));
|
|
409
|
+
p.note(`This agent is configured for ${chalk.bold(`${agentProviderName}/${agentModel}`)}\n` +
|
|
410
|
+
`but you don't have an API key set up for ${agentProviderName}.\n\n` +
|
|
411
|
+
`Your default LLM is ${chalk.green(userDefault)}.`, 'Missing API Key');
|
|
412
|
+
const action = await p.select({
|
|
413
|
+
message: 'What would you like to do?',
|
|
414
|
+
options: [
|
|
415
|
+
{
|
|
416
|
+
value: 'use-default',
|
|
417
|
+
label: `Continue with ${userDefault}`,
|
|
418
|
+
hint: 'Agent will use your default LLM instead (behavior may differ)',
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
value: 'add-key',
|
|
422
|
+
label: `Set up ${agentProviderName} API key`,
|
|
423
|
+
hint: `Configure ${agentProviderName} to run agent as intended`,
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
value: 'cancel',
|
|
427
|
+
label: 'Cancel',
|
|
428
|
+
hint: 'Exit without running the agent',
|
|
429
|
+
},
|
|
430
|
+
],
|
|
431
|
+
});
|
|
432
|
+
if (p.isCancel(action)) {
|
|
433
|
+
p.cancel('Cancelled');
|
|
434
|
+
return { action: 'cancel' };
|
|
435
|
+
}
|
|
436
|
+
if (action === 'cancel') {
|
|
437
|
+
return { action: 'cancel' };
|
|
438
|
+
}
|
|
439
|
+
if (action === 'use-default') {
|
|
440
|
+
p.log.warn(`Using ${userDefault} instead of ${agentProviderName}/${agentModel}. ` +
|
|
441
|
+
`Agent behavior may differ from intended.`);
|
|
442
|
+
return { action: 'use-default' };
|
|
443
|
+
}
|
|
444
|
+
// action === 'add-key' - use the existing API key setup flow
|
|
445
|
+
const setupResult = await interactiveApiKeySetup(agentProvider, {
|
|
446
|
+
exitOnCancel: false,
|
|
447
|
+
model: agentModel,
|
|
448
|
+
});
|
|
449
|
+
if (setupResult.cancelled) {
|
|
450
|
+
return { action: 'cancel' };
|
|
451
|
+
}
|
|
452
|
+
if (setupResult.skipped) {
|
|
453
|
+
// User skipped in the API key setup - ask again what they want to do
|
|
454
|
+
const skipAction = await p.select({
|
|
455
|
+
message: 'API key setup was skipped. What would you like to do?',
|
|
456
|
+
options: [
|
|
457
|
+
{
|
|
458
|
+
value: 'use-default',
|
|
459
|
+
label: `Continue with ${userDefault}`,
|
|
460
|
+
hint: 'Agent will use your default LLM instead',
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
value: 'cancel',
|
|
464
|
+
label: 'Cancel',
|
|
465
|
+
hint: 'Exit without running the agent',
|
|
466
|
+
},
|
|
467
|
+
],
|
|
468
|
+
});
|
|
469
|
+
if (p.isCancel(skipAction) || skipAction === 'cancel') {
|
|
470
|
+
return { action: 'cancel' };
|
|
471
|
+
}
|
|
472
|
+
p.log.warn(`Using ${userDefault} instead of ${agentProviderName}/${agentModel}. ` +
|
|
473
|
+
`Agent behavior may differ from intended.`);
|
|
474
|
+
return { action: 'use-default' };
|
|
475
|
+
}
|
|
476
|
+
if (setupResult.success && setupResult.apiKey) {
|
|
477
|
+
return { action: 'add-key', apiKey: setupResult.apiKey };
|
|
478
|
+
}
|
|
479
|
+
// Shouldn't reach here, but default to cancel
|
|
480
|
+
return { action: 'cancel' };
|
|
481
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LLMProvider } from '@dexto/core';
|
|
2
|
+
export interface VerificationResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
error?: string;
|
|
5
|
+
modelUsed?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Verify an API key by making a minimal test request to the provider.
|
|
9
|
+
* Uses provider-specific endpoints for efficient validation.
|
|
10
|
+
*
|
|
11
|
+
* @param provider - The LLM provider
|
|
12
|
+
* @param apiKey - The API key to verify
|
|
13
|
+
* @param model - Optional specific model to test with
|
|
14
|
+
* @returns Verification result
|
|
15
|
+
*/
|
|
16
|
+
export declare function verifyApiKey(provider: LLMProvider, apiKey: string, _model?: string): Promise<VerificationResult>;
|
|
17
|
+
//# sourceMappingURL=api-key-verification.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-key-verification.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/api-key-verification.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,MAAM,WAAW,kBAAkB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAC9B,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAsC7B"}
|