dexto 1.6.15 → 1.6.16

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.
@@ -1,3 +1,4 @@
1
+ import type { ToolFactoryEntry } from '@dexto/agent-config';
1
2
  import type { Command } from 'commander';
2
3
  type ScaffoldEntryStatus = 'created' | 'existing';
3
4
  type RegistryUpdateStatus = 'created' | 'existing' | 'updated';
@@ -79,6 +80,11 @@ export interface InitCommandRegisterContext {
79
80
  type InitAgentCommandOptions = {
80
81
  subagent?: boolean;
81
82
  primary?: boolean;
83
+ displayName?: string;
84
+ description?: string;
85
+ systemPrompt?: string;
86
+ greeting?: string;
87
+ tools?: ToolFactoryEntry[];
82
88
  };
83
89
  export declare function createWorkspaceScaffold(workspaceRoot?: string): Promise<WorkspaceScaffoldResult>;
84
90
  export declare function createWorkspaceAgentScaffold(agentIdInput: string, options?: InitAgentCommandOptions, workspaceRoot?: string): Promise<WorkspaceAgentScaffoldResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
@@ -1,17 +1,21 @@
1
1
  import * as p from '@clack/prompts';
2
- import { deriveDisplayName, findProjectRegistryPath as findSharedProjectRegistryPath, getPrimaryApiKeyEnvVar, getProjectRegistryPath as getCanonicalProjectRegistryPath, ProjectRegistrySchema, readProjectRegistry as readSharedProjectRegistry, writeConfigFile, } from '@dexto/agent-management';
2
+ import { createDextoAgentFromConfig, deriveDisplayName, findProjectRegistryPath as findSharedProjectRegistryPath, getPrimaryApiKeyEnvVar, getProjectRegistryPath as getCanonicalProjectRegistryPath, ProjectRegistrySchema, readProjectRegistry as readSharedProjectRegistry, writeConfigFile, } from '@dexto/agent-management';
3
3
  import chalk from 'chalk';
4
+ import { spawn } from 'node:child_process';
4
5
  import { promises as fs } from 'node:fs';
6
+ import os from 'node:os';
5
7
  import path from 'node:path';
8
+ import { z } from 'zod';
6
9
  import { ExitSignal, safeExit, withAnalytics } from '../../analytics/wrapper.js';
10
+ import { getEffectiveLLMConfig } from '../../config/effective-llm.js';
7
11
  import { getDeployConfigPath, isWorkspaceDeployAgent, loadDeployConfig } from './deploy/config.js';
8
12
  import { discoverPrimaryWorkspaceAgent } from './deploy/entry-agent.js';
9
- import { selectOrExit, textOrExit } from '../utils/prompt-helpers.js';
13
+ import { confirmOrExit, multiselectOrExit, selectOrExit, textOrExit, } from '../utils/prompt-helpers.js';
14
+ import { ensureImageImporterConfigured } from '../utils/image-importer.js';
10
15
  const AGENTS_FILENAME = 'AGENTS.md';
11
16
  const WORKSPACE_DIRECTORIES = ['agents', 'skills'];
12
17
  const DEFAULT_AGENT_PROVIDER = 'openai';
13
18
  const DEFAULT_AGENT_MODEL = 'gpt-5.3-codex';
14
- const DEFAULT_AGENT_VERSION = '0.1.0';
15
19
  const DEFAULT_AGENTS_MD = `<!-- dexto-workspace -->
16
20
 
17
21
  # Dexto Workspace
@@ -27,7 +31,99 @@ This workspace can define project-specific agents and skills.
27
31
  - If no workspace agent is defined, Dexto uses your global default agent locally
28
32
  - Cloud deploys without a workspace agent use the managed cloud default agent
29
33
  `;
34
+ const CORE_AGENT_TOOL_ENTRIES = [
35
+ {
36
+ type: 'builtin-tools',
37
+ enabledTools: ['ask_user', 'invoke_skill', 'sleep'],
38
+ },
39
+ ];
40
+ const ALWAYS_ENABLED_AGENT_TOOL_ENTRIES = [
41
+ { type: 'creator-tools' },
42
+ { type: 'agent-spawner' },
43
+ ];
44
+ const AGENT_TOOL_BUNDLES = [
45
+ {
46
+ id: 'workspace',
47
+ label: 'Filesystem & Terminal',
48
+ hint: 'Read files and run commands in the workspace',
49
+ entries: [{ type: 'filesystem-tools' }, { type: 'process-tools' }],
50
+ },
51
+ {
52
+ id: 'research',
53
+ label: 'Research and web',
54
+ hint: 'Search the web, fetch URLs, and gather outside context',
55
+ entries: [
56
+ {
57
+ type: 'builtin-tools',
58
+ enabledTools: ['code_search', 'http_request', 'web_search'],
59
+ },
60
+ ],
61
+ },
62
+ {
63
+ id: 'planning',
64
+ label: 'Planning and tasks',
65
+ hint: 'Track todos and keep structured plans',
66
+ entries: [{ type: 'todo-tools' }, { type: 'plan-tools' }],
67
+ },
68
+ {
69
+ id: 'memory',
70
+ label: 'Memory and history',
71
+ hint: 'Search conversation history, logs, and stored memories',
72
+ entries: [{ type: 'lifecycle-tools' }],
73
+ },
74
+ {
75
+ id: 'automation',
76
+ label: 'Automation',
77
+ hint: 'Schedule recurring jobs and proactive work',
78
+ entries: [{ type: 'scheduler-tools' }],
79
+ },
80
+ ];
81
+ const DEFAULT_AGENT_TOOL_BUNDLE_IDS = ['workspace', 'planning'];
30
82
  const ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
83
+ const PROMPT_GENERATOR_AGENT_ID = 'init-agent-prompt-generator';
84
+ const GeneratedSystemPromptPayloadSchema = z
85
+ .object({
86
+ systemPrompt: z.string().trim().min(1),
87
+ })
88
+ .strict();
89
+ const AGENT_PROMPT_GENERATOR_SYSTEM_PROMPT = [
90
+ 'You design production-grade system prompts for Dexto agents.',
91
+ 'Your output will be written directly into agent YAML.',
92
+ '',
93
+ 'Return only valid JSON with this exact shape:',
94
+ '{"systemPrompt":"..."}',
95
+ '',
96
+ 'Prompt requirements:',
97
+ '- Start with "You are <agent name>..."',
98
+ '- Turn the role description into a strong, practical operating prompt',
99
+ '- Keep it general enough to work across different workspaces',
100
+ '- Focus on responsibilities, operating principles, communication style, and constraints',
101
+ '- Instruct the agent to understand the current workspace and context before acting',
102
+ '- Tell the agent to surface risks, assumptions, and follow-up work when relevant',
103
+ '- Mention tools abstractly instead of naming specific tool ids unless explicitly requested',
104
+ '- If the agent is a subagent, include delegation guidance for working on behalf of a parent agent',
105
+ '- Do not include markdown code fences or extra wrapper text',
106
+ ].join('\n');
107
+ function buildInteractiveAgentIdentity(nameInput) {
108
+ const trimmed = nameInput.trim();
109
+ if (!trimmed) {
110
+ throw new Error('Agent name is required.');
111
+ }
112
+ const agentId = trimmed
113
+ .toLowerCase()
114
+ .replace(/[^a-z0-9]+/g, '-')
115
+ .replace(/^-+|-+$/g, '');
116
+ if (!agentId) {
117
+ throw new Error('Agent name must include letters or numbers.');
118
+ }
119
+ return {
120
+ agentId: normalizeScaffoldId(agentId, 'agent'),
121
+ displayName: /[\sA-Z]/.test(trimmed) ? trimmed : deriveDisplayName(agentId),
122
+ };
123
+ }
124
+ function getAgentDisplayName(agentId, options) {
125
+ return options.displayName?.trim() || deriveDisplayName(agentId);
126
+ }
31
127
  function isSubagentEntry(entry) {
32
128
  return (entry.tags?.includes('subagent') ?? false) || Boolean(entry.parentAgentId);
33
129
  }
@@ -118,6 +214,9 @@ async function loadInitialAgentLlmConfig() {
118
214
  };
119
215
  }
