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.
Files changed (223) 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.js +7 -7
  34. package/dist/cli/commands/interactive-commands/general-commands.js +1 -1
  35. package/dist/cli/commands/interactive-commands/prompt-commands.js +11 -11
  36. package/dist/cli/commands/interactive-commands/system/system-commands.js +3 -3
  37. package/dist/cli/commands/list-agents.js +2 -2
  38. package/dist/cli/commands/session-commands.js +16 -16
  39. package/dist/cli/commands/setup.d.ts +13 -5
  40. package/dist/cli/commands/setup.d.ts.map +1 -1
  41. package/dist/cli/commands/setup.js +860 -65
  42. package/dist/cli/commands/which.js +1 -1
  43. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts +2 -0
  44. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
  45. package/dist/cli/ink-cli/components/ApprovalPrompt.js +29 -7
  46. package/dist/cli/ink-cli/components/CustomInput.js +1 -1
  47. package/dist/cli/ink-cli/components/EditableMultiLineInput.js +4 -4
  48. package/dist/cli/ink-cli/components/ElicitationForm.d.ts.map +1 -1
  49. package/dist/cli/ink-cli/components/ElicitationForm.js +6 -6
  50. package/dist/cli/ink-cli/components/ErrorBoundary.d.ts.map +1 -1
  51. package/dist/cli/ink-cli/components/ErrorBoundary.js +1 -1
  52. package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
  53. package/dist/cli/ink-cli/components/Footer.js +1 -1
  54. package/dist/cli/ink-cli/components/HistorySearchBar.d.ts.map +1 -1
  55. package/dist/cli/ink-cli/components/HistorySearchBar.js +1 -1
  56. package/dist/cli/ink-cli/components/MultiLineInput.d.ts.map +1 -1
  57. package/dist/cli/ink-cli/components/MultiLineInput.js +3 -3
  58. package/dist/cli/ink-cli/components/ResourceAutocomplete.d.ts.map +1 -1
  59. package/dist/cli/ink-cli/components/ResourceAutocomplete.js +4 -4
  60. package/dist/cli/ink-cli/components/SlashCommandAutocomplete.js +3 -3
  61. package/dist/cli/ink-cli/components/StatusBar.d.ts.map +1 -1
  62. package/dist/cli/ink-cli/components/StatusBar.js +7 -5
  63. package/dist/cli/ink-cli/components/TextBufferInput.d.ts.map +1 -1
  64. package/dist/cli/ink-cli/components/TextBufferInput.js +6 -6
  65. package/dist/cli/ink-cli/components/base/BaseAutocomplete.js +4 -4
  66. package/dist/cli/ink-cli/components/base/BaseSelector.js +2 -2
  67. package/dist/cli/ink-cli/components/chat/Footer.js +1 -1
  68. package/dist/cli/ink-cli/components/chat/Header.d.ts.map +1 -1
  69. package/dist/cli/ink-cli/components/chat/Header.js +2 -4
  70. package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
  71. package/dist/cli/ink-cli/components/chat/MessageItem.js +5 -5
  72. package/dist/cli/ink-cli/components/chat/MessageList.js +1 -1
  73. package/dist/cli/ink-cli/components/chat/QueuedMessagesDisplay.js +1 -1
  74. package/dist/cli/ink-cli/components/chat/ToolIcon.d.ts +1 -1
  75. package/dist/cli/ink-cli/components/chat/ToolIcon.js +4 -4
  76. package/dist/cli/ink-cli/components/chat/styled-boxes/ConfigBox.js +1 -1
  77. package/dist/cli/ink-cli/components/chat/styled-boxes/HelpBox.js +1 -1
  78. package/dist/cli/ink-cli/components/chat/styled-boxes/LogConfigBox.js +2 -2
  79. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionHistoryBox.js +5 -5
  80. package/dist/cli/ink-cli/components/chat/styled-boxes/SessionListBox.js +2 -2
  81. package/dist/cli/ink-cli/components/chat/styled-boxes/ShortcutsBox.js +1 -1
  82. package/dist/cli/ink-cli/components/chat/styled-boxes/StatsBox.js +1 -1
  83. package/dist/cli/ink-cli/components/chat/styled-boxes/StyledBox.js +2 -2
  84. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
  85. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +1 -1
  86. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
  87. package/dist/cli/ink-cli/components/modes/StaticCLI.js +1 -1
  88. package/dist/cli/ink-cli/components/overlays/ApiKeyInput.js +1 -1
  89. package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts +10 -2
  90. package/dist/cli/ink-cli/components/overlays/CustomModelWizard.d.ts.map +1 -1
  91. package/dist/cli/ink-cli/components/overlays/CustomModelWizard.js +198 -89
  92. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.d.ts.map +1 -1
  93. package/dist/cli/ink-cli/components/overlays/LogLevelSelector.js +2 -2
  94. package/dist/cli/ink-cli/components/overlays/McpAddChoice.d.ts.map +1 -1
  95. package/dist/cli/ink-cli/components/overlays/McpAddChoice.js +1 -1
  96. package/dist/cli/ink-cli/components/overlays/McpAddSelector.js +1 -1
  97. package/dist/cli/ink-cli/components/overlays/McpCustomTypeSelector.d.ts.map +1 -1
  98. package/dist/cli/ink-cli/components/overlays/McpCustomTypeSelector.js +2 -2
  99. package/dist/cli/ink-cli/components/overlays/McpCustomWizard.js +1 -1
  100. package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.d.ts.map +1 -1
  101. package/dist/cli/ink-cli/components/overlays/McpRemoveSelector.js +1 -1
  102. package/dist/cli/ink-cli/components/overlays/McpSelector.d.ts.map +1 -1
  103. package/dist/cli/ink-cli/components/overlays/McpSelector.js +1 -1
  104. package/dist/cli/ink-cli/components/overlays/McpServerActions.d.ts.map +1 -1
  105. package/dist/cli/ink-cli/components/overlays/McpServerActions.js +2 -2
  106. package/dist/cli/ink-cli/components/overlays/McpServerList.d.ts.map +1 -1
  107. package/dist/cli/ink-cli/components/overlays/McpServerList.js +1 -1
  108. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts +5 -5
  109. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.d.ts.map +1 -1
  110. package/dist/cli/ink-cli/components/overlays/ModelSelectorRefactored.js +222 -68
  111. package/dist/cli/ink-cli/components/overlays/PromptAddChoice.d.ts.map +1 -1
  112. package/dist/cli/ink-cli/components/overlays/PromptAddChoice.js +2 -2
  113. package/dist/cli/ink-cli/components/overlays/PromptAddWizard.js +1 -1
  114. package/dist/cli/ink-cli/components/overlays/PromptDeleteSelector.d.ts.map +1 -1
  115. package/dist/cli/ink-cli/components/overlays/PromptDeleteSelector.js +2 -2
  116. package/dist/cli/ink-cli/components/overlays/PromptList.d.ts.map +1 -1
  117. package/dist/cli/ink-cli/components/overlays/PromptList.js +2 -2
  118. package/dist/cli/ink-cli/components/overlays/SearchOverlay.d.ts.map +1 -1
  119. package/dist/cli/ink-cli/components/overlays/SearchOverlay.js +4 -4
  120. package/dist/cli/ink-cli/components/overlays/SessionSubcommandSelector.d.ts.map +1 -1
  121. package/dist/cli/ink-cli/components/overlays/SessionSubcommandSelector.js +1 -1
  122. package/dist/cli/ink-cli/components/overlays/StreamSelector.d.ts.map +1 -1
  123. package/dist/cli/ink-cli/components/overlays/StreamSelector.js +1 -1
  124. package/dist/cli/ink-cli/components/overlays/ToolBrowser.js +12 -12
  125. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts +25 -0
  126. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.d.ts.map +1 -0
  127. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/LocalModelWizard.js +609 -0
  128. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.d.ts +15 -0
  129. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.d.ts.map +1 -0
  130. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/index.js +14 -0
  131. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts +33 -0
  132. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.d.ts.map +1 -0
  133. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/provider-config.js +419 -0
  134. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.d.ts +25 -0
  135. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.d.ts.map +1 -0
  136. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ApiKeyStep.js +29 -0
  137. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.d.ts +17 -0
  138. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.d.ts.map +1 -0
  139. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/ProviderSelector.js +11 -0
  140. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.d.ts +20 -0
  141. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.d.ts.map +1 -0
  142. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/SetupInfoBanner.js +10 -0
  143. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.d.ts +30 -0
  144. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.d.ts.map +1 -0
  145. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/WizardStepInput.js +13 -0
  146. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.d.ts +8 -0
  147. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.d.ts.map +1 -0
  148. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/shared/index.js +7 -0
  149. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts +79 -0
  150. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.d.ts.map +1 -0
  151. package/dist/cli/ink-cli/components/overlays/custom-model-wizard/types.js +38 -0
  152. package/dist/cli/ink-cli/components/renderers/DiffRenderer.js +2 -2
  153. package/dist/cli/ink-cli/components/renderers/FilePreviewRenderer.js +1 -1
  154. package/dist/cli/ink-cli/components/renderers/FileRenderer.js +4 -4
  155. package/dist/cli/ink-cli/components/renderers/GenericRenderer.js +2 -2
  156. package/dist/cli/ink-cli/components/renderers/SearchRenderer.js +1 -1
  157. package/dist/cli/ink-cli/components/renderers/ShellRenderer.js +3 -3
  158. package/dist/cli/ink-cli/components/renderers/diff-shared.js +1 -1
  159. package/dist/cli/ink-cli/components/shared/MarkdownText.d.ts.map +1 -1
  160. package/dist/cli/ink-cli/components/shared/MarkdownText.js +8 -6
  161. package/dist/cli/ink-cli/containers/InputContainer.d.ts.map +1 -1
  162. package/dist/cli/ink-cli/containers/InputContainer.js +23 -1
  163. package/dist/cli/ink-cli/containers/OverlayContainer.d.ts.map +1 -1
  164. package/dist/cli/ink-cli/containers/OverlayContainer.js +80 -24
  165. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts +1 -1
  166. package/dist/cli/ink-cli/hooks/useAgentEvents.d.ts.map +1 -1
  167. package/dist/cli/ink-cli/hooks/useAgentEvents.js +5 -1
  168. package/dist/cli/ink-cli/hooks/useCLIState.d.ts +1 -1
  169. package/dist/cli/ink-cli/hooks/useCLIState.d.ts.map +1 -1
  170. package/dist/cli/ink-cli/hooks/useCLIState.js +4 -2
  171. package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
  172. package/dist/cli/ink-cli/services/processStream.js +77 -9
  173. package/dist/cli/ink-cli/state/types.d.ts +3 -2
  174. package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
  175. package/dist/cli/ink-cli/utils/messageFormatting.d.ts +5 -0
  176. package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
  177. package/dist/cli/ink-cli/utils/messageFormatting.js +59 -1
  178. package/dist/cli/ink-cli/utils/toolUtils.d.ts.map +1 -1
  179. package/dist/cli/ink-cli/utils/toolUtils.js +2 -0
  180. package/dist/cli/utils/api-key-setup.d.ts +54 -4
  181. package/dist/cli/utils/api-key-setup.d.ts.map +1 -1
  182. package/dist/cli/utils/api-key-setup.js +433 -107
  183. package/dist/cli/utils/api-key-verification.d.ts +17 -0
  184. package/dist/cli/utils/api-key-verification.d.ts.map +1 -0
  185. package/dist/cli/utils/api-key-verification.js +211 -0
  186. package/dist/cli/utils/config-validation.d.ts +22 -2
  187. package/dist/cli/utils/config-validation.d.ts.map +1 -1
  188. package/dist/cli/utils/config-validation.js +354 -25
  189. package/dist/cli/utils/local-model-setup.d.ts +46 -0
  190. package/dist/cli/utils/local-model-setup.d.ts.map +1 -0
  191. package/dist/cli/utils/local-model-setup.js +662 -0
  192. package/dist/cli/utils/options.js +1 -1
  193. package/dist/cli/utils/prompt-helpers.d.ts +47 -0
  194. package/dist/cli/utils/prompt-helpers.d.ts.map +1 -0
  195. package/dist/cli/utils/prompt-helpers.js +66 -0
  196. package/dist/cli/utils/provider-setup.d.ts +66 -8
  197. package/dist/cli/utils/provider-setup.d.ts.map +1 -1
  198. package/dist/cli/utils/provider-setup.js +324 -84
  199. package/dist/cli/utils/scaffolding-utils.d.ts +76 -0
  200. package/dist/cli/utils/scaffolding-utils.d.ts.map +1 -0
  201. package/dist/cli/utils/scaffolding-utils.js +246 -0
  202. package/dist/cli/utils/setup-utils.d.ts +16 -0
  203. package/dist/cli/utils/setup-utils.d.ts.map +1 -1
  204. package/dist/cli/utils/setup-utils.js +72 -21
  205. package/dist/cli/utils/template-engine.d.ts +65 -0
  206. package/dist/cli/utils/template-engine.d.ts.map +1 -0
  207. package/dist/cli/utils/template-engine.js +1089 -0
  208. package/dist/config/cli-overrides.d.ts +44 -1
  209. package/dist/config/cli-overrides.d.ts.map +1 -1
  210. package/dist/config/cli-overrides.js +102 -0
  211. package/dist/index.js +315 -53
  212. package/dist/webui/assets/index-8j-KMkX1.js +2054 -0
  213. package/dist/webui/assets/index-c_AX24V4.css +1 -0
  214. package/dist/webui/index.html +3 -9
  215. package/dist/webui/logos/aws-color.svg +1 -0
  216. package/dist/webui/logos/dexto/dexto_logo.svg +1 -1
  217. package/dist/webui/logos/dexto/dexto_logo_light.svg +6 -6
  218. package/dist/webui/logos/glama.svg +7 -0
  219. package/dist/webui/logos/litellm.svg +7 -0
  220. package/dist/webui/logos/openrouter.svg +1 -0
  221. package/package.json +8 -7
  222. package/dist/webui/assets/index-BkwPkZpd.css +0 -1
  223. 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 basic scaffolding for a Dexto project
