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,135 +1,659 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import chalk from 'chalk';
|
|
4
|
-
import { executeWithTimeout } from '../utils/execute.js';
|
|
5
4
|
import * as p from '@clack/prompts';
|
|
6
|
-
import { getPackageManager, getPackageManagerInstallCommand, addScriptsToPackageJson, } from '../utils/package-mgmt.js';
|
|
7
5
|
import { logger } from '@dexto/core';
|
|
6
|
+
import { selectOrExit, textOrExit } from '../utils/prompt-helpers.js';
|
|
7
|
+
import { promptForProjectName, createProjectDirectory, setupGitRepo, createGitignore, initPackageJson, createTsconfigForApp, installDependencies, createEnvExample, ensureDirectory, } from '../utils/scaffolding-utils.js';
|
|
8
|
+
import { generateIndexForImage, generateWebServerIndex, generateWebAppHTML, generateWebAppJS, generateWebAppCSS, generateAppReadme, generateExampleTool, generateDiscoveryScript, } from '../utils/template-engine.js';
|
|
9
|
+
import { getExecutionContext } from '@dexto/agent-management';
|
|
8
10
|
/**
|
|
9
|
-
* Creates
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Creates a Dexto application with two possible modes:
|
|
12
|
+
* - from-image: Use existing image (recommended)
|
|
13
|
+
* - from-core: Build from @dexto/core with custom providers (advanced)
|
|
14
|
+
*
|
|
15
|
+
* Note: To create a new image that extends another image, use `dexto create-image` instead.
|
|
16
|
+
*
|
|
17
|
+
* @param name - Optional name of the app project
|
|
18
|
+
* @param options - Optional flags to specify mode and base image
|
|
13
19
|
* @returns The absolute path to the created project directory
|
|
14
20
|
*/
|
|
15
|
-
export async function createDextoProject(name) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
export async function createDextoProject(name, options) {
|
|
22
|
+
console.log(chalk.blue('🚀 Creating a Dexto application\n'));
|
|
23
|
+
// Step 1: Get project name
|
|
24
|
+
const projectName = name
|
|
25
|
+
? name
|
|
26
|
+
: await promptForProjectName('my-dexto-app', 'What do you want to name your app?');
|
|
27
|
+
// Step 2: Determine app type
|
|
28
|
+
let appType = options?.type || 'script';
|
|
29
|
+
if (!options?.type) {
|
|
30
|
+
appType = await selectOrExit({
|
|
31
|
+
message: 'What type of app?',
|
|
32
|
+
options: [
|
|
33
|
+
{
|
|
34
|
+
value: 'script',
|
|
35
|
+
label: 'Script',
|
|
36
|
+
hint: 'Simple script (default)',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
value: 'webapp',
|
|
40
|
+
label: 'Web App',
|
|
41
|
+
hint: 'REST API server with web frontend',
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
}, 'App creation cancelled');
|
|
45
|
+
}
|
|
46
|
+
// Step 3: Determine app mode (from flags or prompt)
|
|
47
|
+
let mode;
|
|
48
|
+
let baseImage;
|
|
49
|
+
if (options?.fromCore) {
|
|
50
|
+
mode = 'from-core';
|
|
51
|
+
}
|
|
52
|
+
else if (options?.fromImage) {
|
|
53
|
+
mode = 'from-image';
|
|
54
|
+
baseImage = options.fromImage;
|
|
26
55
|
}
|
|
27
56
|
else {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
57
|
+
// No flags provided, use interactive prompt
|
|
58
|
+
mode = await selectOrExit({
|
|
59
|
+
message: 'How do you want to start?',
|
|
60
|
+
options: [
|
|
61
|
+
{
|
|
62
|
+
value: 'from-image',
|
|
63
|
+
label: 'Use existing image (recommended)',
|
|
64
|
+
hint: 'Pre-built image with providers',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
value: 'from-core',
|
|
68
|
+
label: 'Build from core (advanced)',
|
|
69
|
+
hint: 'Custom standalone app with your own providers',
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
}, 'App creation cancelled');
|
|
44
73
|
}
|
|
45
74
|
const spinner = p.spinner();
|
|
46
|
-
|
|
47
|
-
|
|
75
|
+
let projectPath;
|
|
76
|
+
const originalCwd = process.cwd();
|
|
48
77
|
try {
|
|
49
|
-
|
|
78
|
+
// Create project directory
|
|
79
|
+
projectPath = await createProjectDirectory(projectName, spinner);
|
|
80
|
+
// Change to project directory
|
|
81
|
+
process.chdir(projectPath);
|
|
82
|
+
if (mode === 'from-core') {
|
|
83
|
+
// Mode C: Build from core - custom image with bundler
|
|
84
|
+
await scaffoldFromCore(projectPath, projectName, spinner);
|
|
85
|
+
spinner.stop(chalk.green(`✓ Successfully created app: ${projectName}`));
|
|
86
|
+
console.log(`\n${chalk.cyan('Next steps:')}`);
|
|
87
|
+
console.log(` ${chalk.gray('$')} cd ${projectName}`);
|
|
88
|
+
console.log(` ${chalk.gray('$')} pnpm start ${chalk.gray('(discovers providers, builds, and runs)')}`);
|
|
89
|
+
console.log(`\n${chalk.gray('Learn more:')} https://docs.dexto.ai\n`);
|
|
90
|
+
return projectPath;
|
|
91
|
+
}
|
|
92
|
+
// For from-image mode, select the image (if not already provided via flag)
|
|
93
|
+
if (!baseImage) {
|
|
94
|
+
const imageChoice = await selectOrExit({
|
|
95
|
+
message: 'Which image?',
|
|
96
|
+
options: [
|
|
97
|
+
{
|
|
98
|
+
value: '@dexto/image-local',
|
|
99
|
+
label: '@dexto/image-local (recommended)',
|
|
100
|
+
hint: 'Local dev - SQLite, filesystem',
|
|
101
|
+
},
|
|
102
|
+
{ value: 'custom', label: 'Custom npm package...' },
|
|
103
|
+
],
|
|
104
|
+
}, 'App creation cancelled');
|
|
105
|
+
if (imageChoice === 'custom') {
|
|
106
|
+
const customImage = await textOrExit({
|
|
107
|
+
message: 'Enter the npm package name:',
|
|
108
|
+
placeholder: '@myorg/image-custom',
|
|
109
|
+
validate: (value) => {
|
|
110
|
+
if (!value || value.trim() === '') {
|
|
111
|
+
return 'Package name is required';
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
},
|
|
115
|
+
}, 'App creation cancelled');
|
|
116
|
+
baseImage = customImage;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
baseImage = imageChoice;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Scaffold from existing image
|
|
123
|
+
await scaffoldFromImage(projectPath, projectName, baseImage, appType, originalCwd, spinner);
|
|
124
|
+
spinner.stop(chalk.green(`✓ Successfully created app: ${projectName}`));
|
|
125
|
+
console.log(`\n${chalk.cyan('Next steps:')}`);
|
|
126
|
+
console.log(` ${chalk.gray('$')} cd ${projectName}`);
|
|
127
|
+
console.log(` ${chalk.gray('$')} pnpm start`);
|
|
128
|
+
console.log(`\n${chalk.gray('Learn more:')} https://docs.dexto.ai\n`);
|
|
129
|
+
return projectPath;
|
|
50
130
|
}
|
|
51
131
|
catch (error) {
|
|
52
|
-
//
|
|
53
|
-
if (
|
|
54
|
-
|
|
55
|
-
|
|
132
|
+
// Restore original directory on error
|
|
133
|
+
if (originalCwd) {
|
|
134
|
+
try {
|
|
135
|
+
process.chdir(originalCwd);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Ignore if we can't restore - likely a more serious issue
|
|
139
|
+
}
|
|
56
140
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
spinner.stop(`Failed to create project: ${error}`);
|
|
60
|
-
throw error;
|
|
141
|
+
if (spinner) {
|
|
142
|
+
spinner.stop(chalk.red('✗ Failed to create app'));
|
|
61
143
|
}
|
|
144
|
+
throw error;
|
|
62
145
|
}
|
|
63
|
-
// Move to the new project directory
|
|
64
|
-
process.chdir(projectPath);
|
|
65
|
-
// initialize package.json
|
|
66
|
-
await executeWithTimeout('npm', ['init', '-y'], { cwd: projectPath });
|
|
67
|
-
// initialize git repository
|
|
68
|
-
await executeWithTimeout('git', ['init'], { cwd: projectPath });
|
|
69
|
-
// add .gitignore
|
|
70
|
-
await fs.writeFile('.gitignore', 'node_modules\n.env\ndist\n.dexto\n*.log');
|
|
71
|
-
// update package.json module type
|
|
72
|
-
const packageJson = JSON.parse(await fs.readFile('package.json', 'utf8'));
|
|
73
|
-
packageJson.type = 'module';
|
|
74
|
-
await fs.writeFile('package.json', JSON.stringify(packageJson, null, 2));
|
|
75
|
-
spinner.stop('Project files created successfully!');
|
|
76
|
-
spinner.start('Installing dependencies...');
|
|
77
|
-
const packageManager = getPackageManager();
|
|
78
|
-
const installCommand = getPackageManagerInstallCommand(packageManager);
|
|
79
|
-
// install yaml and dotenv
|
|
80
|
-
await executeWithTimeout(packageManager, [installCommand, 'yaml', 'dotenv'], {
|
|
81
|
-
cwd: projectPath,
|
|
82
|
-
});
|
|
83
|
-
// install typescript
|
|
84
|
-
await executeWithTimeout(packageManager, [installCommand, 'typescript', 'tsx', 'ts-node', '@types/node', '--save-dev'], { cwd: projectPath });
|
|
85
|
-
spinner.stop('Dependencies installed!');
|
|
86
|
-
return projectPath;
|
|
87
146
|
}
|
|
88
147
|
/**
|
|
89
|
-
*
|
|
90
|
-
* @param directory - The directory of the project
|
|
148
|
+
* Mode A: Scaffold app using existing image
|
|
91
149
|
*/
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
150
|
+
async function scaffoldFromImage(projectPath, projectName, imageName, appType, originalCwd, spinner) {
|
|
151
|
+
spinner.start('Setting up app structure...');
|
|
152
|
+
// Resolve package name for local images (needed for import statements)
|
|
153
|
+
let packageNameForImport = imageName;
|
|
154
|
+
if (imageName.startsWith('.')) {
|
|
155
|
+
const fullPath = path.resolve(originalCwd, imageName);
|
|
156
|
+
let packageDir = fullPath;
|
|
157
|
+
// If path ends with /dist/index.js, resolve to package root (parent of dist)
|
|
158
|
+
if (fullPath.endsWith('/dist/index.js') || fullPath.endsWith('\\dist\\index.js')) {
|
|
159
|
+
packageDir = path.dirname(path.dirname(fullPath));
|
|
160
|
+
}
|
|
161
|
+
else if (fullPath.endsWith('.js')) {
|
|
162
|
+
packageDir = path.dirname(fullPath);
|
|
163
|
+
}
|
|
164
|
+
// Read package.json to get the actual package name for imports
|
|
165
|
+
try {
|
|
166
|
+
const pkgJsonPath = path.join(packageDir, 'package.json');
|
|
167
|
+
const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf8'));
|
|
168
|
+
packageNameForImport = pkgJson.name;
|
|
169
|
+
}
|
|
170
|
+
catch (_error) {
|
|
171
|
+
logger.warn(`Could not read package.json from ${packageDir}, using path as import`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// Create folders
|
|
175
|
+
await ensureDirectory('src');
|
|
176
|
+
await ensureDirectory('agents');
|
|
177
|
+
// Create src/index.ts based on app type
|
|
178
|
+
let indexContent;
|
|
179
|
+
if (appType === 'webapp') {
|
|
180
|
+
indexContent = generateWebServerIndex({
|
|
181
|
+
projectName,
|
|
182
|
+
packageName: projectName,
|
|
183
|
+
description: 'Dexto web server application',
|
|
184
|
+
imageName: packageNameForImport,
|
|
185
|
+
});
|
|
186
|
+
// Create web app directory and files
|
|
187
|
+
await ensureDirectory('app');
|
|
188
|
+
await ensureDirectory('app/assets');
|
|
189
|
+
await fs.writeFile('app/index.html', generateWebAppHTML(projectName));
|
|
190
|
+
await fs.writeFile('app/assets/main.js', generateWebAppJS());
|
|
191
|
+
await fs.writeFile('app/assets/style.css', generateWebAppCSS());
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
indexContent = generateIndexForImage({
|
|
195
|
+
projectName,
|
|
196
|
+
packageName: projectName,
|
|
197
|
+
description: 'Dexto application',
|
|
198
|
+
imageName: packageNameForImport,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
await fs.writeFile('src/index.ts', indexContent);
|
|
202
|
+
// Create default agent config
|
|
203
|
+
const agentConfig = `# Default Agent Configuration
|
|
204
|
+
|
|
205
|
+
# Image: Specifies the provider bundle for this agent
|
|
206
|
+
image: '${imageName}'
|
|
207
|
+
|
|
208
|
+
# System prompt
|
|
209
|
+
systemPrompt:
|
|
210
|
+
contributors:
|
|
211
|
+
- id: primary
|
|
212
|
+
type: static
|
|
213
|
+
priority: 0
|
|
214
|
+
content: |
|
|
215
|
+
You are a helpful AI assistant.
|
|
216
|
+
|
|
217
|
+
# LLM configuration
|
|
218
|
+
llm:
|
|
219
|
+
provider: openai
|
|
220
|
+
model: gpt-4o
|
|
221
|
+
apiKey: $OPENAI_API_KEY
|
|
222
|
+
|
|
223
|
+
# Storage
|
|
224
|
+
storage:
|
|
225
|
+
cache:
|
|
226
|
+
type: in-memory
|
|
227
|
+
database:
|
|
228
|
+
type: sqlite
|
|
229
|
+
path: ./data/agent.db
|
|
230
|
+
blob:
|
|
231
|
+
type: local
|
|
232
|
+
storePath: ./data/blobs
|
|
233
|
+
|
|
234
|
+
# Custom tools - uncomment to enable filesystem and process tools
|
|
235
|
+
# customTools:
|
|
236
|
+
# - type: filesystem-tools
|
|
237
|
+
# allowedPaths: ['.']
|
|
238
|
+
# blockedPaths: ['.git', 'node_modules']
|
|
239
|
+
# - type: process-tools
|
|
240
|
+
# securityLevel: moderate
|
|
241
|
+
|
|
242
|
+
# MCP servers - add external tools here
|
|
243
|
+
# mcpServers:
|
|
244
|
+
# filesystem:
|
|
245
|
+
# type: stdio
|
|
246
|
+
# command: npx
|
|
247
|
+
# args:
|
|
248
|
+
# - -y
|
|
249
|
+
# - "@modelcontextprotocol/server-filesystem"
|
|
250
|
+
# - .
|
|
251
|
+
`;
|
|
252
|
+
await fs.writeFile('agents/default.yml', agentConfig);
|
|
253
|
+
spinner.message('Creating configuration files...');
|
|
254
|
+
// Create package.json
|
|
255
|
+
await initPackageJson(projectPath, projectName, 'app');
|
|
256
|
+
// Add scripts
|
|
257
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
258
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
259
|
+
packageJson.scripts = {
|
|
260
|
+
start: 'tsx src/index.ts',
|
|
95
261
|
build: 'tsc',
|
|
96
|
-
|
|
97
|
-
|
|
262
|
+
...packageJson.scripts,
|
|
263
|
+
};
|
|
264
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
265
|
+
// Create tsconfig.json
|
|
266
|
+
await createTsconfigForApp(projectPath, 'src');
|
|
267
|
+
// Create README
|
|
268
|
+
const readmeContent = generateAppReadme({
|
|
269
|
+
projectName,
|
|
270
|
+
packageName: projectName,
|
|
271
|
+
description: 'Dexto application using official image',
|
|
272
|
+
imageName,
|
|
273
|
+
});
|
|
274
|
+
await fs.writeFile('README.md', readmeContent);
|
|
275
|
+
// Create .env.example
|
|
276
|
+
await createEnvExample(projectPath, {
|
|
277
|
+
OPENAI_API_KEY: 'sk-...',
|
|
278
|
+
ANTHROPIC_API_KEY: 'sk-ant-...',
|
|
98
279
|
});
|
|
99
|
-
|
|
280
|
+
// Create .gitignore
|
|
281
|
+
await createGitignore(projectPath);
|
|
282
|
+
// Initialize git
|
|
283
|
+
spinner.message('Initializing git repository...');
|
|
284
|
+
await setupGitRepo(projectPath);
|
|
285
|
+
spinner.message('Installing dependencies...');
|
|
286
|
+
// Detect if we're in dexto source - use workspace protocol for local development
|
|
287
|
+
const executionContext = getExecutionContext();
|
|
288
|
+
const isDextoSource = executionContext === 'dexto-source';
|
|
289
|
+
const agentMgmtVersion = isDextoSource ? 'workspace:*' : '^1.3.0';
|
|
290
|
+
// Resolve relative paths to absolute for local images
|
|
291
|
+
// (npm/pnpm need absolute paths to package directories when installing from file system)
|
|
292
|
+
let resolvedImageName = imageName;
|
|
293
|
+
if (imageName.startsWith('.')) {
|
|
294
|
+
const fullPath = path.resolve(originalCwd, imageName);
|
|
295
|
+
// If path ends with /dist/index.js, resolve to package root (parent of dist)
|
|
296
|
+
if (fullPath.endsWith('/dist/index.js') || fullPath.endsWith('\\dist\\index.js')) {
|
|
297
|
+
resolvedImageName = path.dirname(path.dirname(fullPath));
|
|
298
|
+
}
|
|
299
|
+
else if (fullPath.endsWith('.js')) {
|
|
300
|
+
// If it's a .js file but not the standard structure, use the directory
|
|
301
|
+
resolvedImageName = path.dirname(fullPath);
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
// It's already a directory
|
|
305
|
+
resolvedImageName = fullPath;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
else if (isDextoSource && imageName.startsWith('@dexto/image-')) {
|
|
309
|
+
// In dexto source, resolve official images to local workspace packages
|
|
310
|
+
// e.g., @dexto/image-local -> packages/image-local
|
|
311
|
+
const imagePkgName = imageName.replace('@dexto/', '');
|
|
312
|
+
const imagePkgPath = path.resolve(originalCwd, 'packages', imagePkgName);
|
|
313
|
+
if (await fs.pathExists(imagePkgPath)) {
|
|
314
|
+
resolvedImageName = imagePkgPath;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Install dependencies (use pnpm in dexto source for workspace protocol support)
|
|
318
|
+
// Image is loaded as "environment" - we import from core packages directly
|
|
319
|
+
const coreVersion = isDextoSource ? 'workspace:*' : '^1.3.0';
|
|
320
|
+
const serverVersion = isDextoSource ? 'workspace:*' : '^1.3.0';
|
|
321
|
+
const dependencies = [
|
|
322
|
+
resolvedImageName, // Image provides the environment/providers
|
|
323
|
+
`@dexto/core@${coreVersion}`, // Import DextoAgent from here
|
|
324
|
+
`@dexto/agent-management@${agentMgmtVersion}`, // Import loadAgentConfig from here
|
|
325
|
+
'tsx',
|
|
326
|
+
];
|
|
327
|
+
// Add @dexto/server dependency for webapp type
|
|
328
|
+
if (appType === 'webapp') {
|
|
329
|
+
dependencies.push(`@dexto/server@${serverVersion}`);
|
|
330
|
+
}
|
|
331
|
+
await installDependencies(projectPath, {
|
|
332
|
+
dependencies,
|
|
333
|
+
devDependencies: ['typescript@^5.0.0', '@types/node@^20.0.0'],
|
|
334
|
+
}, isDextoSource ? 'pnpm' : undefined);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Mode B: Scaffold standalone app built from @dexto/core
|
|
338
|
+
* Supports both dev (runtime discovery) and production (build-time discovery) workflows
|
|
339
|
+
*/
|
|
340
|
+
async function scaffoldFromCore(projectPath, projectName, spinner) {
|
|
341
|
+
spinner.start('Setting up app structure...');
|
|
342
|
+
// Always include example tool for from-core mode
|
|
343
|
+
const includeExample = true;
|
|
344
|
+
// Create convention-based folders
|
|
345
|
+
await ensureDirectory('src');
|
|
346
|
+
await ensureDirectory('scripts');
|
|
347
|
+
await ensureDirectory('tools');
|
|
348
|
+
await ensureDirectory('blob-store');
|
|
349
|
+
await ensureDirectory('compression');
|
|
350
|
+
await ensureDirectory('plugins');
|
|
351
|
+
await ensureDirectory('agents');
|
|
352
|
+
// Create .gitkeep files for empty directories
|
|
353
|
+
await fs.writeFile('blob-store/.gitkeep', '');
|
|
354
|
+
await fs.writeFile('compression/.gitkeep', '');
|
|
355
|
+
await fs.writeFile('plugins/.gitkeep', '');
|
|
356
|
+
// Create example tool if requested
|
|
357
|
+
if (includeExample) {
|
|
358
|
+
await ensureDirectory('tools/example-tool');
|
|
359
|
+
const exampleToolCode = generateExampleTool('example-tool');
|
|
360
|
+
await fs.writeFile('tools/example-tool/index.ts', exampleToolCode);
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
await fs.writeFile('tools/.gitkeep', '');
|
|
364
|
+
}
|
|
365
|
+
spinner.message('Generating app files...');
|
|
366
|
+
// Create dexto.config.ts for provider discovery configuration
|
|
367
|
+
const dextoConfigContent = `import { defineConfig } from '@dexto/core';
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Dexto Configuration
|
|
371
|
+
*
|
|
372
|
+
* Provider Discovery Modes:
|
|
373
|
+
* - Development (pnpm dev): Runtime discovery - fast iteration, no rebuild needed
|
|
374
|
+
* - Production (pnpm build): Build-time discovery - validates and optimizes everything
|
|
375
|
+
*
|
|
376
|
+
* This mirrors Next.js approach:
|
|
377
|
+
* - next dev: Runtime compilation
|
|
378
|
+
* - next build + next start: Pre-built production bundle
|
|
379
|
+
*/
|
|
380
|
+
export default defineConfig({
|
|
381
|
+
providers: {
|
|
382
|
+
// Auto-discover providers from convention-based folders
|
|
383
|
+
autoDiscover: true,
|
|
384
|
+
folders: ['tools', 'blob-store', 'compression', 'plugins'],
|
|
385
|
+
},
|
|
386
|
+
});
|
|
387
|
+
`;
|
|
388
|
+
await fs.writeFile('dexto.config.ts', dextoConfigContent);
|
|
389
|
+
// Create build-time discovery script
|
|
390
|
+
const discoveryScript = generateDiscoveryScript();
|
|
391
|
+
await fs.writeFile('scripts/discover-providers.ts', discoveryScript);
|
|
392
|
+
// Create app entry point - completely clean, no provider registration code
|
|
393
|
+
const appIndexContent = `// Standalone Dexto app
|
|
394
|
+
// Development: Providers auto-discovered at runtime (pnpm dev)
|
|
395
|
+
// Production: Providers bundled at build time (pnpm build + pnpm start)
|
|
396
|
+
|
|
397
|
+
import { DextoAgent } from '@dexto/core';
|
|
398
|
+
import { loadAgentConfig } from '@dexto/agent-management';
|
|
399
|
+
|
|
400
|
+
async function main() {
|
|
401
|
+
console.log('🚀 Starting ${projectName}\\n');
|
|
402
|
+
|
|
403
|
+
// Load agent configuration
|
|
404
|
+
// In dev mode: providers discovered at runtime from dexto.config.ts
|
|
405
|
+
// In production: providers pre-registered at build time
|
|
406
|
+
const config = await loadAgentConfig('./agents/default.yml');
|
|
407
|
+
|
|
408
|
+
// Create agent
|
|
409
|
+
const agent = new DextoAgent(config, './agents/default.yml');
|
|
410
|
+
|
|
411
|
+
await agent.start();
|
|
412
|
+
console.log('✅ Agent started\\n');
|
|
413
|
+
|
|
414
|
+
// Create a session
|
|
415
|
+
const session = await agent.createSession();
|
|
416
|
+
|
|
417
|
+
// Example interaction
|
|
418
|
+
const response = await agent.run(
|
|
419
|
+
'Hello! Can you help me understand what custom tools are available?',
|
|
420
|
+
undefined, // imageDataInput
|
|
421
|
+
undefined, // fileDataInput
|
|
422
|
+
session.id // sessionId
|
|
423
|
+
);
|
|
424
|
+
|
|
425
|
+
console.log('Agent response:', response);
|
|
426
|
+
|
|
427
|
+
// Cleanup
|
|
428
|
+
await agent.stop();
|
|
100
429
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
430
|
+
|
|
431
|
+
main().catch((error) => {
|
|
432
|
+
console.error('Error:', error);
|
|
433
|
+
process.exit(1);
|
|
434
|
+
});
|
|
435
|
+
`;
|
|
436
|
+
await fs.writeFile('src/index.ts', appIndexContent);
|
|
437
|
+
// Create default agent config
|
|
438
|
+
const agentConfig = `# Default Agent Configuration
|
|
439
|
+
|
|
440
|
+
# System prompt
|
|
441
|
+
systemPrompt:
|
|
442
|
+
contributors:
|
|
443
|
+
- id: primary
|
|
444
|
+
type: static
|
|
445
|
+
priority: 0
|
|
446
|
+
content: |
|
|
447
|
+
You are a helpful AI assistant with custom tools.
|
|
448
|
+
|
|
449
|
+
# LLM configuration
|
|
450
|
+
llm:
|
|
451
|
+
provider: openai
|
|
452
|
+
model: gpt-4o
|
|
453
|
+
apiKey: $OPENAI_API_KEY
|
|
454
|
+
|
|
455
|
+
# Storage
|
|
456
|
+
storage:
|
|
457
|
+
cache:
|
|
458
|
+
type: in-memory
|
|
459
|
+
database:
|
|
460
|
+
type: sqlite
|
|
461
|
+
path: ./data/agent.db
|
|
462
|
+
blob:
|
|
463
|
+
type: local
|
|
464
|
+
storePath: ./data/blobs
|
|
465
|
+
|
|
466
|
+
# Custom tools are auto-discovered at runtime from tools/ folder
|
|
467
|
+
# See dexto.config.ts for provider discovery configuration
|
|
468
|
+
|
|
469
|
+
# MCP servers - add external tools here
|
|
470
|
+
# mcpServers:
|
|
471
|
+
# filesystem:
|
|
472
|
+
# type: stdio
|
|
473
|
+
# command: npx
|
|
474
|
+
# args:
|
|
475
|
+
# - -y
|
|
476
|
+
# - "@modelcontextprotocol/server-filesystem"
|
|
477
|
+
# - .
|
|
478
|
+
`;
|
|
479
|
+
await fs.writeFile('agents/default.yml', agentConfig);
|
|
480
|
+
spinner.message('Creating configuration files...');
|
|
481
|
+
// Create package.json for standalone app
|
|
482
|
+
await initPackageJson(projectPath, projectName, 'app');
|
|
483
|
+
// Add scripts for both development and production workflows
|
|
484
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
485
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
486
|
+
packageJson.scripts = {
|
|
487
|
+
// Development: runtime discovery (fast iteration)
|
|
488
|
+
dev: 'tsx src/index.ts',
|
|
489
|
+
// Production: build-time discovery + bundling
|
|
490
|
+
build: 'tsx scripts/discover-providers.ts && tsup',
|
|
491
|
+
start: 'node dist/_entry.js',
|
|
492
|
+
typecheck: 'tsc --noEmit',
|
|
493
|
+
discover: 'tsx scripts/discover-providers.ts',
|
|
494
|
+
...packageJson.scripts,
|
|
495
|
+
};
|
|
496
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
497
|
+
// Create tsconfig.json
|
|
498
|
+
const tsconfigContent = {
|
|
106
499
|
compilerOptions: {
|
|
107
500
|
target: 'ES2022',
|
|
108
501
|
module: 'ESNext',
|
|
109
|
-
moduleResolution: '
|
|
502
|
+
moduleResolution: 'bundler',
|
|
503
|
+
lib: ['ES2022'],
|
|
504
|
+
outDir: './dist',
|
|
505
|
+
rootDir: './src',
|
|
110
506
|
strict: true,
|
|
111
507
|
esModuleInterop: true,
|
|
112
|
-
forceConsistentCasingInFileNames: true,
|
|
113
508
|
skipLibCheck: true,
|
|
114
|
-
|
|
115
|
-
|
|
509
|
+
forceConsistentCasingInFileNames: true,
|
|
510
|
+
resolveJsonModule: true,
|
|
511
|
+
declaration: true,
|
|
512
|
+
declarationMap: true,
|
|
513
|
+
sourceMap: true,
|
|
116
514
|
},
|
|
117
|
-
include: [
|
|
118
|
-
exclude: ['node_modules', 'dist'
|
|
515
|
+
include: ['src/**/*', 'tools/**/*', 'blob-store/**/*', 'compression/**/*', 'plugins/**/*'],
|
|
516
|
+
exclude: ['node_modules', 'dist'],
|
|
119
517
|
};
|
|
120
|
-
await fs.
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
518
|
+
await fs.writeFile('tsconfig.json', JSON.stringify(tsconfigContent, null, 2));
|
|
519
|
+
// Create tsup.config.ts - builds from generated _entry.ts for production
|
|
520
|
+
const tsupConfig = `import { defineConfig } from 'tsup';
|
|
521
|
+
|
|
522
|
+
export default defineConfig({
|
|
523
|
+
entry: ['src/_entry.ts'], // Generated by scripts/discover-providers.ts
|
|
524
|
+
format: ['esm'],
|
|
525
|
+
dts: false, // Skip DTS for build artifacts
|
|
526
|
+
sourcemap: true,
|
|
527
|
+
clean: true,
|
|
528
|
+
external: ['@dexto/core', '@dexto/agent-management'],
|
|
529
|
+
noExternal: [],
|
|
530
|
+
});
|
|
531
|
+
`;
|
|
532
|
+
await fs.writeFile('tsup.config.ts', tsupConfig);
|
|
533
|
+
// Create .gitignore - ignore generated build artifacts
|
|
534
|
+
await createGitignore(projectPath, [
|
|
535
|
+
'*.tsbuildinfo',
|
|
536
|
+
'dist/',
|
|
537
|
+
'src/_entry.ts',
|
|
538
|
+
'src/_providers.ts',
|
|
539
|
+
]);
|
|
540
|
+
// Create .env.example
|
|
541
|
+
await createEnvExample(projectPath, {
|
|
542
|
+
OPENAI_API_KEY: 'sk-...',
|
|
543
|
+
ANTHROPIC_API_KEY: 'sk-ant-...',
|
|
544
|
+
});
|
|
545
|
+
// Create README
|
|
546
|
+
const readmeContent = `# ${projectName}
|
|
547
|
+
|
|
548
|
+
Standalone Dexto app with convention-based auto-discovery.
|
|
549
|
+
|
|
550
|
+
## Getting Started
|
|
551
|
+
|
|
552
|
+
\`\`\`bash
|
|
553
|
+
# Install dependencies
|
|
554
|
+
pnpm install
|
|
555
|
+
|
|
556
|
+
# Add your API key
|
|
557
|
+
cp .env.example .env
|
|
558
|
+
# Edit .env and add your OPENAI_API_KEY
|
|
559
|
+
|
|
560
|
+
# Development (runtime discovery - fast iteration)
|
|
561
|
+
pnpm dev
|
|
562
|
+
|
|
563
|
+
# Production (build-time discovery + optimized bundle)
|
|
564
|
+
pnpm build
|
|
565
|
+
pnpm start
|
|
566
|
+
\`\`\`
|
|
567
|
+
|
|
568
|
+
That's it! Custom providers are discovered automatically:
|
|
569
|
+
- **Dev mode** (\`pnpm dev\`): Runtime discovery - add/modify providers without rebuilding
|
|
570
|
+
- **Production** (\`pnpm build\`): Build-time discovery - validates and bundles everything
|
|
571
|
+
|
|
572
|
+
## Project Structure
|
|
573
|
+
|
|
574
|
+
\`\`\`
|
|
575
|
+
${projectName}/
|
|
576
|
+
├── src/
|
|
577
|
+
│ ├── index.ts # Your app code (clean, no boilerplate!)
|
|
578
|
+
│ ├── _entry.ts # Auto-generated (build only, gitignored)
|
|
579
|
+
│ └── _providers.ts # Auto-generated (build only, gitignored)
|
|
580
|
+
├── scripts/
|
|
581
|
+
│ └── discover-providers.ts # Build-time discovery script
|
|
582
|
+
├── dexto.config.ts # Provider discovery configuration
|
|
583
|
+
├── tools/ # Add custom tool providers here
|
|
584
|
+
├── blob-store/ # Add custom blob storage providers here
|
|
585
|
+
├── compression/ # Add custom compression providers here
|
|
586
|
+
├── plugins/ # Add custom plugins here
|
|
587
|
+
└── agents/
|
|
588
|
+
└── default.yml # Agent configuration
|
|
589
|
+
\`\`\`
|
|
590
|
+
|
|
591
|
+
## Adding Custom Providers
|
|
592
|
+
|
|
593
|
+
1. Create a provider in the appropriate folder (tools/, blob-store/, compression/, plugins/)
|
|
594
|
+
2. Export it with the naming convention: \`<folderName>Provider\`
|
|
595
|
+
3. Run \`pnpm dev\` (instant) or \`pnpm build\` (validated) - everything is auto-discovered!
|
|
596
|
+
|
|
597
|
+
**Example** - Adding a custom tool:
|
|
598
|
+
\`\`\`typescript
|
|
599
|
+
// tools/my-tool/index.ts
|
|
600
|
+
import { z } from 'zod';
|
|
601
|
+
|
|
602
|
+
export const myToolProvider = {
|
|
603
|
+
type: 'my-tool',
|
|
604
|
+
configSchema: z.object({ type: z.literal('my-tool') }),
|
|
605
|
+
tools: [
|
|
606
|
+
{
|
|
607
|
+
name: 'do_something',
|
|
608
|
+
description: 'Does something useful',
|
|
609
|
+
parameters: z.object({ input: z.string() }),
|
|
610
|
+
execute: async ({ input }) => {
|
|
611
|
+
return \`Processed: \${input}\`;
|
|
612
|
+
},
|
|
613
|
+
},
|
|
614
|
+
],
|
|
615
|
+
};
|
|
616
|
+
\`\`\`
|
|
617
|
+
|
|
618
|
+
That's it! No imports, no registration code needed.
|
|
619
|
+
|
|
620
|
+
## Scripts
|
|
621
|
+
|
|
622
|
+
- \`pnpm start\` - Build and run (auto-discovers providers)
|
|
623
|
+
- \`pnpm run dev\` - Development mode with hot reload
|
|
624
|
+
- \`pnpm run build\` - Build only
|
|
625
|
+
- \`pnpm run discover\` - Manually run provider discovery
|
|
626
|
+
- \`pnpm run typecheck\` - Type check
|
|
627
|
+
|
|
628
|
+
## How It Works
|
|
629
|
+
|
|
630
|
+
1. **Discovery**: Scans conventional folders for providers
|
|
631
|
+
2. **Generation**: Creates \`src/_providers.ts\` (registrations) and \`src/_entry.ts\` (wiring)
|
|
632
|
+
3. **Build**: Bundles everything into \`dist/_entry.js\`
|
|
633
|
+
4. **Run**: Your clean app code runs with all providers pre-registered
|
|
634
|
+
|
|
635
|
+
## Learn More
|
|
636
|
+
|
|
637
|
+
- [Dexto Documentation](https://docs.dexto.ai)
|
|
638
|
+
- [Custom Tools Guide](https://docs.dexto.ai/docs/guides/custom-tools)
|
|
639
|
+
`;
|
|
640
|
+
await fs.writeFile('README.md', readmeContent);
|
|
641
|
+
// Initialize git
|
|
642
|
+
spinner.message('Initializing git repository...');
|
|
643
|
+
await setupGitRepo(projectPath);
|
|
644
|
+
spinner.message('Installing dependencies...');
|
|
645
|
+
// Detect if we're in dexto source - use workspace protocol for local development
|
|
646
|
+
const executionContext = getExecutionContext();
|
|
647
|
+
const isDextoSource = executionContext === 'dexto-source';
|
|
648
|
+
const coreVersion = isDextoSource ? 'workspace:*' : '^1.3.0';
|
|
649
|
+
const agentMgmtVersion = isDextoSource ? 'workspace:*' : '^1.3.0';
|
|
650
|
+
// Install dependencies (use pnpm in dexto source for workspace protocol support)
|
|
651
|
+
await installDependencies(projectPath, {
|
|
652
|
+
dependencies: [
|
|
653
|
+
`@dexto/core@${coreVersion}`,
|
|
654
|
+
'zod',
|
|
655
|
+
`@dexto/agent-management@${agentMgmtVersion}`,
|
|
656
|
+
],
|
|
657
|
+
devDependencies: ['typescript@^5.0.0', '@types/node@^20.0.0', 'tsx', 'tsup'],
|
|
658
|
+
}, isDextoSource ? 'pnpm' : undefined);
|
|
135
659
|
}
|