120
216
  function buildAgentDescription(agentId, options) {
217
+ if (options.description?.trim()) {
218
+ return options.description.trim();
219
+ }
121
220
  if (options.subagent) {
122
221
  return `Workspace sub-agent '${agentId}' for delegated tasks.`;
123
222
  }
@@ -126,107 +225,463 @@ function buildAgentDescription(agentId, options) {
126
225
  }
127
226
  return `Workspace agent '${agentId}' for this project.`;
128
227
  }
129
- async function buildAgentConfig(agentId, options) {
130
- const llmConfig = await loadInitialAgentLlmConfig();
131
- const displayName = deriveDisplayName(agentId);
132
- const description = buildAgentDescription(agentId, options);
133
- const llm = {
134
- provider: llmConfig.provider,
135
- model: llmConfig.model,
136
- apiKey: llmConfig.apiKey,
137
- };
138
- return {
139
- image: '@dexto/image-local',
140
- agentId,
141
- agentCard: {
142
- name: displayName,
143
- description,
144
- url: `https://example.com/agents/${agentId}`,
145
- version: DEFAULT_AGENT_VERSION,
146
- },
147
- systemPrompt: options.subagent
228
+ function buildDefaultGeneratedPrompt(displayName, options) {
229
+ const roleLabel = options.subagent ? 'specialized workspace subagent' : 'workspace agent';
230
+ return [
231
+ `You are ${displayName}, a ${roleLabel}.`,
232
+ '',
233
+ 'Your role and focus:',
234
+ '- Replace this section with the responsibilities you want this agent to own.',
235
+ '',
236
+ 'Operating principles:',
237
+ '- Read the relevant files and current state before taking action.',
238
+ '- Keep responses concrete, direct, and grounded in the workspace.',
239
+ '- Make the smallest correct change that moves the task forward.',
240
+ '- Call out assumptions, risks, and follow-up work clearly.',
241
+ ...(options.subagent
148
242
  ? [
149
- `You are ${displayName}, a specialized sub-agent for this workspace.`,
150
- '',
151
- 'Complete delegated tasks efficiently and concisely.',
152
- 'Read the relevant files before responding.',
153
- 'Return a clear result to the parent agent with concrete findings or next steps.',
154
- ].join('\n')
155
- : [
156
- `You are ${displayName}, the workspace agent for this project.`,
157
243
  '',
158
- 'Help the user understand, edit, run, and deploy the files in this workspace.',
159
- 'Read relevant files before making changes.',
160
- 'Keep changes focused and explain what changed.',
161
- ].join('\n'),
162
- greeting: options.subagent
163
- ? `Ready to help as ${displayName}.`
164
- : 'Ready to work in this workspace.',
165
- llm,
166
- permissions: {
167
- mode: 'manual',
168
- allowedToolsStorage: 'storage',
169
- },
170
- };
244
+ 'Delegation guidance:',
245
+ '- Complete delegated work efficiently and return a crisp result to the parent agent.',
246
+ ]
247
+ : []),
248
+ ].join('\n');
171
249
  }
