dexto 1.6.8 → 1.6.9

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 (104) hide show
  1. package/README.md +4 -4
  2. package/dist/analytics/wrapper.d.ts.map +1 -1
  3. package/dist/analytics/wrapper.js +43 -9
  4. package/dist/cli/auth/api-client.d.ts +50 -0
  5. package/dist/cli/auth/api-client.d.ts.map +1 -1
  6. package/dist/cli/auth/api-client.js +379 -15
  7. package/dist/cli/auth/browser-launch.d.ts +6 -0
  8. package/dist/cli/auth/browser-launch.d.ts.map +1 -0
  9. package/dist/cli/auth/browser-launch.js +24 -0
  10. package/dist/cli/auth/device.d.ts +14 -0
  11. package/dist/cli/auth/device.d.ts.map +1 -0
  12. package/dist/cli/auth/device.js +93 -0
  13. package/dist/cli/auth/index.d.ts +3 -1
  14. package/dist/cli/auth/index.d.ts.map +1 -1
  15. package/dist/cli/auth/index.js +2 -1
  16. package/dist/cli/auth/login-persistence.d.ts +13 -0
  17. package/dist/cli/auth/login-persistence.d.ts.map +1 -0
  18. package/dist/cli/auth/login-persistence.js +22 -0
  19. package/dist/cli/auth/oauth.d.ts +4 -1
  20. package/dist/cli/auth/oauth.d.ts.map +1 -1
  21. package/dist/cli/auth/oauth.js +6 -2
  22. package/dist/cli/auth/types.d.ts +12 -0
  23. package/dist/cli/auth/types.d.ts.map +1 -0
  24. package/dist/cli/auth/types.js +1 -0
  25. package/dist/cli/commands/agents/register.d.ts +6 -0
  26. package/dist/cli/commands/agents/register.d.ts.map +1 -0
  27. package/dist/cli/commands/agents/register.js +85 -0
  28. package/dist/cli/commands/auth/index.d.ts +1 -1
  29. package/dist/cli/commands/auth/index.d.ts.map +1 -1
  30. package/dist/cli/commands/auth/index.js +1 -1
  31. package/dist/cli/commands/auth/login.d.ts +6 -6
  32. package/dist/cli/commands/auth/login.d.ts.map +1 -1
  33. package/dist/cli/commands/auth/login.js +85 -115
  34. package/dist/cli/commands/auth/logout.d.ts.map +1 -1
  35. package/dist/cli/commands/auth/logout.js +32 -2
  36. package/dist/cli/commands/auth/register.d.ts +3 -0
  37. package/dist/cli/commands/auth/register.d.ts.map +1 -0
  38. package/dist/cli/commands/auth/register.js +94 -0
  39. package/dist/cli/commands/billing/register.d.ts +3 -0
  40. package/dist/cli/commands/billing/register.d.ts.map +1 -0
  41. package/dist/cli/commands/billing/register.js +20 -0
  42. package/dist/cli/commands/helpers/formatters.d.ts.map +1 -1
  43. package/dist/cli/commands/helpers/formatters.js +9 -0
  44. package/dist/cli/commands/image/register.d.ts +6 -0
  45. package/dist/cli/commands/image/register.d.ts.map +1 -0
  46. package/dist/cli/commands/image/register.js +144 -0
  47. package/dist/cli/commands/install.d.ts +2 -2
  48. package/dist/cli/commands/list-agents.d.ts.map +1 -1
  49. package/dist/cli/commands/list-agents.js +3 -3
  50. package/dist/cli/commands/mcp/register.d.ts +6 -0
  51. package/dist/cli/commands/mcp/register.d.ts.map +1 -0
  52. package/dist/cli/commands/mcp/register.js +64 -0
  53. package/dist/cli/commands/plugin/register.d.ts +6 -0
  54. package/dist/cli/commands/plugin/register.d.ts.map +1 -0
  55. package/dist/cli/commands/plugin/register.js +183 -0
  56. package/dist/cli/commands/plugin.d.ts +4 -4
  57. package/dist/cli/commands/register-context.d.ts +12 -0
  58. package/dist/cli/commands/register-context.d.ts.map +1 -0
  59. package/dist/cli/commands/register-context.js +1 -0
  60. package/dist/cli/commands/run/headless.d.ts +20 -0
  61. package/dist/cli/commands/run/headless.d.ts.map +1 -0
  62. package/dist/cli/commands/run/headless.js +275 -0
  63. package/dist/cli/commands/run/register.d.ts +3 -0
  64. package/dist/cli/commands/run/register.d.ts.map +1 -0
  65. package/dist/cli/commands/run/register.js +78 -0
  66. package/dist/cli/commands/search/register.d.ts +3 -0
  67. package/dist/cli/commands/search/register.d.ts.map +1 -0
  68. package/dist/cli/commands/search/register.js +55 -0
  69. package/dist/cli/commands/session/register.d.ts +3 -0
  70. package/dist/cli/commands/session/register.d.ts.map +1 -0
  71. package/dist/cli/commands/session/register.js +75 -0
  72. package/dist/cli/commands/setup.js +4 -4
  73. package/dist/cli/commands/sync-agents.d.ts +3 -3
  74. package/dist/cli/commands/sync-agents.js +4 -4
  75. package/dist/cli/commands/uninstall.d.ts +2 -2
  76. package/dist/cli/modes/cli.d.ts +3 -0
  77. package/dist/cli/modes/cli.d.ts.map +1 -0
  78. package/dist/cli/modes/cli.js +170 -0
  79. package/dist/cli/modes/context.d.ts +20 -0
  80. package/dist/cli/modes/context.d.ts.map +1 -0
  81. package/dist/cli/modes/context.js +1 -0
  82. package/dist/cli/modes/dispatch.d.ts +3 -0
  83. package/dist/cli/modes/dispatch.d.ts.map +1 -0
  84. package/dist/cli/modes/dispatch.js +52 -0
  85. package/dist/cli/modes/mcp.d.ts +3 -0
  86. package/dist/cli/modes/mcp.d.ts.map +1 -0
  87. package/dist/cli/modes/mcp.js +23 -0
  88. package/dist/cli/modes/server.d.ts +3 -0
  89. package/dist/cli/modes/server.d.ts.map +1 -0
  90. package/dist/cli/modes/server.js +36 -0
  91. package/dist/cli/modes/web.d.ts +3 -0
  92. package/dist/cli/modes/web.d.ts.map +1 -0
  93. package/dist/cli/modes/web.js +50 -0
  94. package/dist/cli/utils/setup-utils.js +1 -1
  95. package/dist/index-main.js +150 -991
  96. package/dist/utils/port-utils.d.ts +1 -1
  97. package/dist/utils/port-utils.d.ts.map +1 -1
  98. package/dist/utils/port-utils.js +7 -3
  99. package/dist/webui/assets/index-Bn9YuTdA.css +1 -0
  100. package/dist/webui/assets/index-CNiOYnOb.js +2059 -0
  101. package/dist/webui/index.html +2 -2
  102. package/package.json +12 -12
  103. package/dist/webui/assets/index-d6c-yJNn.js +0 -2059
  104. package/dist/webui/assets/index-yKdFLN1k.css +0 -1
