dexto 1.13.4 → 1.14.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 (62) hide show
  1. package/dist/api/mcp/http-gateway.d.ts +21 -0
  2. package/dist/api/mcp/http-gateway.d.ts.map +1 -0
  3. package/dist/api/mcp/http-gateway.js +110 -0
  4. package/dist/api/mcp/tool-aggregation-handler.d.ts +9 -6
  5. package/dist/api/mcp/tool-aggregation-handler.d.ts.map +1 -1
  6. package/dist/api/mcp/tool-aggregation-handler.js +203 -70
  7. package/dist/api/server-hono.d.ts +2 -0
  8. package/dist/api/server-hono.d.ts.map +1 -1
  9. package/dist/api/server-hono.js +377 -276
  10. package/dist/cli/approval/headless-approval-handler.d.ts +4 -0
  11. package/dist/cli/approval/headless-approval-handler.d.ts.map +1 -0
  12. package/dist/cli/approval/headless-approval-handler.js +19 -0
  13. package/dist/cli/auth/api-client.js +1 -1
  14. package/dist/cli/auth/constants.d.ts +1 -0
  15. package/dist/cli/auth/constants.d.ts.map +1 -1
  16. package/dist/cli/auth/constants.js +2 -1
  17. package/dist/cli/auth/dexto-api-key.d.ts.map +1 -1
  18. package/dist/cli/auth/dexto-api-key.js +3 -0
  19. package/dist/cli/auth/login-persistence.d.ts +1 -1
  20. package/dist/cli/auth/login-persistence.d.ts.map +1 -1
  21. package/dist/cli/auth/login-persistence.js +9 -1
  22. package/dist/cli/auth/service.d.ts +2 -0
  23. package/dist/cli/auth/service.d.ts.map +1 -1
  24. package/dist/cli/auth/service.js +1 -0
  25. package/dist/cli/commands/agents/register.d.ts.map +1 -1
  26. package/dist/cli/commands/agents/register.js +0 -1
  27. package/dist/cli/commands/auth/login.d.ts.map +1 -1
  28. package/dist/cli/commands/auth/login.js +9 -4
  29. package/dist/cli/commands/cloud/discovery.d.ts +17 -0
  30. package/dist/cli/commands/cloud/discovery.d.ts.map +1 -0
  31. package/dist/cli/commands/cloud/discovery.js +88 -0
  32. package/dist/cli/commands/cloud/register.d.ts +3 -0
  33. package/dist/cli/commands/cloud/register.d.ts.map +1 -0
  34. package/dist/cli/commands/cloud/register.js +27 -0
  35. package/dist/cli/commands/mcp/register.d.ts +1 -1
  36. package/dist/cli/commands/mcp/register.d.ts.map +1 -1
  37. package/dist/cli/commands/mcp/register.js +259 -26
  38. package/dist/cli/commands/mcp/standalone.d.ts +98 -0
  39. package/dist/cli/commands/mcp/standalone.d.ts.map +1 -0
  40. package/dist/cli/commands/mcp/standalone.js +489 -0
  41. package/dist/cli/commands/run/headless.d.ts +3 -1
  42. package/dist/cli/commands/run/headless.d.ts.map +1 -1
  43. package/dist/cli/commands/run/headless.js +13 -1
  44. package/dist/cli/commands/run/output.d.ts +21 -0
  45. package/dist/cli/commands/run/output.d.ts.map +1 -0
  46. package/dist/cli/commands/run/output.js +95 -0
  47. package/dist/cli/commands/run/register.d.ts.map +1 -1
  48. package/dist/cli/commands/run/register.js +27 -3
  49. package/dist/cli/commands/setup.d.ts +2 -2
  50. package/dist/cli/commands/trace/client.d.ts +2 -2
  51. package/dist/cli/utils/options.js +3 -1
  52. package/dist/config/cli-overrides.d.ts +3 -1
  53. package/dist/config/cli-overrides.d.ts.map +1 -1
  54. package/dist/config/cli-overrides.js +9 -3
  55. package/dist/index-main.js +11 -10
  56. package/dist/utils/env.d.ts +2 -0
  57. package/dist/utils/env.d.ts.map +1 -1
  58. package/dist/utils/env.js +6 -0
  59. package/dist/utils/graceful-shutdown.d.ts +1 -1
  60. package/dist/utils/graceful-shutdown.d.ts.map +1 -1
  61. package/dist/utils/graceful-shutdown.js +28 -9
  62. package/package.json +14 -14