172
- function buildRegistryEntry(agentId, options) {
173
- const description = buildAgentDescription(agentId, options);
250
+ function buildScaffoldSystemPrompt(displayName, options) {
251
+ if (options.subagent) {
252
+ return [
253
+ `You are ${displayName}, a specialized sub-agent for this workspace.`,
254
+ '',
255
+ 'Complete delegated tasks efficiently and concisely.',
256
+ 'Read the relevant files before responding.',
257
+ 'Return a clear result to the parent agent with concrete findings or next steps.',
258
+ ].join('\n');
259
+ }
260
+ return [
261
+ `You are ${displayName}, the workspace agent for this project.`,
262
+ '',
263
+ 'Help the user understand, edit, run, and deploy the files in this workspace.',
264
+ 'Read relevant files before making changes.',
265
+ 'Keep changes focused and explain what changed.',
266
+ ].join('\n');
267
+ }
268
+ function buildSystemPromptConfig(systemPrompt) {
174
269
  return {
175
- id: agentId,
176
- name: deriveDisplayName(agentId),
177
- description,
178
- configPath: `./${agentId}/${agentId}.yml`,
179
- ...(options.subagent ? { tags: ['subagent'] } : {}),
270
+ contributors: [
271
+ {
272
+ id: 'primary',
273
+ type: 'static',
274
+ priority: 0,
275
+ content: systemPrompt,
276
+ },
277
+ {
278
+ id: 'date',
279
+ type: 'dynamic',
280
+ priority: 10,
281
+ source: 'date',
282
+ },
283
+ {
284
+ id: 'env',
285
+ type: 'dynamic',
286
+ priority: 15,
287
+ source: 'env',
288
+ },
289
+ ],
180
290
  };
181
291
  }
182
- function addSubagentTag(entry) {
183
- const tags = new Set(entry.tags ?? []);
184
- tags.add('subagent');
292
+ function extractJsonObjectFromResponse(content) {
293
+ const trimmed = content.trim();
294
+ if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
295
+ return trimmed;
296
+ }
297
+ const fencedMatch = trimmed.match(/```(?:json)?\s*([\s\S]*?)```/i);
298
+ if (fencedMatch?.[1]) {
299
+ return fencedMatch[1].trim();
300
+ }
301
+ const firstBrace = trimmed.indexOf('{');
302
+ const lastBrace = trimmed.lastIndexOf('}');
303
+ if (firstBrace >= 0 && lastBrace > firstBrace) {
304
+ return trimmed.slice(firstBrace, lastBrace + 1);
305
+ }
306
+ throw new Error('Prompt generator did not return valid JSON.');
307
+ }
308
+ function parseGeneratedSystemPromptResponse(content) {
309
+ const parsed = JSON.parse(extractJsonObjectFromResponse(content));
310
+ return GeneratedSystemPromptPayloadSchema.parse(parsed).systemPrompt;
311
+ }
312
+ function buildPromptGenerationRequest(displayName, roleDescription, options) {
313
+ return [
314
+ 'Generate a Dexto system prompt from this brief.',
315
+ '',
316
+ `Agent name: ${displayName}`,
317
+ `Agent type: ${options.subagent ? 'workspace subagent' : 'workspace agent'}`,
318
+ `Role description: ${normalizeInteractiveDescription(roleDescription)}`,
319
+ '',
320
+ 'Additional guidance:',
321
+ '- Make the prompt concrete and opinionated, not generic filler',
322
+ '- Prefer short sections and useful bullet points over long prose',
323
+ '- Assume tool access may vary by workspace, so keep tool guidance capability-based',
324
+ '- Avoid references to specific repositories, companies, or file names',
325
+ '',
326
+ 'Return JSON only.',
327
+ ].join('\n');
328
+ }
329
+ async function generateAgentSystemPromptFromDescription(displayName, roleDescription, options) {
330
+ await ensureImageImporterConfigured();
331
+ const effectiveLLM = await getEffectiveLLMConfig();
332
+ if (!effectiveLLM) {
333
+ throw new Error('No active LLM configuration is available for prompt generation. Configure one with `dexto setup` first.');
334
+ }
335
+ const spinner = p.spinner();
336
+ spinner.start('Generating system prompt...');
337
+ const generatorAgent = await createDextoAgentFromConfig({
338
+ agentIdOverride: PROMPT_GENERATOR_AGENT_ID,
339
+ enrichOptions: {
340
+ isInteractiveCli: false,
341
+ skipPluginDiscovery: true,
342
+ },
343
+ config: {
344
+ image: '@dexto/image-local',
345
+ systemPrompt: buildSystemPromptConfig(AGENT_PROMPT_GENERATOR_SYSTEM_PROMPT),
346
+ llm: {
347
+ provider: effectiveLLM.provider,
348
+ model: effectiveLLM.model,
349
+ ...(effectiveLLM.apiKey ? { apiKey: effectiveLLM.apiKey } : {}),
350
+ ...(effectiveLLM.baseURL ? { baseURL: effectiveLLM.baseURL } : {}),
351
+ },
352
+ storage: {
353
+ cache: { type: 'in-memory' },
354
+ database: { type: 'in-memory' },
355
+ blob: { type: 'in-memory' },
356
+ },
357
+ permissions: {
358
+ mode: 'auto-deny',
359
+ allowedToolsStorage: 'memory',
360
+ },
361
+ elicitation: {
362
+ enabled: false,
363
+ },
364
+ tools: [],
365
+ },
366
+ });
367
+ try {
368
+ await generatorAgent.start();
369
+ const session = await generatorAgent.createSession(PROMPT_GENERATOR_AGENT_ID);
370
+ const response = await generatorAgent.generate(buildPromptGenerationRequest(displayName, roleDescription, options), session.id);
371
+ const systemPrompt = parseGeneratedSystemPromptResponse(response.content);
372
+ spinner.stop(chalk.green('Generated system prompt'));
373
+ return systemPrompt;
374
+ }
375
+ catch (error) {
376
+ spinner.stop(chalk.red('Failed to generate system prompt'));
377
+ throw new Error(`Could not generate a system prompt automatically: ${error instanceof Error ? error.message : String(error)}`);
378
+ }
379
+ finally {
380
+ await generatorAgent.stop().catch(() => undefined);
381
+ }
382
+ }
383
+ function encodePromptForTextInput(systemPrompt) {
384
+ return systemPrompt.replace(/\n/g, '\\n');
385
+ }
386
+ function decodePromptFromTextInput(systemPrompt) {
387
+ return systemPrompt.replace(/\\n/g, '\n').trim();
388
+ }
389
+ function normalizeInteractiveDescription(description) {
390
+ const trimmed = description.trim().replace(/\s+/g, ' ');
391
+ if (!trimmed) {
392
+ return trimmed;
393
+ }
394
+ return /[.!?]$/.test(trimmed) ? trimmed : `${trimmed}.`;
395
+ }
396
+ function cloneToolEntry(entry) {
397
+ const maybeEnabledTools = entry.enabledTools;
185
398
  return {
186
399
  ...entry,
187
- tags: Array.from(tags).sort(),
400
+ ...(Array.isArray(maybeEnabledTools)
401
+ ? {
402
+ enabledTools: maybeEnabledTools.filter((tool) => typeof tool === 'string'),
403
+ }
404
+ : {}),
188
405
  };
189
406
  }
190
- function validateInitAgentOptions(options) {
191
- if (options.primary && options.subagent) {
192
- throw new Error('A sub-agent cannot also be the primary workspace agent.');
407
+ function mergeToolEntries(entries) {
408
+ const merged = new Map();
409
+ for (const entry of entries) {
410
+ const existing = merged.get(entry.type);
411
+ if (!existing) {
412
+ merged.set(entry.type, cloneToolEntry(entry));
413
+ continue;
414
+ }
415
+ const existingEnabledTools = existing.enabledTools;
416
+ const nextEnabledTools = entry.enabledTools;
417
+ if (Array.isArray(existingEnabledTools) && Array.isArray(nextEnabledTools)) {
418
+ merged.set(entry.type, {
419
+ ...existing,
420
+ enabledTools: Array.from(new Set([
421
+ ...existingEnabledTools.filter((tool) => typeof tool === 'string'),
422
+ ...nextEnabledTools.filter((tool) => typeof tool === 'string'),
423
+ ])),
424
+ });
425
+ continue;
426
+ }
427
+ if (!Array.isArray(existingEnabledTools) && Array.isArray(nextEnabledTools)) {
428
+ continue;
429
+ }
430
+ if (Array.isArray(existingEnabledTools) && !Array.isArray(nextEnabledTools)) {
431
+ merged.set(entry.type, cloneToolEntry(entry));
432
+ continue;
433
+ }
434
+ merged.set(entry.type, cloneToolEntry(entry));
435
+ }
436
+ return Array.from(merged.values());
437
+ }
438
+ function buildToolConfigFromBundleIds(bundleIds) {
439
+ const selectedBundleEntries = bundleIds.flatMap((bundleId) => {
440
+ const bundle = AGENT_TOOL_BUNDLES.find((entry) => entry.id === bundleId);
441
+ return bundle?.entries ?? [];
442
+ });
443
+ return mergeToolEntries([
444
+ ...CORE_AGENT_TOOL_ENTRIES,
445
+ ...ALWAYS_ENABLED_AGENT_TOOL_ENTRIES,
446
+ ...selectedBundleEntries,
447
+ ]);
448
+ }
449
+ function formatBundleSelection(bundleIds) {
450
+ if (bundleIds.length === 0) {
451
+ return 'Core utilities only';
452
+ }
453
+ return bundleIds
454
+ .map((bundleId) => AGENT_TOOL_BUNDLES.find((bundle) => bundle.id === bundleId)?.label ?? bundleId)
455
+ .join(', ');
456
+ }
457
+ function renderPromptPreview(systemPrompt) {
458
+ console.log(`\n${chalk.cyan.bold('System Prompt Preview')}`);
459
+ console.log(chalk.dim('Review the full prompt before continuing.\n'));
460
+ console.log(systemPrompt);
461
+ console.log();
462
+ }
463
+ function getPreferredEditorCommand() {
464
+ const envEditor = process.env.VISUAL?.trim() || process.env.EDITOR?.trim();
465
+ if (envEditor) {
466
+ return envEditor;
193
467
  }
468
+ return process.platform === 'win32' ? 'notepad' : 'vi';
194
469
  }
195
- async function promptForAgentId(kind) {
196
- const placeholder = kind === 'subagent'
197
- ? 'explore-agent'
198
- : kind === 'primary'
199
- ? 'review-agent'
200
- : 'helper-agent';
201
- return await textOrExit({
202
- message: 'Agent id',
203
- placeholder,
470
+ async function openFileInEditor(editorCommand, filePath) {
471
+ await new Promise((resolve, reject) => {
472
+ const child = spawn(editorCommand, [filePath], {
473
+ stdio: 'inherit',
474
+ shell: true,
475
+ });
476
+ child.once('error', reject);
477
+ child.once('exit', (code) => {
478
+ if (code === 0) {
479
+ resolve();
480
+ return;
481
+ }
482
+ reject(new Error(`Editor exited with code ${code ?? 'unknown'}.`));
483
+ });
484
+ });
485
+ }
486
+ async function editSystemPromptInEditor(displayName, options, initialPrompt) {
487
+ const editorCommand = getPreferredEditorCommand();
488
+ const initialContent = initialPrompt ?? buildDefaultGeneratedPrompt(displayName, options);
489
+ const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'dexto-agent-prompt-'));
490
+ const promptPath = path.join(tempDir, 'system-prompt.md');
491
+ try {
492
+ await fs.writeFile(promptPath, `${initialContent}\n`, 'utf8');
493
+ p.log.info(`Opening ${chalk.cyan(editorCommand)} for prompt editing. Save and close the editor to continue.`);
494
+ while (true) {
495
+ await openFileInEditor(editorCommand, promptPath);
496
+ const editedPrompt = (await fs.readFile(promptPath, 'utf8')).trim();
497
+ if (editedPrompt) {
498
+ return editedPrompt;
499
+ }
500
+ p.log.warn('System prompt was empty. Reopening the editor.');
501
+ }
502
+ }
503
+ finally {
504
+ await fs.rm(tempDir, { recursive: true, force: true }).catch(() => undefined);
505
+ }
506
+ }
507
+ async function promptForAgentName(initialValue) {
508
+ const rawName = await textOrExit({
509
+ message: 'Agent name',
510
+ ...(initialValue ? { initialValue } : {}),
511
+ placeholder: 'Review Agent',
204
512
  validate(value) {
205
513
  try {
206
- normalizeScaffoldId(value, 'agent');
514
+ buildInteractiveAgentIdentity(value);
207
515
  return undefined;
208
516
  }
209
517
  catch (error) {
210
- return error instanceof Error ? error.message : 'Invalid agent id';
518
+ return error instanceof Error ? error.message : 'Invalid agent name';
211
519
  }
212
520
  },
213
521
  }, 'Agent initialization cancelled');
522
+ return buildInteractiveAgentIdentity(rawName);
214
523
  }
215
- async function resolveInitAgentInput(agentIdInput, options, workspaceRoot) {
216
- validateInitAgentOptions(options);
217
- if (agentIdInput) {
524
+ async function promptForAvailableAgentName(workspaceRoot) {
525
+ const resolvedWorkspaceRoot = path.resolve(workspaceRoot);
526
+ let initialValue;
527
+ while (true) {
528
+ const identity = await promptForAgentName(initialValue);
529
+ const registryState = await loadWorkspaceProjectRegistry(resolvedWorkspaceRoot);
530
+ const existingEntry = getWorkspaceAgentEntry(registryState.registry, identity.agentId);
531
+ if (!existingEntry) {
532
+ return identity;
533
+ }
534
+ p.log.warn(`Agent '${identity.agentId}' already exists in ${path.relative(resolvedWorkspaceRoot, registryState.path)}. Choose a different name or run \`dexto init agent ${identity.agentId}\` to update the existing agent.`);
535
+ initialValue = identity.displayName;
536
+ }
537
+ }
538
+ async function promptForCustomSystemPrompt(displayName, options, initialPrompt) {
539
+ try {
540
+ return await editSystemPromptInEditor(displayName, options, initialPrompt);
541
+ }
542
+ catch (error) {
543
+ p.log.warn(`Could not open an editor cleanly. Falling back to inline prompt editing. ${error instanceof Error ? error.message : String(error)}`);
544
+ const rawPrompt = await textOrExit({
545
+ message: 'System prompt (use \\n for line breaks)',
546
+ initialValue: encodePromptForTextInput(initialPrompt ?? buildDefaultGeneratedPrompt(displayName, options)),
547
+ placeholder: encodePromptForTextInput(buildDefaultGeneratedPrompt(displayName, options)),
548
+ validate(value) {
549
+ const decoded = decodePromptFromTextInput(value);
550
+ return decoded ? undefined : 'System prompt is required';
551
+ },
552
+ }, 'Agent initialization cancelled');
553
+ return decodePromptFromTextInput(rawPrompt);
554
+ }
555
+ }
556
+ async function promptForReviewedCustomSystemPrompt(displayName, options, initialPrompt) {
557
+ let customPrompt = initialPrompt ?? '';
558
+ while (true) {
559
+ customPrompt = await promptForCustomSystemPrompt(displayName, options, customPrompt);
560
+ renderPromptPreview(customPrompt);
561
+ const confirmed = await confirmOrExit({
562
+ message: 'Use this system prompt?',
563
+ initialValue: true,
564
+ }, 'Agent initialization cancelled');
565
+ if (confirmed) {
566
+ return customPrompt;
567
+ }
568
+ }
569
+ }
570
+ async function promptForAgentSystemPrompt(displayName, options) {
571
+ const effectiveLLM = await getEffectiveLLMConfig();
572
+ if (!effectiveLLM) {
573
+ p.log.info('No active LLM configuration found. Opening the prompt editor instead. Run `dexto setup` to enable automatic prompt generation.');
218
574
  return {
219
- agentId: normalizeScaffoldId(agentIdInput, 'agent'),
220
- options,
575
+ mode: 'custom',
576
+ systemPrompt: await promptForReviewedCustomSystemPrompt(displayName, options),
577
+ description: null,
221
578
  };
222
579
  }
223
- if (options.subagent || options.primary) {
224
- const kind = options.subagent ? 'subagent' : 'primary';
580
+ const promptMode = await selectOrExit({
581
+ message: 'How do you want to create the system prompt?',
582
+ initialValue: 'generate',
583
+ options: [
584
+ {
585
+ value: 'generate',
586
+ label: 'Generate from description',
587
+ hint: 'Start from a short role description and review the full prompt',
588
+ },
589
+ {
590
+ value: 'custom',
591
+ label: 'Write custom prompt',
592
+ hint: 'Enter your own prompt text directly',
593
+ },
594
+ ],
595
+ }, 'Agent initialization cancelled');
596
+ if (promptMode === 'custom') {
225
597
  return {
226
- agentId: normalizeScaffoldId(await promptForAgentId(kind), 'agent'),
227
- options,
598
+ mode: 'custom',
599
+ systemPrompt: await promptForReviewedCustomSystemPrompt(displayName, options),
600
+ description: null,
228
601
  };
229
602
  }
603
+ let roleDescription = await textOrExit({
604
+ message: 'Describe this agent’s role',
605
+ placeholder: 'Reviews code changes, finds risks, and suggests focused fixes.',
606
+ validate(value) {
607
+ return value.trim() ? undefined : 'Role description is required';
608
+ },
609
+ }, 'Agent initialization cancelled');
610
+ let systemPrompt = await generateAgentSystemPromptFromDescription(displayName, roleDescription, options);
611
+ while (true) {
612
+ renderPromptPreview(systemPrompt);
613
+ const action = await selectOrExit({
614
+ message: 'What do you want to do with this prompt?',
615
+ initialValue: 'continue',
616
+ options: [
617
+ {
618
+ value: 'continue',
619
+ label: 'Continue',
620
+ hint: 'Use this prompt as-is',
621
+ },
622
+ {
623
+ value: 'edit',
624
+ label: 'Edit prompt',
625
+ hint: 'Make direct changes to the generated prompt',
626
+ },
627
+ {
628
+ value: 'regenerate',
629
+ label: 'Regenerate',
630
+ hint: 'Update the role description and rebuild the prompt',
631
+ },
632
+ ],
633
+ }, 'Agent initialization cancelled');
634
+ if (action === 'continue') {
635
+ return {
636
+ mode: 'generate',
637
+ systemPrompt,
638
+ description: normalizeInteractiveDescription(roleDescription),
639
+ };
640
+ }
641
+ if (action === 'edit') {
642
+ systemPrompt = await promptForCustomSystemPrompt(displayName, options, systemPrompt);
643
+ continue;
644
+ }
645
+ roleDescription = await textOrExit({
646
+ message: 'Describe this agent’s role',
647
+ initialValue: roleDescription,
648
+ validate(value) {
649
+ return value.trim() ? undefined : 'Role description is required';
650
+ },
651
+ }, 'Agent initialization cancelled');
652
+ systemPrompt = await generateAgentSystemPromptFromDescription(displayName, roleDescription, options);
653
+ }
654
+ }
655
+ async function promptForAgentToolBundles() {
656
+ return await multiselectOrExit({
657
+ message: 'Select tool bundles (agent creation is enabled by default)',
658
+ initialValues: DEFAULT_AGENT_TOOL_BUNDLE_IDS,
659
+ options: AGENT_TOOL_BUNDLES.map((bundle) => ({
660
+ value: bundle.id,
661
+ label: bundle.label,
662
+ hint: bundle.hint,
663
+ })),
664
+ }, 'Agent initialization cancelled');
665
+ }
666
+ async function describePlannedAgentRole(options, workspaceRoot) {
667
+ const registryState = await loadWorkspaceProjectRegistry(path.resolve(workspaceRoot));
668
+ const currentPrimaryAgentId = getEffectiveWorkspacePrimaryAgentId(registryState.registry);
669
+ if (options.subagent) {
670
+ return currentPrimaryAgentId
671
+ ? `Subagent (will link to ${currentPrimaryAgentId})`
672
+ : 'Subagent (no primary agent available yet)';
673
+ }
674
+ if (options.primary) {
675
+ return currentPrimaryAgentId
676
+ ? `Primary agent (replaces ${currentPrimaryAgentId})`
677
+ : 'Primary agent';
678
+ }
679
+ return currentPrimaryAgentId ? 'Additional agent' : 'Primary agent (first workspace agent)';
680
+ }
681
+ async function resolveInteractiveAgentRoleOptions(options, workspaceRoot) {
682
+ if (options.subagent || options.primary) {
683
+ return options;
684
+ }
230
685
  const registryState = await loadWorkspaceProjectRegistry(path.resolve(workspaceRoot));
231
686
  const currentPrimaryAgentId = getEffectiveWorkspacePrimaryAgentId(registryState.registry);
232
687
  const kind = await selectOrExit({
@@ -252,10 +707,116 @@ async function resolveInitAgentInput(agentIdInput, options, workspaceRoot) {
252
707
  },
253
708
  ],
254
709
  }, 'Agent initialization cancelled');
255
- const resolvedOptions = kind === 'primary' ? { primary: true } : kind === 'subagent' ? { subagent: true } : {};
256
710
  return {
257
- agentId: normalizeScaffoldId(await promptForAgentId(kind), 'agent'),
258
- options: resolvedOptions,
711
+ ...options,
712
+ ...(kind === 'primary' ? { primary: true } : {}),
713
+ ...(kind === 'subagent' ? { subagent: true } : {}),
714
+ };
715
+ }
716
+ async function buildAgentConfig(agentId, options) {
717
+ const llmConfig = await loadInitialAgentLlmConfig();
718
+ const displayName = getAgentDisplayName(agentId, options);
719
+ const systemPrompt = options.systemPrompt ?? buildScaffoldSystemPrompt(displayName, options);
720
+ const usesAskUser = options.tools === undefined ||
721
+ options.tools.some((entry) => {
722
+ if (entry.type !== 'builtin-tools' || entry.enabled === false) {
723
+ return false;
724
+ }
725
+ const maybeEnabledTools = entry.enabledTools;
726
+ return (!Array.isArray(maybeEnabledTools) ||
727
+ maybeEnabledTools.some((tool) => tool === 'ask_user'));
728
+ });
729
+ const llm = {
730
+ provider: llmConfig.provider,
731
+ model: llmConfig.model,
732
+ apiKey: llmConfig.apiKey,
733
+ };
734
+ return {
735
+ image: '@dexto/image-local',
736
+ systemPrompt: buildSystemPromptConfig(systemPrompt),
737
+ greeting: options.greeting ??
738
+ (options.subagent
739
+ ? `Ready to help as ${displayName}.`
740
+ : 'Ready to work in this workspace.'),
741
+ llm,
742
+ ...(options.tools ? { tools: options.tools } : {}),
743
+ permissions: {
744
+ mode: 'manual',
745
+ allowedToolsStorage: 'storage',
746
+ },
747
+ ...(usesAskUser
748
+ ? {
749
+ elicitation: {
750
+ enabled: true,
751
+ },
752
+ }
753
+ : {}),
754
+ };
755
+ }
756
+ function buildRegistryEntry(agentId, options) {
757
+ const description = buildAgentDescription(agentId, options);
758
+ return {
759
+ id: agentId,
760
+ name: getAgentDisplayName(agentId, options),
761
+ description,
762
+ configPath: `./${agentId}/${agentId}.yml`,
763
+ ...(options.subagent ? { tags: ['subagent'] } : {}),
764
+ };
765
+ }
766
+ function addSubagentTag(entry) {
767
+ const tags = new Set(entry.tags ?? []);
768
+ tags.add('subagent');
769
+ return {
770
+ ...entry,
771
+ tags: Array.from(tags).sort(),
772
+ };
773
+ }
774
+ function validateInitAgentOptions(options) {
775
+ if (options.primary && options.subagent) {
776
+ throw new Error('A sub-agent cannot also be the primary workspace agent.');
777
+ }
778
+ }
779
+ async function resolveInitAgentInput(agentIdInput, options, workspaceRoot) {
780
+ validateInitAgentOptions(options);
781
+ if (agentIdInput) {
782
+ return {
783
+ agentId: normalizeScaffoldId(agentIdInput, 'agent'),
784
+ options,
785
+ };
786
+ }
787
+ const resolvedOptions = await resolveInteractiveAgentRoleOptions(options, workspaceRoot);
788
+ const identity = await promptForAvailableAgentName(workspaceRoot);
789
+ const promptResult = await promptForAgentSystemPrompt(identity.displayName, resolvedOptions);
790
+ const bundleIds = await promptForAgentToolBundles();
791
+ const roleSummary = await describePlannedAgentRole(resolvedOptions, workspaceRoot);
792
+ const selectedTools = buildToolConfigFromBundleIds(bundleIds);
793
+ p.note([
794
+ `${chalk.cyan('Name:')} ${chalk.bold(identity.displayName)}`,
795
+ `${chalk.cyan('Id:')} ${chalk.dim(identity.agentId)}`,
796
+ `${chalk.cyan('Workspace role:')} ${roleSummary}`,
797
+ `${chalk.cyan('System prompt:')} ${promptResult.mode === 'generate' ? 'Generated from description' : 'Custom'}`,
798
+ `${chalk.cyan('Tool bundles:')} ${formatBundleSelection(bundleIds)}`,
799
+ `${chalk.cyan('Core utilities:')} ask_user, invoke_skill, sleep`,
800
+ `${chalk.cyan('Agent creation:')} enabled by default`,
801
+ ].join('\n'), 'Agent Summary');
802
+ const confirmed = await confirmOrExit({
803
+ message: 'Create this agent?',
804
+ initialValue: true,
805
+ }, 'Agent initialization cancelled');
806
+ if (!confirmed) {
807
+ return null;
808
+ }
809
+ return {
810
+ agentId: identity.agentId,
811
+ options: {
812
+ ...resolvedOptions,
813
+ displayName: identity.displayName,
814
+ description: promptResult.description ??
815
+ buildAgentDescription(identity.agentId, resolvedOptions),
816
+ systemPrompt: promptResult.systemPrompt,
817
+ greeting: `Ready to help as ${identity.displayName}.`,
818
+ tools: selectedTools,
819
+ },
259
820
  };
260
821
  }
261
822
  function buildSkillTemplate(skillId) {
@@ -684,6 +1245,10 @@ export async function handleInitCommand(workspaceRoot = process.cwd()) {
684
1245
  export async function handleInitAgentCommand(agentIdInput, options = {}, workspaceRoot = process.cwd()) {
685
1246
  p.intro(chalk.inverse('Dexto Init Agent'));
686
1247
  const resolved = await resolveInitAgentInput(agentIdInput, options, workspaceRoot);
1248
+ if (!resolved) {
1249
+ p.outro(chalk.yellow('Agent initialization cancelled.'));
1250
+ return;
1251
+ }
687
1252
  const result = await createWorkspaceAgentScaffold(resolved.agentId, resolved.options, workspaceRoot);
688
1253
  const subagentLinkResult = resolved.options.subagent
689
1254
  ? await linkWorkspaceSubagentToPrimaryAgent(resolved.agentId, workspaceRoot)
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA6DxB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0ClB,CAAC;AAEP,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAClE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AA6JtE;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC9F"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA+DxB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0ClB,CAAC;AAEP,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAClE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAqKtE;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC9F"}
@@ -1,12 +1,15 @@
1
1
  // packages/cli/src/cli/commands/setup.ts
2
+ import { promises as fs } from 'node:fs';
3
+ import path from 'node:path';
2
4
  import chalk from 'chalk';
3
5
  import { z } from 'zod';
4
6
  import open from 'open';
5
7
  import { acceptsAnyModel, CodexAppServerClient, createCodexBaseURL, getDefaultModelForProvider, getCodexAuthModeLabel, getCodexProviderDisplayName, getCuratedModelsForProvider, getReasoningProfile, getSupportedModels, isCodexBaseURL, LLM_PROVIDERS, LLM_REGISTRY, logger, parseCodexBaseURL, isValidProviderModel, supportsCustomModels, requiresApiKey, resolveApiKeyForProvider, } from '@dexto/core';
6
- import { createInitialPreferences, saveGlobalPreferences, loadGlobalPreferences, getGlobalPreferencesPath, updateGlobalPreferences, setActiveModel, isDextoAuthEnabled, loadCustomModels, saveCustomModel, deleteCustomModel, globalPreferencesExist, } from '@dexto/agent-management';
8
+ import { createInitialPreferences, saveGlobalPreferences, loadGlobalPreferences, getGlobalPreferencesPath, updateGlobalPreferences, setActiveModel, isDextoAuthEnabled, loadCustomModels, saveCustomModel, deleteCustomModel, globalPreferencesExist, getDextoGlobalPath, } from '@dexto/agent-management';
7
9
  import { interactiveApiKeySetup, hasApiKeyConfigured } from '../utils/api-key-setup.js';
8
10
  import { selectProvider, getProviderDisplayName, getProviderEnvVar, providerRequiresBaseURL, getDefaultModel, } from '../utils/provider-setup.js';
9
11
  import { setupLocalModels, setupOllamaModels, hasSelectedModel, getModelFromResult, } from '../utils/local-model-setup.js';
12
+ import { executeCommand } from '../utils/self-management.js';
10
13
  import { requiresSetup } from '../utils/setup-utils.js';
11
14
  import { canUseDextoProvider } from '../utils/dexto-setup.js';
12
15
  import { handleAutoLogin } from './auth/login.js';
@@ -69,6 +72,13 @@ const REASONING_VARIANT_HINTS = {
69
72
  max: 'Maximum reasoning within provider limits',
70
73
  xhigh: 'Extra high reasoning',
71
74
  };
75
+ const OPENAI_CODEX_PACKAGE = '@openai/codex';
76
+ const DEXTO_DEPS_PACKAGE_JSON = {
77
+ name: 'dexto-deps',
78
+ version: '1.0.0',
79
+ private: true,
80
+ description: 'Managed dependencies for Dexto',
81
+ };
72
82
  function toReasoningVariantLabel(variant, defaultVariant) {
73
83
  const normalized = variant.toLowerCase();
74
84
  const withKnownCasing = normalized === 'xhigh'
@@ -420,6 +430,104 @@ function getConfiguredProviderDisplayName(provider, baseURL) {
420
430
  function isCodexConfigured(provider, baseURL) {
421
431
  return provider === 'openai-compatible' && isCodexBaseURL(baseURL);
422
432
  }
433
+ async function ensureDextoDepsPackageJson() {
434
+ const depsDir = getDextoGlobalPath('deps');
435
+ await fs.mkdir(depsDir, { recursive: true });
436
+ const packageJsonPath = path.join(depsDir, 'package.json');
437
+ try {
438
+ await fs.access(packageJsonPath);
439
+ }
440
+ catch (error) {
441
+ if (error.code !== 'ENOENT') {
442
+ throw error;
443
+ }
444
+ await fs.writeFile(packageJsonPath, JSON.stringify(DEXTO_DEPS_PACKAGE_JSON, null, 2), 'utf-8');
445
+ }
446
+ return depsDir;
447
+ }
448
+ function isMissingCodexCliError(error) {
449
+ if (!(error instanceof Error)) {
450
+ return false;
451
+ }
452
+ const code = error.code;
453
+ return (error.message.includes('Codex CLI not found on PATH') ||
454
+ error.message.includes('spawn codex ENOENT') ||
455
+ (code === 'ENOENT' && error.message.includes('spawn')));
456
+ }
457
+ function getCodexSetupErrorMessage(error) {
458
+ if (isMissingCodexCliError(error)) {
459
+ return 'Codex CLI not found on PATH. Install Codex to use ChatGPT Login in Dexto.';
460
+ }
461
+ return error instanceof Error ? error.message : String(error);
462
+ }
463
+ async function resolveCodexInstaller() {
464
+ const candidates = [
465
+ {
466
+ command: 'npm',
467
+ args: ['install', OPENAI_CODEX_PACKAGE, '--no-audit', '--no-fund'],
468
+ label: 'npm',
469
+ },
470
+ {
471
+ command: 'pnpm',
472
+ args: ['add', OPENAI_CODEX_PACKAGE],
473
+ label: 'pnpm',
474
+ },
475
+ {
476
+ command: 'bun',
477
+ args: ['add', OPENAI_CODEX_PACKAGE],
478
+ label: 'bun',
479
+ },
480
+ ];
481
+ for (const candidate of candidates) {
482
+ const probe = await executeCommand(candidate.command, ['--version']);
483
+ if (probe.code === 0) {
484
+ return candidate;
485
+ }
486
+ }
487
+ return null;
488
+ }
489
+ function getCodexInstallerFailureMessage(installer, result) {
490
+ const details = `${result.stderr}\n${result.stdout}`
491
+ .split(/\r?\n/)
492
+ .map((line) => line.trim())
493
+ .filter((line) => line.length > 0);
494
+ const lastLine = details.at(-1);
495
+ return lastLine
496
+ ? `Failed to install the OpenAI Codex CLI via ${installer.label}: ${lastLine}`
497
+ : `Failed to install the OpenAI Codex CLI via ${installer.label}.`;
498
+ }
499
+ async function installManagedCodexCli() {
500
+ const depsDir = await ensureDextoDepsPackageJson();
501
+ const installer = await resolveCodexInstaller();
502
+ if (!installer) {
503
+ throw new Error('Could not find npm, pnpm, or bun to install the OpenAI Codex CLI automatically.');
504
+ }
505
+ const result = await executeCommand(installer.command, installer.args, { cwd: depsDir });
506
+ if (result.code !== 0) {
507
+ throw new Error(getCodexInstallerFailureMessage(installer, result));
508
+ }
509
+ }
510
+ async function createCodexClientForSetup() {
511
+ try {
512
+ return await CodexAppServerClient.create();
513
+ }
514
+ catch (error) {
515
+ if (!isMissingCodexCliError(error)) {
516
+ throw error;
517
+ }
518
+ const spinner = p.spinner();
519
+ spinner.start('Installing OpenAI Codex CLI...');
520
+ try {
521
+ await installManagedCodexCli();
522
+ spinner.stop('OpenAI Codex CLI installed');
523
+ }
524
+ catch (installError) {
525
+ spinner.stop('OpenAI Codex CLI installation failed');
526
+ throw installError;
527
+ }
528
+ return await CodexAppServerClient.create();
529
+ }
530
+ }
423
531
  async function ensureCodexChatGPTLogin(client) {
424
532
  const spinner = p.spinner();
425
533
  spinner.start('Starting ChatGPT login with Codex...');
@@ -510,7 +618,7 @@ async function handleCodexProviderSetup(options = {}) {
510
618
  console.log(chalk.cyan('\nChatGPT Login Setup\n'));
511
619
  let client = null;
512
620
  try {
513
- client = await CodexAppServerClient.create();
621
+ client = await createCodexClientForSetup();
514
622
  const account = await ensureCodexChatGPTSession(client);
515
623
  if (!account || account.account?.type !== 'chatgpt') {
516
624
  return abort('Setup cancelled');
@@ -579,7 +687,7 @@ async function handleCodexProviderSetup(options = {}) {
579
687
  return true;
580
688
  }
581
689
  catch (error) {
582
- const errorMessage = error instanceof Error ? error.message : String(error);
690
+ const errorMessage = getCodexSetupErrorMessage(error);
583
691
  p.log.error(`ChatGPT Login setup failed: ${errorMessage}`);
584
692
  return abort('Setup cancelled', 1);
585
693
  }
@@ -601,7 +709,7 @@ async function handleCodexChatGPTLoginRefresh(options = {}) {
601
709
  console.log(chalk.cyan('\nChatGPT Login\n'));
602
710
  let client = null;
603
711
  try {
604
- client = await CodexAppServerClient.create();
712
+ client = await createCodexClientForSetup();
605
713
  const account = await ensureCodexChatGPTSession(client);
606
714
  if (!account || account.account?.type !== 'chatgpt') {
607
715
  return abort('ChatGPT login cancelled');
@@ -610,7 +718,7 @@ async function handleCodexChatGPTLoginRefresh(options = {}) {
610
718
  return true;
611
719
  }
612
720
  catch (error) {
613
- const errorMessage = error instanceof Error ? error.message : String(error);
721
+ const errorMessage = getCodexSetupErrorMessage(error);
614
722
  p.log.error(`ChatGPT Login failed: ${errorMessage}`);
615
723
  return abort('ChatGPT login cancelled', 1);
616
724
  }
@@ -0,0 +1,2 @@
1
+ export declare function ensureImageImporterConfigured(): Promise<void>;
2
+ //# sourceMappingURL=image-importer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-importer.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/image-importer.ts"],"names":[],"mappings":"AAKA,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,IAAI,CAAC,CAOnE"}
@@ -0,0 +1,10 @@
1
+ import { setImageImporter } from '@dexto/agent-config';
2
+ import { importImageModule } from './image-store.js';
3
+ let imageImporterConfigured = false;
4
+ export async function ensureImageImporterConfigured() {
5
+ if (imageImporterConfigured) {
6
+ return;
7
+ }
8
+ setImageImporter((specifier) => importImageModule(specifier));
9
+ imageImporterConfigured = true;
10
+ }
@@ -8,6 +8,7 @@ import * as p from '@clack/prompts';
8
8
  type SelectOptions = Parameters<typeof p.select>[0];
9
9
  type TextOptions = Parameters<typeof p.text>[0];
10
10
  type ConfirmOptions = Parameters<typeof p.confirm>[0];
11
+ type MultiselectOptions = Parameters<typeof p.multiselect>[0];
11
12
  /**
12
13
  * Select prompt that exits on cancel.
13
14
  * Use for linear flows where cancel should abort the entire operation.
@@ -43,5 +44,10 @@ export declare function textOrExit(options: TextOptions, cancelMessage?: string)
43
44
  * }, 'Operation cancelled');
44
45
  */
45
46
  export declare function confirmOrExit(options: ConfirmOptions, cancelMessage?: string): Promise<boolean>;
47
+ /**
48
+ * Multiselect prompt that exits on cancel.
49
+ * Use for linear flows where cancel should abort the entire operation.
50
+ */
51
+ export declare function multiselectOrExit<T extends string>(options: MultiselectOptions, cancelMessage?: string): Promise<T[]>;
46
52
  export {};
47
53
  //# sourceMappingURL=prompt-helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-helpers.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/prompt-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAMpC,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAMtD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,EAC/C,OAAO,EAAE,aAAa,EACtB,aAAa,SAAc,GAC5B,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC5B,OAAO,EAAE,WAAW,EACpB,aAAa,SAAc,GAC5B,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAC/B,OAAO,EAAE,cAAc,EACvB,aAAa,SAAc,GAC5B,OAAO,CAAC,OAAO,CAAC,CAOlB"}
1
+ {"version":3,"file":"prompt-helpers.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/prompt-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAMpC,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACtD,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAM9D;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,EAC/C,OAAO,EAAE,aAAa,EACtB,aAAa,SAAc,GAC5B,OAAO,CAAC,CAAC,CAAC,CAOZ;AAED;;;;;;;;;GASG;AACH,wBAAsB,UAAU,CAC5B,OAAO,EAAE,WAAW,EACpB,aAAa,SAAc,GAC5B,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAC/B,OAAO,EAAE,cAAc,EACvB,aAAa,SAAc,GAC5B,OAAO,CAAC,OAAO,CAAC,CAOlB;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EACpD,OAAO,EAAE,kBAAkB,EAC3B,aAAa,SAAc,GAC5B,OAAO,CAAC,CAAC,EAAE,CAAC,CAOd"}
@@ -64,3 +64,15 @@ export async function confirmOrExit(options, cancelMessage = 'Cancelled') {
64
64
  }
65
65
  return result;
66
66
  }
67
+ /**
68
+ * Multiselect prompt that exits on cancel.
69
+ * Use for linear flows where cancel should abort the entire operation.
70
+ */
71
+ export async function multiselectOrExit(options, cancelMessage = 'Cancelled') {
72
+ const result = await p.multiselect(options);
73
+ if (p.isCancel(result)) {
74
+ p.cancel(cancelMessage);
75
+ process.exit(0);
76
+ }
77
+ return result;
78
+ }
@@ -44,7 +44,7 @@ const cliVersion = resolveCliVersion();
44
44
  // Set CLI version for Dexto Gateway usage tracking
45
45
  process.env.DEXTO_CLI_VERSION = cliVersion;
46
46
  import { logger, getProviderFromModel, getAllSupportedModels, startLlmRegistryAutoUpdate, DextoAgent, isPath, resolveApiKeyForProvider, getPrimaryApiKeyEnvVar, } from '@dexto/core';
47
- import { applyImageDefaults, cleanNullValues, AgentConfigSchema, loadImage, resolveServicesFromConfig, setImageImporter, toDextoAgentOptions, } from '@dexto/agent-config';
47
+ import { applyImageDefaults, cleanNullValues, AgentConfigSchema, loadImage, resolveServicesFromConfig, toDextoAgentOptions, } from '@dexto/agent-config';
48
48
  import { getDextoPackageRoot, resolveAgentPath, loadAgentConfig, findDextoProjectRoot, globalPreferencesExist, loadGlobalPreferences, resolveBundledScript, enrichAgentConfig, isDextoAuthEnabled, } from '@dexto/agent-management';
49
49
  import { validateCliOptions, handleCliOptionsError } from './cli/utils/options.js';
50
50
  import { validateAgentConfig } from './cli/utils/config-validation.js';
@@ -60,19 +60,11 @@ import { registerPluginCommand } from './cli/commands/plugin/register.js';
60
60
  import { registerAgentsCommand } from './cli/commands/agents/register.js';
61
61
  import { registerDeployCommand } from './cli/commands/deploy/register.js';
62
62
  import { registerInitCommand } from './cli/commands/init.js';
63
+ import { ensureImageImporterConfigured } from './cli/utils/image-importer.js';
63
64
  const program = new Command();
64
- let imageImporterConfigured = false;
65
65
  let dextoApiKeyBootstrapped = false;
66
66
  let versionCheckPromise = null;
67
67
  let llmRegistryAutoUpdateStarted = false;
68
- async function ensureImageImporterConfigured() {
69
- if (imageImporterConfigured) {
70
- return;
71
- }
72
- const { importImageModule } = await import('./cli/utils/image-store.js');
73
- setImageImporter((specifier) => importImageModule(specifier));
74
- imageImporterConfigured = true;
75
- }
76
68
  async function ensureDextoApiKeyBootstrap() {
77
69
  if (dextoApiKeyBootstrapped) {
78
70
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dexto",
3
- "version": "1.6.15",
3
+ "version": "1.6.16",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "dexto": "./dist/index.js"
@@ -34,16 +34,16 @@
34
34
  "ws": "^8.18.1",
35
35
  "yaml": "^2.7.1",
36
36
  "zod": "^3.25.0",
37
- "@dexto/agent-config": "1.6.15",
38
- "@dexto/agent-management": "1.6.15",
39
- "@dexto/analytics": "1.6.15",
40
- "@dexto/core": "1.6.15",
41
- "@dexto/image-local": "1.6.15",
42
- "@dexto/image-logger-agent": "1.6.15",
43
- "@dexto/registry": "1.6.15",
44
- "@dexto/server": "1.6.15",
45
- "@dexto/storage": "1.6.15",
46
- "@dexto/tui": "1.6.15"
37
+ "@dexto/agent-config": "1.6.16",
38
+ "@dexto/agent-management": "1.6.16",
39
+ "@dexto/analytics": "1.6.16",
40
+ "@dexto/core": "1.6.16",
41
+ "@dexto/image-local": "1.6.16",
42
+ "@dexto/image-logger-agent": "1.6.16",
43
+ "@dexto/registry": "1.6.16",
44
+ "@dexto/server": "1.6.16",
45
+ "@dexto/storage": "1.6.16",
46
+ "@dexto/tui": "1.6.16"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/ws": "^8.5.11",