@@ -0,0 +1,78 @@
1
+ import { resolveAgentPath } from '@dexto/agent-management';
2
+ import { withAnalytics, safeExit, ExitSignal } from '../../../analytics/wrapper.js';
3
+ export function registerRunCommand({ program, cliVersion, bootstrapAgentFromGlobalOpts, }) {
4
+ program
5
+ .command('run [prompt]')
6
+ .description('Run a single prompt non-interactively (headless mode)')
7
+ .option('-m, --model <model>', 'Specify the LLM model to use for this run')
8
+ .addHelpText('after', `
9
+ Examples:
10
+ $ dexto run "summarize this repository"
11
+ $ echo "fix lint errors" | dexto run
12
+ $ dexto run - < prompt.txt
13
+ `)
14
+ .action(withAnalytics('run', async (promptArg, runOptions) => {
15
+ let agent;
16
+ let exitCode = 0;
17
+ let exitReason = 'ok';
18
+ try {
19
+ const { executeHeadlessRun, printHeadlessAssistantResponse, printHeadlessMcpStartup, printHeadlessRunSummary, resolveHeadlessPrompt, writeFinalMessageToStdout, writeHeadlessError, } = await import('./headless.js');
20
+ const prompt = await resolveHeadlessPrompt(promptArg);
21
+ if (prompt.trim().length === 0) {
22
+ writeHeadlessError('Prompt cannot be empty.');
23
+ exitCode = 1;
24
+ exitReason = 'empty-prompt';
25
+ }
26
+ else {
27
+ const bootstrapOptions = runOptions?.model
28
+ ? { mode: 'headless-run', modelOverride: runOptions.model }
29
+ : { mode: 'headless-run' };
30
+ agent = await bootstrapAgentFromGlobalOpts(bootstrapOptions);
31
+ const session = await agent.createSession();
32
+ const globalOpts = program.opts();
33
+ const resolvedAgentPath = await resolveAgentPath(globalOpts.agent, globalOpts.autoInstall !== false);
34
+ printHeadlessRunSummary({
35
+ agent,
36
+ sessionId: session.id,
37
+ prompt,
38
+ agentPath: resolvedAgentPath,
39
+ cliVersion,
40
+ });
41
+ printHeadlessMcpStartup(agent);
42
+ const runResult = await executeHeadlessRun(agent, session.id, prompt);
43
+ if (runResult.finalMessage !== undefined) {
44
+ printHeadlessAssistantResponse(runResult.finalMessage, runResult.totalTokens);
45
+ writeFinalMessageToStdout(runResult.finalMessage);
46
+ }
47
+ else {
48
+ writeHeadlessError('No final response was produced.');
49
+ exitCode = 1;
50
+ exitReason = 'no-final-response';
51
+ }
52
+ if (runResult.fatalError) {
53
+ exitCode = 1;
54
+ exitReason = 'fatal-error';
55
+ }
56
+ }
57
+ }
58
+ catch (err) {
59
+ if (err instanceof ExitSignal)
60
+ throw err;
61
+ const errorMessage = err instanceof Error ? err.message : String(err);
62
+ process.stderr.write(`dexto run failed: ${errorMessage}\n`);
63
+ exitCode = 1;
64
+ exitReason = 'error';
65
+ }
66
+ finally {
67
+ if (agent) {
68
+ try {
69
+ await agent.stop();
70
+ }
71
+ catch {
72
+ // Ignore shutdown errors in headless mode cleanup
73
+ }
74
+ }
75
+ }
76
+ safeExit('run', exitCode, exitReason);
77
+ }));
78
+ }
@@ -0,0 +1,3 @@
1
+ import type { RuntimeCommandRegisterContext } from '../register-context.js';
2
+ export declare function registerSearchCommand({ program, bootstrapAgentFromGlobalOpts, }: RuntimeCommandRegisterContext): void;
3
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/search/register.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAE5E,wBAAgB,qBAAqB,CAAC,EAClC,OAAO,EACP,4BAA4B,GAC/B,EAAE,6BAA6B,GAAG,IAAI,CA8EtC"}
@@ -0,0 +1,55 @@
1
+ import { withAnalytics, safeExit, ExitSignal } from '../../../analytics/wrapper.js';
2
+ export function registerSearchCommand({ program, bootstrapAgentFromGlobalOpts, }) {
3
+ program
4
+ .command('search')
5
+ .description('Search session history')
6
+ .argument('<query>', 'Search query')
7
+ .option('--session <sessionId>', 'Search in specific session')
8
+ .option('--role <role>', 'Filter by role (user, assistant, system, tool)')
9
+ .option('--limit <number>', 'Limit number of results', '10')
10
+ .action(withAnalytics('search', async (query, options) => {
11
+ let agent = null;
12
+ try {
13
+ const searchOptions = {};
14
+ if (options.session) {
15
+ searchOptions.sessionId = options.session;
16
+ }
17
+ if (options.role) {
18
+ const allowed = new Set(['user', 'assistant', 'system', 'tool']);
19
+ if (!allowed.has(options.role)) {
20
+ console.error(`❌ Invalid role: ${options.role}. Use one of: user, assistant, system, tool`);
21
+ safeExit('search', 1, 'invalid-role');
22
+ }
23
+ searchOptions.role = options.role;
24
+ }
25
+ if (options.limit) {
26
+ const rawLimit = options.limit.trim();
27
+ const parsed = Number(rawLimit);
28
+ if (!/^\d+$/.test(rawLimit) ||
29
+ !Number.isInteger(parsed) ||
30
+ parsed <= 0) {
31
+ console.error(`❌ Invalid --limit: ${options.limit}. Use a positive integer (e.g., 10).`);
32
+ safeExit('search', 1, 'invalid-limit');
33
+ }
34
+ searchOptions.limit = parsed;
35
+ }
36
+ agent = await bootstrapAgentFromGlobalOpts({
37
+ mode: 'non-interactive',
38
+ });
39
+ const { handleSessionSearchCommand } = await import('../session-commands.js');
40
+ await handleSessionSearchCommand(agent, query, searchOptions);
41
+ safeExit('search', 0);
42
+ }
43
+ catch (err) {
44
+ if (err instanceof ExitSignal)
45
+ throw err;
46
+ console.error(`❌ dexto search command failed: ${err}`);
47
+ safeExit('search', 1, 'error');
48
+ }
49
+ finally {
50
+ if (agent) {
51
+ await agent.stop().catch(() => { });
52
+ }
53
+ }
54
+ }));
55
+ }
@@ -0,0 +1,3 @@
1
+ import type { RuntimeCommandRegisterContext } from '../register-context.js';
2
+ export declare function registerSessionCommand({ program, bootstrapAgentFromGlobalOpts, }: RuntimeCommandRegisterContext): void;
3
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/session/register.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AAE5E,wBAAgB,sBAAsB,CAAC,EACnC,OAAO,EACP,4BAA4B,GAC/B,EAAE,6BAA6B,GAAG,IAAI,CA4EtC"}
@@ -0,0 +1,75 @@
1
+ import { withAnalytics, safeExit, ExitSignal } from '../../../analytics/wrapper.js';
2
+ export function registerSessionCommand({ program, bootstrapAgentFromGlobalOpts, }) {
3
+ const sessionCommand = program.command('session').description('Manage chat sessions');
4
+ sessionCommand
5
+ .command('list')
6
+ .description('List all sessions')
7
+ .action(withAnalytics('session list', async () => {
8
+ let agent = null;
9
+ try {
10
+ agent = await bootstrapAgentFromGlobalOpts({ mode: 'non-interactive' });
11
+ const { handleSessionListCommand } = await import('../session-commands.js');
12
+ await handleSessionListCommand(agent);
13
+ safeExit('session list', 0);
14
+ }
15
+ catch (err) {
16
+ if (err instanceof ExitSignal)
17
+ throw err;
18
+ console.error(`❌ dexto session list command failed: ${err}`);
19
+ safeExit('session list', 1, 'error');
20
+ }
21
+ finally {
22
+ if (agent) {
23
+ await agent.stop().catch(() => { });
24
+ }
25
+ }
26
+ }));
27
+ sessionCommand
28
+ .command('history')
29
+ .description('Show session history')
30
+ .argument('[sessionId]', 'Session ID (defaults to current session)')
31
+ .action(withAnalytics('session history', async (sessionId) => {
32
+ let agent = null;
33
+ try {
34
+ agent = await bootstrapAgentFromGlobalOpts({ mode: 'non-interactive' });
35
+ const { handleSessionHistoryCommand } = await import('../session-commands.js');
36
+ await handleSessionHistoryCommand(agent, sessionId);
37
+ safeExit('session history', 0);
38
+ }
39
+ catch (err) {
40
+ if (err instanceof ExitSignal)
41
+ throw err;
42
+ console.error(`❌ dexto session history command failed: ${err}`);
43
+ safeExit('session history', 1, 'error');
44
+ }
45
+ finally {
46
+ if (agent) {
47
+ await agent.stop().catch(() => { });
48
+ }
49
+ }
50
+ }));
51
+ sessionCommand
52
+ .command('delete')
53
+ .description('Delete a session')
54
+ .argument('<sessionId>', 'Session ID to delete')
55
+ .action(withAnalytics('session delete', async (sessionId) => {
56
+ let agent = null;
57
+ try {
58
+ agent = await bootstrapAgentFromGlobalOpts({ mode: 'non-interactive' });
59
+ const { handleSessionDeleteCommand } = await import('../session-commands.js');
60
+ await handleSessionDeleteCommand(agent, sessionId);
61
+ safeExit('session delete', 0);
62
+ }
63
+ catch (err) {
64
+ if (err instanceof ExitSignal)
65
+ throw err;
66
+ console.error(`❌ dexto session delete command failed: ${err}`);
67
+ safeExit('session delete', 1, 'error');
68
+ }
69
+ finally {
70
+ if (agent) {
71
+ await agent.stop().catch(() => { });
72
+ }
73
+ }
74
+ }));
75
+ }
@@ -9,7 +9,7 @@ import { selectProvider, getProviderDisplayName, getProviderEnvVar, providerRequ
9
9
  import { setupLocalModels, setupOllamaModels, hasSelectedModel, getModelFromResult, } from '../utils/local-model-setup.js';
10
10
  import { requiresSetup } from '../utils/setup-utils.js';
11
11
  import { canUseDextoProvider } from '../utils/dexto-setup.js';
12
- import { handleBrowserLogin } from './auth/login.js';
12
+ import { handleAutoLogin } from './auth/login.js';
13
13
  import { loadAuth, getDextoApiClient } from '../auth/index.js';
14
14
  import { DEXTO_CREDITS_URL } from '../auth/constants.js';
15
15
  import * as p from '@clack/prompts';
@@ -431,16 +431,16 @@ async function handleDextoProviderSetup(options = {}) {
431
431
  const hasKey = await canUseDextoProvider();
432
432
  if (!hasKey) {
433
433
  p.note(`Dexto gives you instant access to ${chalk.cyan('all AI models')} with a single account.\n\n` +
434
- `We'll open your browser to sign in or create an account.`, 'Login Required');
434
+ `We'll guide you through device-code login.`, 'Login Required');
435
435
  const shouldLogin = await p.confirm({
436
- message: 'Continue with browser login?',
436
+ message: 'Continue with Dexto login?',
437
437
  initialValue: true,
438
438
  });
439
439
  if (p.isCancel(shouldLogin) || !shouldLogin) {
440
440
  return abort('Setup cancelled');
441
441
  }
442
442
  try {
443
- await handleBrowserLogin();
443
+ await handleAutoLogin();
444
444
  // Verify key was actually provisioned (provisionKeys silently catches errors)
445
445
  if (!(await canUseDextoProvider())) {
446
446
  p.log.error('API key provisioning failed. Please try again or use `dexto setup` with a different provider.');
@@ -25,9 +25,9 @@ export declare function shouldPromptForSync(): Promise<boolean>;
25
25
  *
26
26
  * @example
27
27
  * ```bash
28
- * dexto sync-agents # Interactive - prompt for each
29
- * dexto sync-agents --list # Show what would be updated
30
- * dexto sync-agents --force # Update all without prompting
28
+ * dexto agents sync # Interactive - prompt for each
29
+ * dexto agents sync --list # Show what would be updated
30
+ * dexto agents sync --force # Update all without prompting
31
31
  * ```
32
32
  */
33
33
  export declare function handleSyncAgentsCommand(options: SyncAgentsCommandOptions): Promise<void>;
@@ -243,9 +243,9 @@ function formatStatus(status) {
243
243
  *
244
244
  * @example
245
245
  * ```bash
246
- * dexto sync-agents # Interactive - prompt for each
247
- * dexto sync-agents --list # Show what would be updated
248
- * dexto sync-agents --force # Update all without prompting
246
+ * dexto agents sync # Interactive - prompt for each
247
+ * dexto agents sync --list # Show what would be updated
248
+ * dexto agents sync --force # Update all without prompting
249
249
  * ```
250
250
  */
251
251
  export async function handleSyncAgentsCommand(options) {
@@ -363,7 +363,7 @@ export async function handleSyncAgentsCommand(options) {
363
363
  console.log('');
364
364
  // If list mode, stop here
365
365
  if (list) {
366
- p.outro('Use `dexto sync-agents` to update agents');
366
+ p.outro('Use `dexto agents sync` to update agents');
367
367
  return;
368
368
  }
369
369
  // No updates needed
@@ -4,13 +4,13 @@ declare const UninstallCommandSchema: z.ZodObject<{
4
4
  all: z.ZodDefault<z.ZodBoolean>;
5
5
  force: z.ZodDefault<z.ZodBoolean>;
6
6
  }, "strict", z.ZodTypeAny, {
7
- all: boolean;
8
7
  agents: string[];
9
8
  force: boolean;
9
+ all: boolean;
10
10
  }, {
11
11
  agents: string[];
12
- all?: boolean | undefined;
13
12
  force?: boolean | undefined;
13
+ all?: boolean | undefined;
14
14
  }>;
15
15
  export type UninstallCommandOptions = z.output<typeof UninstallCommandSchema>;
16
16
  export declare function handleUninstallCommand(agents: string[], options: Partial<UninstallCommandOptions>): Promise<void>;
@@ -0,0 +1,3 @@
1
+ import type { MainModeContext } from './context.js';
2
+ export declare function runCliMode(context: MainModeContext): Promise<void>;
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../../src/cli/modes/cli.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAsBpD,wBAAsB,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuLxE"}
@@ -0,0 +1,170 @@
1
+ import * as p from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import { logger } from '@dexto/core';
4
+ import { safeExit, ExitSignal } from '../../analytics/wrapper.js';
5
+ async function getMostRecentSessionId(agent) {
6
+ const sessionIds = await agent.listSessions();
7
+ if (sessionIds.length === 0) {
8
+ return null;
9
+ }
10
+ let mostRecentId = null;
11
+ let mostRecentActivity = 0;
12
+ for (const sessionId of sessionIds) {
13
+ const metadata = await agent.getSessionMetadata(sessionId);
14
+ if (metadata && metadata.lastActivity > mostRecentActivity) {
15
+ mostRecentActivity = metadata.lastActivity;
16
+ mostRecentId = sessionId;
17
+ }
18
+ }
19
+ return mostRecentId;
20
+ }
21
+ export async function runCliMode(context) {
22
+ const { agent, opts, validatedConfig, resolvedPath, initialPrompt, getVersionCheckResult } = context;
23
+ const needsHandler = validatedConfig.permissions.mode === 'manual' || validatedConfig.elicitation.enabled;
24
+ if (needsHandler) {
25
+ const { createCLIApprovalHandler } = await import('../approval/index.js');
26
+ const handler = createCLIApprovalHandler(agent);
27
+ agent.setApprovalHandler(handler);
28
+ logger.debug('CLI approval handler configured for Ink CLI');
29
+ }
30
+ await agent.start();
31
+ try {
32
+ const llmConfig = agent.getCurrentLLMConfig();
33
+ const { requiresApiKey } = await import('@dexto/core');
34
+ if (requiresApiKey(llmConfig.provider) && !llmConfig.apiKey?.trim()) {
35
+ const { interactiveApiKeySetup } = await import('../utils/api-key-setup.js');
36
+ console.log(chalk.yellow(`\n⚠️ API key required for provider '${llmConfig.provider}'\n`));
37
+ const setupResult = await interactiveApiKeySetup(llmConfig.provider, {
38
+ exitOnCancel: false,
39
+ model: llmConfig.model,
40
+ });
41
+ if (setupResult.cancelled) {
42
+ safeExit('main', 0, 'api-key-setup-cancelled');
43
+ }
44
+ if (setupResult.skipped) {
45
+ safeExit('main', 0, 'api-key-pending');
46
+ }
47
+ if (setupResult.success && setupResult.apiKey) {
48
+ await agent.switchLLM({
49
+ provider: llmConfig.provider,
50
+ model: llmConfig.model,
51
+ apiKey: setupResult.apiKey,
52
+ });
53
+ logger.info('API key configured successfully, continuing...');
54
+ }
55
+ }
56
+ let cliSessionId;
57
+ if (opts.resume) {
58
+ const existing = await agent.getSession(opts.resume);
59
+ if (!existing) {
60
+ console.error(`❌ Session '${opts.resume}' not found`);
61
+ console.error('💡 Use `dexto session list` to see available sessions');
62
+ safeExit('main', 1, 'resume-failed');
63
+ }
64
+ cliSessionId = opts.resume;
65
+ }
66
+ else if (opts.continue) {
67
+ const mostRecentSessionId = await getMostRecentSessionId(agent);
68
+ if (mostRecentSessionId) {
69
+ cliSessionId = mostRecentSessionId;
70
+ }
71
+ else {
72
+ const session = await agent.createSession();
73
+ cliSessionId = session.id;
74
+ }
75
+ }
76
+ else {
77
+ const session = await agent.createSession();
78
+ cliSessionId = session.id;
79
+ }
80
+ const cliUpdateInfo = await getVersionCheckResult();
81
+ const { shouldPromptForSync, handleSyncAgentsCommand } = await import('../commands/sync-agents.js');
82
+ const needsSync = await shouldPromptForSync();
83
+ if (needsSync) {
84
+ const shouldSync = await p.confirm({
85
+ message: 'Agent config updates available. Sync now?',
86
+ initialValue: true,
87
+ });
88
+ if (!p.isCancel(shouldSync) && shouldSync) {
89
+ await handleSyncAgentsCommand({ force: true, quiet: true });
90
+ }
91
+ }
92
+ const originalConsole = {
93
+ log: console.log,
94
+ error: console.error,
95
+ warn: console.warn,
96
+ info: console.info,
97
+ };
98
+ const noOp = () => { };
99
+ console.log = noOp;
100
+ console.error = noOp;
101
+ console.warn = noOp;
102
+ console.info = noOp;
103
+ let inkError = undefined;
104
+ try {
105
+ const [{ startInkCliRefactored, setTuiRuntimeServices }, { registerGracefulShutdown }, { applyLayeredEnvironmentLoading }, { getProviderDisplayName, isValidApiKeyFormat, getProviderInstructions }, { performDeviceCodeLogin, persistOAuthLoginResult, ensureDextoApiKeyForAuthToken, loadAuth, storeAuth, removeAuth, removeDextoApiKeyFromEnv, }, { isUsingDextoCredits }, { canUseDextoProvider }, { capture },] = await Promise.all([
106
+ import('@dexto/tui'),
107
+ import('../../utils/graceful-shutdown.js'),
108
+ import('../../utils/env.js'),
109
+ import('../utils/provider-setup.js'),
110
+ import('../auth/index.js'),
111
+ import('../../config/effective-llm.js'),
112
+ import('../utils/dexto-setup.js'),
113
+ import('../../analytics/index.js'),
114
+ ]);
115
+ setTuiRuntimeServices({
116
+ registerGracefulShutdown,
117
+ capture: (event, properties) => {
118
+ capture(event, properties);
119
+ },
120
+ applyLayeredEnvironmentLoading,
121
+ getProviderDisplayName,
122
+ isValidApiKeyFormat,
123
+ getProviderInstructions,
124
+ performDeviceCodeLogin,
125
+ persistOAuthLoginResult,
126
+ ensureDextoApiKeyForAuthToken,
127
+ loadAuth,
128
+ storeAuth,
129
+ removeAuth,
130
+ removeDextoApiKeyFromEnv,
131
+ isUsingDextoCredits,
132
+ canUseDextoProvider,
133
+ });
134
+ await startInkCliRefactored(agent, cliSessionId, {
135
+ updateInfo: cliUpdateInfo ?? undefined,
136
+ configFilePath: resolvedPath,
137
+ ...(initialPrompt && { initialPrompt }),
138
+ bypassPermissions: opts.bypassPermissions,
139
+ });
140
+ }
141
+ catch (error) {
142
+ inkError = error;
143
+ }
144
+ finally {
145
+ console.log = originalConsole.log;
146
+ console.error = originalConsole.error;
147
+ console.warn = originalConsole.warn;
148
+ console.info = originalConsole.info;
149
+ }
150
+ if (inkError) {
151
+ if (inkError instanceof ExitSignal)
152
+ throw inkError;
153
+ const errorMessage = inkError instanceof Error ? inkError.message : String(inkError);
154
+ console.error(`❌ Ink CLI failed: ${errorMessage}`);
155
+ if (inkError instanceof Error && inkError.stack) {
156
+ console.error(inkError.stack);
157
+ }
158
+ safeExit('main', 1, 'ink-cli-error');
159
+ }
160
+ safeExit('main', 0);
161
+ }
162
+ finally {
163
+ try {
164
+ await agent.stop();
165
+ }
166
+ catch {
167
+ // Ignore shutdown errors
168
+ }
169
+ }
170
+ }
@@ -0,0 +1,20 @@
1
+ import type { ValidatedAgentConfig } from '@dexto/agent-config';
2
+ import type { DextoAgent } from '@dexto/core';
3
+ import type { UpdateInfo } from '../utils/version-check.js';
4
+ export interface MainModeOptions {
5
+ mode: string;
6
+ port?: string;
7
+ resume?: string;
8
+ continue?: boolean;
9
+ bypassPermissions?: boolean;
10
+ }
11
+ export interface MainModeContext {
12
+ agent: DextoAgent;
13
+ opts: MainModeOptions;
14
+ validatedConfig: ValidatedAgentConfig;
15
+ resolvedPath: string;
16
+ derivedAgentId: string;
17
+ initialPrompt: string | undefined;
18
+ getVersionCheckResult: () => Promise<UpdateInfo | null>;
19
+ }
20
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../src/cli/modes/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,IAAI,EAAE,eAAe,CAAC;IACtB,eAAe,EAAE,oBAAoB,CAAC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,qBAAqB,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;CAC3D"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { MainModeContext } from './context.js';
2
+ export declare function dispatchMainMode(context: MainModeContext): Promise<void>;
3
+ //# sourceMappingURL=dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../../src/cli/modes/dispatch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAqD9E"}
@@ -0,0 +1,52 @@
1
+ import { safeExit, ExitSignal } from '../../analytics/wrapper.js';
2
+ export async function dispatchMainMode(context) {
3
+ const mode = context.opts.mode;
4
+ try {
5
+ switch (mode) {
6
+ case 'cli': {
7
+ const { runCliMode } = await import('./cli.js');
8
+ await runCliMode(context);
9
+ return;
10
+ }
11
+ case 'web': {
12
+ const { runWebMode } = await import('./web.js');
13
+ await runWebMode(context);
14
+ return;
15
+ }
16
+ case 'server': {
17
+ const { runServerMode } = await import('./server.js');
18
+ await runServerMode(context);
19
+ return;
20
+ }
21
+ case 'mcp': {
22
+ const { runMcpMode } = await import('./mcp.js');
23
+ await runMcpMode(context);
24
+ return;
25
+ }
26
+ default:
27
+ if (mode === 'discord' || mode === 'telegram') {
28
+ console.error(`❌ Error: '${mode}' mode has been moved to examples`);
29
+ console.error('');
30
+ console.error(`The ${mode} bot is now a standalone example that you can customize.`);
31
+ console.error('');
32
+ console.error(`📖 See: examples/${mode}-bot/README.md`);
33
+ console.error('');
34
+ console.error('To run it:');
35
+ console.error(` cd examples/${mode}-bot`);
36
+ console.error(' pnpm install');
37
+ console.error(' pnpm start');
38
+ }
39
+ else {
40
+ console.error(`❌ Unknown mode '${mode}'. Use web, cli, server, or mcp.`);
41
+ }
42
+ safeExit('main', 1, 'unknown-mode');
43
+ }
44
+ }
45
+ catch (err) {
46
+ if (err instanceof ExitSignal)
47
+ throw err;
48
+ const message = err instanceof Error ? err.message : String(err);
49
+ console.error(`❌ Failed to start '${mode}' mode: ${message}`);
50
+ safeExit('main', 1, 'mode-startup-failed');
51
+ }
52
+ }
@@ -0,0 +1,3 @@
1
+ import type { MainModeContext } from './context.js';
2
+ export declare function runMcpMode(context: MainModeContext): Promise<void>;
3
+ //# sourceMappingURL=mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../../src/cli/modes/mcp.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,wBAAsB,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBxE"}
@@ -0,0 +1,23 @@
1
+ import { createAgentCard } from '@dexto/core';
2
+ import { safeExit } from '../../analytics/wrapper.js';
3
+ export async function runMcpMode(context) {
4
+ const { agent } = context;
5
+ const agentCardConfig = agent.config.agentCard || {
6
+ name: 'dexto',
7
+ version: '1.0.0',
8
+ };
9
+ try {
10
+ const agentCardData = createAgentCard({
11
+ defaultName: agentCardConfig.name ?? 'dexto',
12
+ defaultVersion: agentCardConfig.version ?? '1.0.0',
13
+ defaultBaseUrl: 'stdio://local-dexto',
14
+ }, agentCardConfig);
15
+ const { createMcpTransport, initializeMcpServer } = await import('@dexto/server');
16
+ const mcpTransport = await createMcpTransport('stdio');
17
+ await initializeMcpServer(agent, agentCardData, mcpTransport);
18
+ }
19
+ catch (err) {
20
+ process.stderr.write(`MCP server startup failed: ${err}\n`);
21
+ safeExit('main', 1, 'mcp-startup-failed');
22
+ }
23
+ }
@@ -0,0 +1,3 @@
1
+ import type { MainModeContext } from './context.js';
2
+ export declare function runServerMode(context: MainModeContext): Promise<void>;
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/cli/modes/server.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpD,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA0C3E"}
@@ -0,0 +1,36 @@
1
+ import { getPort } from '../../utils/port-utils.js';
2
+ export async function runServerMode(context) {
3
+ const { agent, opts, derivedAgentId, resolvedPath, getVersionCheckResult } = context;
4
+ const { startHonoApiServer } = await import('../../api/server-hono.js');
5
+ const agentCard = agent.config.agentCard ?? {};
6
+ const defaultPort = (() => {
7
+ if (!opts.port) {
8
+ return 3001;
9
+ }
10
+ const rawPort = opts.port.trim();
11
+ const parsedPort = Number(rawPort);
12
+ if (!/^\d+$/.test(rawPort) ||
13
+ !Number.isInteger(parsedPort) ||
14
+ parsedPort <= 0 ||
15
+ parsedPort > 65535) {
16
+ throw new Error(`Invalid --port value "${opts.port}". Use a port between 1 and 65535.`);
17
+ }
18
+ return parsedPort;
19
+ })();
20
+ const apiPort = getPort(process.env.PORT, defaultPort, 'PORT');
21
+ const apiUrl = process.env.DEXTO_URL ?? `http://localhost:${apiPort}`;
22
+ console.log('🌐 Starting server (REST APIs + SSE)...');
23
+ await startHonoApiServer(agent, apiPort, agentCard, derivedAgentId, resolvedPath);
24
+ console.log(`✅ Server running at ${apiUrl}`);
25
+ console.log('Available endpoints:');
26
+ console.log(' POST /api/message - Send async message');
27
+ console.log(' POST /api/message-sync - Send sync message');
28
+ console.log(' POST /api/reset - Reset conversation');
29
+ console.log(' GET /api/mcp/servers - List MCP servers');
30
+ console.log(' SSE support available for real-time events');
31
+ const serverUpdateInfo = await getVersionCheckResult();
32
+ if (serverUpdateInfo) {
33
+ const { displayUpdateNotification } = await import('../utils/version-check.js');
34
+ displayUpdateNotification(serverUpdateInfo);
35
+ }
36
+ }