@@ -1,3 +1,6 @@
1
+ import { Option } from 'commander';
2
+ import { handleHeadlessApproval } from '../../approval/headless-approval-handler.js';
3
+ import { writeHeadlessResult } from './output.js';
1
4
  import { resolveAgentPath } from '@dexto/agent-management';
2
5
  import { withAnalytics, safeExit, ExitSignal } from '../../../analytics/wrapper.js';
3
6
  export function registerRunCommand({ program, cliVersion, bootstrapAgentFromGlobalOpts, }) {
@@ -5,6 +8,9 @@ export function registerRunCommand({ program, cliVersion, bootstrapAgentFromGlob
5
8
  .command('run [prompt]')
6
9
  .description('Run a single prompt non-interactively (headless mode)')
7
10
  .option('-m, --model <model>', 'Specify the LLM model to use for this run')
11
+ .addOption(new Option('--format <format>', 'Output format')
12
+ .choices(['text', 'json', 'jsonl'])
13
+ .default('text'))
8
14
  .addHelpText('after', `
9
15
  Examples:
10
16
  $ dexto run "summarize this repository"
@@ -13,6 +19,8 @@ Examples:
13
19
  `)
14
20
  .action(withAnalytics('run', async (promptArg, runOptions) => {
15
21
  let agent;
22
+ let sessionId;
23
+ let result = {};
16
24
  let exitCode = 0;
17
25
  let exitReason = 'ok';
18
26
  try {
@@ -20,15 +28,19 @@ Examples:
20
28
  const prompt = await resolveHeadlessPrompt(promptArg);
21
29
  if (prompt.trim().length === 0) {
22
30
  writeHeadlessError('Prompt cannot be empty.');
31
+ result = { fatalError: new Error('Prompt cannot be empty.') };
23
32
  exitCode = 1;
24
33
  exitReason = 'empty-prompt';
25
34
  }
26
35
  else {
27
- const bootstrapOptions = runOptions?.model
36
+ const bootstrapOptions = runOptions.model
28
37
  ? { mode: 'headless-run', modelOverride: runOptions.model }
29
38
  : { mode: 'headless-run' };
30
39
  agent = await bootstrapAgentFromGlobalOpts(bootstrapOptions);
31
40
  const session = await agent.createSession();
41
+ sessionId = session.id;
42
+ const approvalAgent = agent;
43
+ approvalAgent.setApprovalHandler((request) => handleHeadlessApproval(request, approvalAgent, session.id));
32
44
  const globalOpts = program.opts();
33
45
  const resolvedAgentPath = await resolveAgentPath(globalOpts.agent, globalOpts.autoInstall !== false);
34
46
  printHeadlessRunSummary({
@@ -39,13 +51,21 @@ Examples:
39
51
  cliVersion,
40
52
  });
41
53
  printHeadlessMcpStartup(agent);
42
- const runResult = await executeHeadlessRun(agent, session.id, prompt);
54
+ const runResult = await executeHeadlessRun(agent, session.id, prompt, runOptions.format);
55
+ result = runResult;
43
56
  if (runResult.finalMessage !== undefined) {
44
57
  printHeadlessAssistantResponse(runResult.finalMessage, runResult.totalTokens);
45
- writeFinalMessageToStdout(runResult.finalMessage);
58
+ if (runOptions.format === 'text') {
59
+ writeFinalMessageToStdout(runResult.finalMessage);
60
+ }
46
61
  }
47
62
  else {
48
63
  writeHeadlessError('No final response was produced.');
64
+ result = {
65
+ ...runResult,
66
+ fatalError: runResult.fatalError ??
67
+ new Error('No final response was produced.'),
68
+ };
49
69
  exitCode = 1;
50
70
  exitReason = 'no-final-response';
51
71
  }
@@ -59,6 +79,9 @@ Examples:
59
79
  if (err instanceof ExitSignal)
60
80
  throw err;
61
81
  const errorMessage = err instanceof Error ? err.message : String(err);
82
+ result = {
83
+ fatalError: err instanceof Error ? err : new Error(errorMessage),
84
+ };
62
85
  process.stderr.write(`dexto run failed: ${errorMessage}\n`);
63
86
  exitCode = 1;
64
87
  exitReason = 'error';
@@ -73,6 +96,7 @@ Examples:
73
96
  }
74
97
  }
75
98
  }
99
+ await writeHeadlessResult(runOptions.format, result, sessionId);
76
100
  safeExit('run', exitCode, exitReason);
77
101
  }));
78
102
  }
@@ -2,6 +2,7 @@ import { z } from 'zod';
2
2
  declare const SetupCommandSchema: z.ZodObject<{
3
3
  provider: z.ZodOptional<z.ZodEnum<{
4
4
  "dexto-nova": "dexto-nova";
5
+ local: "local";
5
6
  openai: "openai";
6
7
  "openai-compatible": "openai-compatible";
7
8
  anthropic: "anthropic";
@@ -16,7 +17,6 @@ declare const SetupCommandSchema: z.ZodObject<{
16
17
  glama: "glama";
17
18
  vertex: "vertex";
18
19
  bedrock: "bedrock";
19
- local: "local";
20
20
  ollama: "ollama";
21
21
  }>>;
22
22
  model: z.ZodOptional<z.ZodString>;
@@ -25,11 +25,11 @@ declare const SetupCommandSchema: z.ZodObject<{
25
25
  force: z.ZodDefault<z.ZodBoolean>;
26
26
  defaultMode: z.ZodOptional<z.ZodEnum<{
27
27
  cli: "cli";
28
+ mcp: "mcp";
28
29
  web: "web";
29
30
  server: "server";
30
31
  discord: "discord";
31
32
  telegram: "telegram";
32
- mcp: "mcp";
33
33
  }>>;
34
34
  quickStart: z.ZodDefault<z.ZodBoolean>;
35
35
  }, z.core.$strict>;
@@ -15,8 +15,8 @@ declare const RunTraceSpanSchema: z.ZodObject<{
15
15
  startedAt: z.ZodString;
16
16
  status: z.ZodEnum<{
17
17
  failed: "failed";
18
- completed: "completed";
19
18
  cancelled: "cancelled";
19
+ completed: "completed";
20
20
  running: "running";
21
21
  }>;
22
22
  traceId: z.ZodString;
@@ -46,8 +46,8 @@ declare const RunTraceSchema: z.ZodObject<{
46
46
  startedAt: z.ZodString;
47
47
  status: z.ZodEnum<{
48
48
  failed: "failed";
49
- completed: "completed";
50
49
  cancelled: "cancelled";
50
+ completed: "completed";
51
51
  running: "running";
52
52
  }>;
53
53
  traceId: z.ZodString;
@@ -30,6 +30,7 @@ export function validateCliOptions(opts) {
30
30
  return !isNaN(port) && port > 0 && port <= 65535;
31
31
  }, { message: 'Port must be a number between 1 and 65535' })
32
32
  .optional(),
33
+ permissionsMode: z.enum(['manual', 'auto-approve']).optional(),
33
34
  autoApprove: z
34
35
  .boolean()
35
36
  .optional()
@@ -39,7 +40,7 @@ export function validateCliOptions(opts) {
39
40
  .boolean()
40
41
  .optional()
41
42
  .default(false)
42
- .describe('Start the interactive CLI in bypass permissions mode (auto-approve approval prompts)'),
43
+ .describe('Select auto-approve permissions'),
43
44
  elicitation: z
44
45
  .boolean()
45
46
  .optional()
@@ -91,6 +92,7 @@ export function validateCliOptions(opts) {
91
92
  provider: opts.provider,
92
93
  model: opts.model,
93
94
  interactive: opts.interactive,
95
+ permissionsMode: opts.permissionsMode,
94
96
  autoApprove: opts.autoApprove,
95
97
  bypassPermissions: opts.bypassPermissions,
96
98
  elicitation: opts.elicitation,
@@ -20,7 +20,7 @@
20
20
  */
21
21
  import type { AgentConfig } from '@dexto/agent-config';
22
22
  import { type LLMProvider } from '@dexto/llm';
23
- import { type LLMConfig } from '@dexto/core';
23
+ import { type LLMConfig, type PermissionsMode } from '@dexto/core';
24
24
  import type { GlobalPreferences } from '@dexto/agent-management';
25
25
  /**
26
26
  * CLI config override type for fields that can be overridden via CLI
@@ -28,6 +28,8 @@ import type { GlobalPreferences } from '@dexto/agent-management';
28
28
  */
29
29
  export interface CLIConfigOverrides extends Partial<Pick<LLMConfig, 'provider' | 'model' | 'apiKey'>> {
30
30
  autoApprove?: boolean;
31
+ bypassPermissions?: boolean;
32
+ permissionsMode?: PermissionsMode;
31
33
  /** When false (via --no-elicitation), disables elicitation */
32
34
  elicitation?: boolean;
33
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"cli-overrides.d.ts","sourceRoot":"","sources":["../../src/config/cli-overrides.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAKH,KAAK,WAAW,EACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAA+C,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;GAGG;AACH,MAAM,WAAW,kBACb,SAAQ,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACtC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,2BAA2B,EAAE,OAAO,CAAC;IACrC,wBAAwB,EAAE,OAAO,CAAC;IAClC,yBAAyB,EAAE,OAAO,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC7B,UAAU,EAAE,WAAW,EACvB,YAAY,CAAC,EAAE,kBAAkB,GAClC,WAAW,CAuCb;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAChC,UAAU,EAAE,WAAW,EACvB,WAAW,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACxC,WAAW,CAwBb;AAED,wBAAgB,uBAAuB,CACnC,UAAU,EAAE,WAAW,EACvB,OAAO,EAAE,yBAAyB,GACnC,WAAW,CAyCb;AAcD,wBAAgB,oBAAoB,CAChC,QAAQ,EAAE,WAAW,EACrB,SAAS,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC,GAC3D,OAAO,CAgBT;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACrC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,WAAW,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,WAAW,GAAG,SAAS,CAAC;IACtC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACnC,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,iBAAiB,GAAG,IAAI,EACrC,cAAc,EAAE,MAAM,GAAG,SAAS,GACnC,wBAAwB,CAwC1B"}
1
+ {"version":3,"file":"cli-overrides.d.ts","sourceRoot":"","sources":["../../src/config/cli-overrides.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAKH,KAAK,WAAW,EACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAGH,KAAK,SAAS,EACd,KAAK,eAAe,EACvB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAEjE;;;GAGG;AACH,MAAM,WAAW,kBACb,SAAQ,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,8DAA8D;IAC9D,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACtC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,2BAA2B,EAAE,OAAO,CAAC;IACrC,wBAAwB,EAAE,OAAO,CAAC;IAClC,yBAAyB,EAAE,OAAO,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC7B,UAAU,EAAE,WAAW,EACvB,YAAY,CAAC,EAAE,kBAAkB,GAClC,WAAW,CAoDb;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAChC,UAAU,EAAE,WAAW,EACvB,WAAW,EAAE,OAAO,CAAC,iBAAiB,CAAC,GACxC,WAAW,CAwBb;AAED,wBAAgB,uBAAuB,CACnC,UAAU,EAAE,WAAW,EACvB,OAAO,EAAE,yBAAyB,GACnC,WAAW,CAyCb;AAcD,wBAAgB,oBAAoB,CAChC,QAAQ,EAAE,WAAW,EACrB,SAAS,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC,GAC3D,OAAO,CAgBT;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACrC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,WAAW,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,WAAW,GAAG,SAAS,CAAC;IACtC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,aAAa,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACnC,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,iBAAiB,GAAG,IAAI,EACrC,cAAc,EAAE,MAAM,GAAG,SAAS,GACnC,wBAAwB,CAwC1B"}
@@ -19,7 +19,7 @@
19
19
  * - Merge strategy configuration for non-LLM fields
20
20
  */
21
21
  import { LLM_PROVIDERS, getDefaultModelForProvider, requiresApiKey, requiresBaseURL, } from '@dexto/llm';
22
- import { EnvExpandedString, resolveApiKeyForProvider } from '@dexto/core';
22
+ import { EnvExpandedString, resolveApiKeyForProvider, } from '@dexto/core';
23
23
  /**
24
24
  * Applies CLI overrides to an agent configuration
25
25
  * This merges CLI arguments into the base config without validation.
@@ -34,6 +34,10 @@ export function applyCLIOverrides(baseConfig, cliOverrides) {
34
34
  // No overrides, return base config as-is (no validation yet)
35
35
  return baseConfig;
36
36
  }
37
+ if (cliOverrides.permissionsMode === 'manual' &&
38
+ (cliOverrides.autoApprove || cliOverrides.bypassPermissions)) {
39
+ throw new Error('--permissions-mode manual conflicts with --auto-approve and --bypass-permissions.');
40
+ }
37
41
  // Create a deep copy of the base config for modification
38
42
  const mergedConfig = JSON.parse(JSON.stringify(baseConfig));
39
43
  // Apply CLI overrides to LLM config (llm is required in AgentConfig)
@@ -46,11 +50,13 @@ export function applyCLIOverrides(baseConfig, cliOverrides) {
46
50
  if (cliOverrides.apiKey) {
47
51
  mergedConfig.llm.apiKey = cliOverrides.apiKey;
48
52
  }
49
- if (cliOverrides.autoApprove) {
53
+ if (cliOverrides.permissionsMode ||
54
+ cliOverrides.autoApprove ||
55
+ cliOverrides.bypassPermissions) {
50
56
  // Ensure permissions section exists before overriding
51
57
  mergedConfig.permissions = {
52
58
  ...(mergedConfig.permissions ?? {}),
53
- mode: 'auto-approve',
59
+ mode: cliOverrides.permissionsMode ?? 'auto-approve',
54
60
  };
55
61
  }
56
62
  if (cliOverrides.elicitation === false) {
@@ -1,10 +1,11 @@
1
1
  import { existsSync, readFileSync } from 'fs';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
- import { Command } from 'commander';
4
+ import { Command, Option } from 'commander';
5
5
  import * as p from '@clack/prompts';
6
6
  import chalk from 'chalk';
7
7
  import { withAnalytics, safeExit, ExitSignal } from './analytics/wrapper.js';
8
+ import { handleHeadlessApproval } from './cli/approval/headless-approval-handler.js';
8
9
  function readVersionFromPackageJson(packageJsonPath) {
9
10
  if (!existsSync(packageJsonPath)) {
10
11
  return undefined;
@@ -55,6 +56,7 @@ import { registerSessionCommand } from './cli/commands/session/register.js';
55
56
  import { registerSearchCommand } from './cli/commands/search/register.js';
56
57
  import { registerAuthCommand } from './cli/commands/auth/register.js';
57
58
  import { registerBillingCommand } from './cli/commands/billing/register.js';
59
+ import { registerCloudCommand } from './cli/commands/cloud/register.js';
58
60
  import { registerMcpCommand } from './cli/commands/mcp/register.js';
59
61
  import { registerImageCommand } from './cli/commands/image/register.js';
60
62
  import { registerPluginCommand } from './cli/commands/plugin/register.js';
@@ -110,8 +112,9 @@ program
110
112
  .option('--no-interactive', 'Disable interactive prompts and API key setup')
111
113
  .option('--skip-setup', 'Skip global setup validation (useful for MCP mode, automation)')
112
114
  .option('-m, --model <model>', 'Specify the LLM model to use')
113
- .option('--auto-approve', 'Always approve tool executions without approval prompts')
114
- .option('--bypass-permissions', 'Start the interactive CLI in bypass permissions mode (auto-approve approval prompts)')
115
+ .addOption(new Option('--permissions-mode <mode>', "Override the local agent's configured approval mode").choices(['manual', 'auto-approve']))
116
+ .option('--auto-approve', 'Select auto-approve permissions (mandatory approvals still apply)')
117
+ .option('--bypass-permissions', 'Select auto-approve permissions (alias for --permissions-mode auto-approve)')
115
118
  .option('--no-elicitation', 'Disable elicitation (agent cannot prompt user for input)')
116
119
  .option('-c, --continue', 'Continue most recent session (CLI mode)')
117
120
  .option('-r, --resume <sessionId>', 'Resume a session by ID (CLI mode)')
@@ -343,6 +346,9 @@ async function bootstrapAgentFromGlobalOpts(options) {
343
346
  console.error(err.message);
344
347
  }
345
348
  console.error(`💡 Install it with: dexto image install ${imageName}`);
349
+ if (isHeadlessRun) {
350
+ throw new Error(`Failed to load image '${imageName}'`, { cause: err });
351
+ }
346
352
  safeExit('bootstrap', 1, 'image-load-failed');
347
353
  }
348
354
  const configWithImageDefaults = applyImageDefaults(mergedConfig, image.defaults);
@@ -361,13 +367,6 @@ async function bootstrapAgentFromGlobalOpts(options) {
361
367
  transports: [{ type: 'silent' }],
362
368
  };
363
369
  }
364
- // Override approval config for non-interactive commands.
365
- // Headless operations default to auto-approve and disable elicitation to
366
- // avoid waiting for interactive approval handlers.
367
- enrichedConfig.permissions = {
368
- ...(enrichedConfig.permissions ?? {}),
369
- mode: 'auto-approve',
370
- };
371
370
  enrichedConfig.elicitation = {
372
371
  enabled: false,
373
372
  ...(enrichedConfig.elicitation?.timeout !== undefined && {
@@ -385,6 +384,7 @@ async function bootstrapAgentFromGlobalOpts(options) {
385
384
  authResolver: createModelAuthResolver(),
386
385
  },
387
386
  }));
387
+ agent.setApprovalHandler((request) => handleHeadlessApproval(request, agent, undefined));
388
388
  await agent.start();
389
389
  await (await import('./utils/workspace.js')).applyWorkspaceToAgent(agent, workspaceRoot);
390
390
  // Register graceful shutdown
@@ -411,6 +411,7 @@ registerSessionCommand(runtimeCommandContext);
411
411
  registerSearchCommand(runtimeCommandContext);
412
412
  registerAuthCommand(runtimeCommandContext);
413
413
  registerBillingCommand(runtimeCommandContext);
414
+ registerCloudCommand(program);
414
415
  registerMcpCommand({ program });
415
416
  // 13) Main dexto CLI - Interactive (CLI) or run in other modes (--mode web/server/mcp)
416
417
  program
@@ -1,3 +1,5 @@
1
+ /** Read an environment value from before CLI dotenv loading. */
2
+ export declare function getIncomingEnvironmentVariable(name: string): string | undefined;
1
3
  /**
2
4
  * Multi-layer environment variable loading with context awareness.
3
5
  * Loads environment variables in priority order:
@@ -1 +1 @@
1
- {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/utils/env.ts"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC1C,SAAS,GAAE,MAAsB,GAClC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgDjC;AAED;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CAChD,SAAS,GAAE,MAAsB,GAClC,OAAO,CAAC,IAAI,CAAC,CAKf"}
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/utils/env.ts"],"names":[],"mappings":"AAWA,gEAAgE;AAChE,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAE/E;AAED;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC1C,SAAS,GAAE,MAAsB,GAClC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgDjC;AAED;;;;;;GAMG;AACH,wBAAsB,8BAA8B,CAChD,SAAS,GAAE,MAAsB,GAClC,OAAO,CAAC,IAAI,CAAC,CAMf"}
package/dist/utils/env.js CHANGED
@@ -2,6 +2,11 @@ import * as path from 'path';
2
2
  import { homedir } from 'os';
3
3
  import dotenv from 'dotenv';
4
4
  import { getExecutionContext, ensureDextoGlobalDirectory, getDextoEnvPath, } from '@dexto/agent-management';
5
+ let incomingEnvironment;
6
+ /** Read an environment value from before CLI dotenv loading. */
7
+ export function getIncomingEnvironmentVariable(name) {
8
+ return (incomingEnvironment ?? process.env)[name];
9
+ }
5
10
  /**
6
11
  * Multi-layer environment variable loading with context awareness.
7
12
  * Loads environment variables in priority order:
@@ -67,6 +72,7 @@ export async function loadEnvironmentVariables(startPath = process.cwd()) {
67
72
  * @param startPath Starting directory for project detection
68
73
  */
69
74
  export async function applyLayeredEnvironmentLoading(startPath = process.cwd()) {
75
+ incomingEnvironment = { ...process.env };
70
76
  await ensureDextoGlobalDirectory();
71
77
  const layeredEnv = await loadEnvironmentVariables(startPath);
72
78
  Object.assign(process.env, layeredEnv);
@@ -13,6 +13,6 @@ export interface GracefulShutdownOptions {
13
13
  */
14
14
  forceExitTimeout?: number;
15
15
  }
16
- export declare function registerGracefulShutdown(getCurrentAgent: () => ShutdownTarget, options?: GracefulShutdownOptions): void;
16
+ export declare function registerGracefulShutdown(getCurrentAgent: () => ShutdownTarget, options?: GracefulShutdownOptions): () => void;
17
17
  export {};
18
18
  //# sourceMappingURL=graceful-shutdown.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"graceful-shutdown.d.ts","sourceRoot":"","sources":["../../src/utils/graceful-shutdown.ts"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACpB,IAAI,CAAC,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,uBAAuB;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,wBAAwB,CACpC,eAAe,EAAE,MAAM,cAAc,EACrC,OAAO,GAAE,uBAA4B,GACtC,IAAI,CAmHN"}
1
+ {"version":3,"file":"graceful-shutdown.d.ts","sourceRoot":"","sources":["../../src/utils/graceful-shutdown.ts"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACpB,IAAI,CAAC,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,uBAAuB;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,wBAAwB,CACpC,eAAe,EAAE,MAAM,cAAc,EACrC,OAAO,GAAE,uBAA4B,GACtC,MAAM,IAAI,CAoIZ"}
@@ -24,13 +24,19 @@ export function registerGracefulShutdown(getCurrentAgent, options = {}) {
24
24
  process.exit(1);
25
25
  }
26
26
  };
27
- signals.forEach((signal) => {
28
- process.on(signal, () => performShutdown(signal));
27
+ const signalListeners = signals.map((signal) => {
28
+ const listener = () => {
29
+ void performShutdown(signal);
30
+ };
31
+ process.on(signal, listener);
32
+ return { signal, listener };
29
33
  });
34
+ let sigintListener;
35
+ let resetTimer;
30
36
  // In ink mode, handle SIGINT specially - allow first one to pass through to Ink
31
37
  if (inkMode) {
32
38
  let firstSigintTime = null;
33
- process.on('SIGINT', () => {
39
+ sigintListener = () => {
34
40
  const now = Date.now();
35
41
  // If already shutting down, ignore
36
42
  if (isShuttingDown)
@@ -39,7 +45,7 @@ export function registerGracefulShutdown(getCurrentAgent, options = {}) {
39
45
  if (firstSigintTime === null) {
40
46
  firstSigintTime = now;
41
47
  // Set timeout to clear the "first sigint" state
42
- setTimeout(() => {
48
+ resetTimer = setTimeout(() => {
43
49
  if (firstSigintTime !== null &&
44
50
  Date.now() - firstSigintTime >= forceExitTimeout) {
45
51
  firstSigintTime = null;
@@ -56,10 +62,11 @@ export function registerGracefulShutdown(getCurrentAgent, options = {}) {
56
62
  // Timeout expired, treat as new first SIGINT
57
63
  firstSigintTime = now;
58
64
  }
59
- });
65
+ };
66
+ process.on('SIGINT', sigintListener);
60
67
  }
61
68
  // Handle uncaught exceptions
62
- process.on('uncaughtException', async (error) => {
69
+ const exceptionListener = async (error) => {
63
70
  logger.error(`Uncaught exception: ${error instanceof Error ? error.message : String(error)}`, { error }, 'red');
64
71
  if (!isShuttingDown) {
65
72
  isShuttingDown = true;
@@ -74,8 +81,9 @@ export function registerGracefulShutdown(getCurrentAgent, options = {}) {
74
81
  }
75
82
  }
76
83
  process.exit(1);
77
- });
78
- process.on('unhandledRejection', async (reason) => {
84
+ };
85
+ process.on('uncaughtException', exceptionListener);
86
+ const rejectionListener = async (reason) => {
79
87
  logger.error(`Unhandled rejection: ${reason}`, { reason }, 'red');
80
88
  if (!isShuttingDown) {
81
89
  isShuttingDown = true;
@@ -90,5 +98,16 @@ export function registerGracefulShutdown(getCurrentAgent, options = {}) {
90
98
  }
91
99
  }
92
100
  process.exit(1);
93
- });
101
+ };
102
+ process.on('unhandledRejection', rejectionListener);
103
+ return () => {
104
+ for (const { signal, listener } of signalListeners)
105
+ process.off(signal, listener);
106
+ if (sigintListener)
107
+ process.off('SIGINT', sigintListener);
108
+ if (resetTimer)
109
+ clearTimeout(resetTimer);
110
+ process.off('uncaughtException', exceptionListener);
111
+ process.off('unhandledRejection', rejectionListener);
112
+ };
94
113
  }
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "dexto",
3
- "version": "1.13.4",
3
+ "version": "1.14.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "dexto": "./dist/index.js"
7
7
  },
8
8
  "dependencies": {
9
9
  "@clack/prompts": "^0.10.1",
10
- "@modelcontextprotocol/sdk": "^1.28.0",
10
+ "@modelcontextprotocol/sdk": "^1.32.1",
11
11
  "@opentelemetry/instrumentation-http": "^0.210.0",
12
12
  "@opentelemetry/instrumentation-undici": "^0.20.0",
13
13
  "@opentelemetry/core": "^1.28.0",
@@ -34,18 +34,18 @@
34
34
  "ws": "^8.18.1",
35
35
  "yaml": "^2.8.3",
36
36
  "zod": "^4.3.6",
37
- "@dexto/agent-config": "1.13.4",
38
- "@dexto/agent-management": "1.13.4",
39
- "@dexto/analytics": "1.13.4",
40
- "@dexto/client-sdk": "1.13.4",
41
- "@dexto/core": "1.13.4",
42
- "@dexto/image-local": "1.13.4",
43
- "@dexto/image-logger-agent": "1.13.4",
44
- "@dexto/llm": "1.13.4",
45
- "@dexto/registry": "1.13.4",
46
- "@dexto/server": "1.13.4",
47
- "@dexto/storage": "1.13.4",
48
- "@dexto/tui": "1.13.4"
37
+ "@dexto/agent-config": "1.14.0",
38
+ "@dexto/agent-management": "1.14.0",
39
+ "@dexto/analytics": "1.14.0",
40
+ "@dexto/client-sdk": "1.14.0",
41
+ "@dexto/core": "1.14.0",
42
+ "@dexto/image-local": "1.14.0",
43
+ "@dexto/image-logger-agent": "1.14.0",
44
+ "@dexto/llm": "1.14.0",
45
+ "@dexto/registry": "1.14.0",
46
+ "@dexto/server": "1.14.0",
47
+ "@dexto/storage": "1.14.0",
48
+ "@dexto/tui": "1.14.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/ws": "^8.5.11",