10
- * sets up git and gitignore, and sets up initial dependencies
11
- * Does not add scripts to package.json or create tsconfig.json which require the directory name
12
- * @param name - The name of the project
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
- // Basic regex: must start with a letter, contain only letters, numbers, hyphens or underscores
17
- const nameRegex = /^[a-zA-Z][a-zA-Z0-9-_]*$/;
18
- let projectName;
19
- if (name) {
20
- // Validate provided project name
21
- if (!nameRegex.test(name)) {
22
- console.log(chalk.red('Invalid project name. Must start with a letter and contain only letters, numbers, hyphens or underscores.'));
23
- process.exit(1);
24
- }
25
- projectName = name;
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
- let input;
29
- do {
30
- input = await p.text({
31
- message: 'What do you want to name your Dexto project?',
32
- placeholder: 'my-dexto-project',
33
- defaultValue: 'my-dexto-project',
34
- });
35
- if (p.isCancel(input)) {
36
- p.cancel('Project creation cancelled');
37
- process.exit(0);
38
- }
39
- if (!nameRegex.test(input)) {
40
- console.log(chalk.red('Invalid project name. Must start with a letter and contain only letters, numbers, hyphens or underscores.'));
41
- }
42
- } while (!nameRegex.test(input));
43
- projectName = input;
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
- const projectPath = path.resolve(process.cwd(), projectName);
47
- spinner.start(`Creating dexto project in ${projectPath}...`);
75
+ let projectPath;
76
+ const originalCwd = process.cwd();
48
77
  try {
49
- await fs.mkdir(projectPath);
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
- // if the directory already exists, end the process
53
- if (error instanceof Error && 'code' in error && error.code === 'EEXIST') {
54
- spinner.stop(`Directory "${projectName}" already exists. Please choose a different name or delete the existing directory.`);
55
- process.exit(1);
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
- else {
58
- // If it's not an EEXIST error, rethrow it to be caught by the outer catch
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
- * Adds the dexto scripts to the package.json. Assumes the package.json already exists and is accessible
90
- * @param directory - The directory of the project
148
+ * Mode A: Scaffold app using existing image
91
149
  */
92
- export async function addDextoScriptsToPackageJson(directory, projectPath) {
93
- logger.debug(`Adding dexto scripts to package.json in ${projectPath}`);
94
- await addScriptsToPackageJson({
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
- start: `node dist/${path.join('dexto', 'dexto-example.js')}`,
97
- dev: `node --loader ts-node/esm ${path.join(directory, 'dexto', 'dexto-example.ts')}`,
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
- logger.debug(`Successfully added dexto scripts to package.json in ${projectPath}`);
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
- /** Creates a tsconfig.json file in the project directory */
102
- export async function createTsconfigJson(projectPath, directory) {
103
- // setup tsconfig.json
104
- logger.debug(`Creating tsconfig.json in ${projectPath}`);
105
- const tsconfig = {
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: 'node',
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
- outDir: 'dist',
115
- rootDir: directory,
509
+ forceConsistentCasingInFileNames: true,
510
+ resolveJsonModule: true,
511
+ declaration: true,
512
+ declarationMap: true,
513
+ sourceMap: true,
116
514
  },
117
- include: [`${directory}/**/*.ts`],
118
- exclude: ['node_modules', 'dist', '.dexto'],
515
+ include: ['src/**/*', 'tools/**/*', 'blob-store/**/*', 'compression/**/*', 'plugins/**/*'],
516
+ exclude: ['node_modules', 'dist'],
119
517
  };
120
- await fs.writeJSON(path.join(projectPath, 'tsconfig.json'), tsconfig, { spaces: 4 });
121
- logger.debug(`Successfully created tsconfig.json in ${projectPath}`);
122
- }
123
- /** Adds notes for users to get started with their new initialized Dexto project */
124
- export async function postCreateDexto(projectPath, directory) {
125
- const nextSteps = [
126
- `1. Go to the project directory: ${chalk.cyan(`cd ${projectPath}`)}`,
127
- `2. Run the example: ${chalk.cyan(`npm run dev`)}`,
128
- `3. Add/update your API key(s) in ${chalk.cyan('.env')}`,
129
- `4. Check out the agent configuration file ${chalk.cyan(path.join(directory, 'dexto', 'agents', 'default-agent.yml'))}`,
130
- `5. Try out different LLMs and MCP servers in the default-agent.yml file`,
131
- `6. Run dexto in your project directory to start the interactive CLI with default-agent.yml file`,
132
- `7. Read more about Dexto: ${chalk.cyan('https://docs.dexto.ai')}`,
133
- ].join('\n');
134
- p.note(nextSteps, chalk.yellow('Next steps:'));
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
  }