dexto 1.1.10 → 1.1.11

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 (152) hide show
  1. package/README.md +4 -2
  2. package/dist/agents/agent-registry.json +30 -1
  3. package/dist/agents/database-agent/database-agent.yml +3 -0
  4. package/dist/agents/default-agent.yml +102 -12
  5. package/dist/agents/github-agent/github-agent.yml +3 -0
  6. package/dist/agents/image-editor-agent/image-editor-agent.yml +3 -0
  7. package/dist/agents/music-agent/music-agent.yml +3 -0
  8. package/dist/agents/nano-banana-agent/nano-banana-agent.yml +3 -0
  9. package/dist/agents/podcast-agent/podcast-agent.yml +3 -0
  10. package/dist/agents/product-name-researcher/product-name-researcher.yml +3 -0
  11. package/dist/agents/talk2pdf-agent/talk2pdf-agent.yml +3 -0
  12. package/dist/agents/triage-demo/triage-agent.yml +3 -0
  13. package/dist/api/mcp/tool-aggregation-handler.d.ts.map +1 -1
  14. package/dist/api/mcp/tool-aggregation-handler.js +34 -42
  15. package/dist/api/memory/memory-handler.d.ts +15 -0
  16. package/dist/api/memory/memory-handler.d.ts.map +1 -0
  17. package/dist/api/memory/memory-handler.js +129 -0
  18. package/dist/api/server.d.ts +2 -2
  19. package/dist/api/server.d.ts.map +1 -1
  20. package/dist/api/server.js +987 -231
  21. package/dist/api/webhook-subscriber.d.ts.map +1 -1
  22. package/dist/api/webhook-subscriber.js +2 -1
  23. package/dist/api/websocket-subscriber.d.ts.map +1 -1
  24. package/dist/api/websocket-subscriber.js +61 -10
  25. package/dist/cli/cli-subscriber.d.ts +2 -1
  26. package/dist/cli/cli-subscriber.d.ts.map +1 -1
  27. package/dist/cli/cli-subscriber.js +11 -3
  28. package/dist/cli/cli.d.ts.map +1 -1
  29. package/dist/cli/cli.js +1 -0
  30. package/dist/cli/commands/install.d.ts +3 -3
  31. package/dist/cli/commands/install.d.ts.map +1 -1
  32. package/dist/cli/commands/install.js +223 -41
  33. package/dist/cli/commands/interactive-commands/prompt-commands.d.ts +8 -1
  34. package/dist/cli/commands/interactive-commands/prompt-commands.d.ts.map +1 -1
  35. package/dist/cli/commands/interactive-commands/prompt-commands.js +252 -4
  36. package/dist/cli/commands/list-agents.d.ts.map +1 -1
  37. package/dist/cli/commands/list-agents.js +22 -3
  38. package/dist/cli/commands/setup.d.ts +4 -4
  39. package/dist/cli/commands/uninstall.d.ts +1 -1
  40. package/dist/cli/tool-confirmation/cli-confirmation-handler.d.ts +36 -7
  41. package/dist/cli/tool-confirmation/cli-confirmation-handler.d.ts.map +1 -1
  42. package/dist/cli/tool-confirmation/cli-confirmation-handler.js +314 -34
  43. package/dist/index.js +53 -46
  44. package/dist/webui/.next/standalone/.next/static/VoeDi3iuGmMdZu_kx-R2X/_buildManifest.js +1 -0
  45. package/dist/webui/.next/standalone/.next/static/chunks/419-5526a47c95a2fa60.js +1 -0
  46. package/dist/webui/.next/standalone/.next/static/chunks/429-838829c1391e496d.js +25 -0
  47. package/dist/webui/.next/standalone/.next/static/chunks/459-62011998b002cbf6.js +1 -0
  48. package/dist/webui/.next/standalone/.next/static/chunks/711-76a7d2bf4d6f69e5.js +1 -0
  49. package/dist/webui/.next/standalone/.next/static/chunks/854-8cad9404fc78e0cc.js +1 -0
  50. package/dist/webui/.next/standalone/.next/static/chunks/935-07f9df196b13275e.js +1 -0
  51. package/dist/webui/.next/standalone/.next/static/chunks/app/chat/[sessionId]/page-b8acc47b0d8c5c0a.js +1 -0
  52. package/dist/webui/.next/standalone/.next/static/chunks/app/layout-f4a6ee5a028899d1.js +1 -0
  53. package/dist/webui/.next/standalone/.next/static/chunks/app/page-e117ae372850d25f.js +1 -0
  54. package/dist/webui/.next/standalone/.next/static/chunks/app/playground/page-09340fb6b3f4caa2.js +1 -0
  55. package/dist/webui/.next/standalone/.next/static/chunks/{webpack-7c234e7e7e272295.js → webpack-7229fd0786f0483c.js} +1 -1
  56. package/dist/webui/.next/standalone/.next/static/css/21e6c142ca3cdc42.css +1 -0
  57. package/dist/webui/.next/standalone/.next/static/css/de70bee13400563f.css +1 -0
  58. package/dist/webui/.next/standalone/package.json +6 -2
  59. package/dist/webui/.next/standalone/packages/webui/.next/BUILD_ID +1 -1
  60. package/dist/webui/.next/standalone/packages/webui/.next/app-build-manifest.json +30 -15
  61. package/dist/webui/.next/standalone/packages/webui/.next/app-path-routes-manifest.json +1 -0
  62. package/dist/webui/.next/standalone/packages/webui/.next/build-manifest.json +5 -5
  63. package/dist/webui/.next/standalone/packages/webui/.next/prerender-manifest.json +3 -3
  64. package/dist/webui/.next/standalone/packages/webui/.next/required-server-files.json +1 -1
  65. package/dist/webui/.next/standalone/packages/webui/.next/routes-manifest.json +10 -1
  66. package/dist/webui/.next/standalone/packages/webui/.next/server/app/_not-found/page.js +1 -1
  67. package/dist/webui/.next/standalone/packages/webui/.next/server/app/_not-found/page.js.nft.json +1 -1
  68. package/dist/webui/.next/standalone/packages/webui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  69. package/dist/webui/.next/standalone/packages/webui/.next/server/app/chat/[sessionId]/page.js +2 -0
  70. package/dist/webui/.next/standalone/packages/webui/.next/server/app/chat/[sessionId]/page.js.nft.json +1 -0
  71. package/dist/webui/.next/standalone/packages/webui/.next/server/app/chat/[sessionId]/page_client-reference-manifest.js +1 -0
  72. package/dist/webui/.next/standalone/packages/webui/.next/server/app/page.js +2 -11
  73. package/dist/webui/.next/standalone/packages/webui/.next/server/app/page.js.nft.json +1 -1
  74. package/dist/webui/.next/standalone/packages/webui/.next/server/app/page_client-reference-manifest.js +1 -1
  75. package/dist/webui/.next/standalone/packages/webui/.next/server/app/playground/page.js +4 -4
  76. package/dist/webui/.next/standalone/packages/webui/.next/server/app/playground/page.js.nft.json +1 -1
  77. package/dist/webui/.next/standalone/packages/webui/.next/server/app/playground/page_client-reference-manifest.js +1 -1
  78. package/dist/webui/.next/standalone/packages/webui/.next/server/app-paths-manifest.json +1 -0
  79. package/dist/webui/.next/standalone/packages/webui/.next/server/chunks/1.js +12 -0
  80. package/dist/webui/.next/standalone/packages/webui/.next/server/chunks/419.js +25 -0
  81. package/dist/webui/.next/standalone/packages/webui/.next/server/chunks/{619.js → 426.js} +2 -2
  82. package/dist/webui/.next/standalone/packages/webui/.next/server/chunks/43.js +1 -1
  83. package/dist/webui/.next/standalone/packages/webui/.next/server/chunks/654.js +1 -0
  84. package/dist/webui/.next/standalone/packages/webui/.next/server/chunks/71.js +5 -0
  85. package/dist/webui/.next/standalone/packages/webui/.next/server/middleware-build-manifest.js +1 -1
  86. package/dist/webui/.next/standalone/packages/webui/.next/server/pages/500.html +1 -1
  87. package/dist/webui/.next/standalone/packages/webui/.next/server/pages-manifest.json +1 -1
  88. package/dist/webui/.next/standalone/packages/webui/.next/server/server-reference-manifest.json +1 -1
  89. package/dist/webui/.next/standalone/packages/webui/.next/static/VoeDi3iuGmMdZu_kx-R2X/_buildManifest.js +1 -0
  90. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/419-5526a47c95a2fa60.js +1 -0
  91. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/429-838829c1391e496d.js +25 -0
  92. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/459-62011998b002cbf6.js +1 -0
  93. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/711-76a7d2bf4d6f69e5.js +1 -0
  94. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/854-8cad9404fc78e0cc.js +1 -0
  95. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/935-07f9df196b13275e.js +1 -0
  96. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/app/chat/[sessionId]/page-b8acc47b0d8c5c0a.js +1 -0
  97. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/app/layout-f4a6ee5a028899d1.js +1 -0
  98. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/app/page-e117ae372850d25f.js +1 -0
  99. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/app/playground/page-09340fb6b3f4caa2.js +1 -0
  100. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/{webpack-7c234e7e7e272295.js → webpack-7229fd0786f0483c.js} +1 -1
  101. package/dist/webui/.next/standalone/packages/webui/.next/static/css/21e6c142ca3cdc42.css +1 -0
  102. package/dist/webui/.next/standalone/packages/webui/.next/static/css/de70bee13400563f.css +1 -0
  103. package/dist/webui/.next/standalone/packages/webui/package.json +7 -4
  104. package/dist/webui/.next/standalone/packages/webui/server.js +1 -1
  105. package/dist/webui/.next/static/VoeDi3iuGmMdZu_kx-R2X/_buildManifest.js +1 -0
  106. package/dist/webui/.next/static/chunks/419-5526a47c95a2fa60.js +1 -0
  107. package/dist/webui/.next/static/chunks/429-838829c1391e496d.js +25 -0
  108. package/dist/webui/.next/static/chunks/459-62011998b002cbf6.js +1 -0
  109. package/dist/webui/.next/static/chunks/711-76a7d2bf4d6f69e5.js +1 -0
  110. package/dist/webui/.next/static/chunks/854-8cad9404fc78e0cc.js +1 -0
  111. package/dist/webui/.next/static/chunks/935-07f9df196b13275e.js +1 -0
  112. package/dist/webui/.next/static/chunks/app/chat/[sessionId]/page-b8acc47b0d8c5c0a.js +1 -0
  113. package/dist/webui/.next/static/chunks/app/layout-f4a6ee5a028899d1.js +1 -0
  114. package/dist/webui/.next/static/chunks/app/page-e117ae372850d25f.js +1 -0
  115. package/dist/webui/.next/static/chunks/app/playground/page-09340fb6b3f4caa2.js +1 -0
  116. package/dist/webui/.next/static/chunks/{webpack-7c234e7e7e272295.js → webpack-7229fd0786f0483c.js} +1 -1
  117. package/dist/webui/.next/static/css/21e6c142ca3cdc42.css +1 -0
  118. package/dist/webui/.next/static/css/de70bee13400563f.css +1 -0
  119. package/dist/webui/package.json +7 -4
  120. package/package.json +5 -4
  121. package/dist/webui/.next/standalone/.next/static/PvkEd_BO6ZXxX99T_gUvs/_buildManifest.js +0 -1
  122. package/dist/webui/.next/standalone/.next/static/chunks/179-78abc2eacbc41da9.js +0 -1
  123. package/dist/webui/.next/standalone/.next/static/chunks/442-b1916bec348454b3.js +0 -1
  124. package/dist/webui/.next/standalone/.next/static/chunks/544-c4a8f278ed1a25d7.js +0 -1
  125. package/dist/webui/.next/standalone/.next/static/chunks/854-2a6d5a5297a15d52.js +0 -1
  126. package/dist/webui/.next/standalone/.next/static/chunks/app/layout-dde711766eda096b.js +0 -1
  127. package/dist/webui/.next/standalone/.next/static/chunks/app/page-5e94d5a49dc718d0.js +0 -1
  128. package/dist/webui/.next/standalone/.next/static/chunks/app/playground/page-9ae40e0b219583e3.js +0 -1
  129. package/dist/webui/.next/standalone/.next/static/css/045cc65741e38fbd.css +0 -3
  130. package/dist/webui/.next/standalone/packages/webui/.next/server/chunks/549.js +0 -1
  131. package/dist/webui/.next/standalone/packages/webui/.next/server/chunks/950.js +0 -5
  132. package/dist/webui/.next/standalone/packages/webui/.next/static/PvkEd_BO6ZXxX99T_gUvs/_buildManifest.js +0 -1
  133. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/179-78abc2eacbc41da9.js +0 -1
  134. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/442-b1916bec348454b3.js +0 -1
  135. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/544-c4a8f278ed1a25d7.js +0 -1
  136. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/854-2a6d5a5297a15d52.js +0 -1
  137. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/app/layout-dde711766eda096b.js +0 -1
  138. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/app/page-5e94d5a49dc718d0.js +0 -1
  139. package/dist/webui/.next/standalone/packages/webui/.next/static/chunks/app/playground/page-9ae40e0b219583e3.js +0 -1
  140. package/dist/webui/.next/standalone/packages/webui/.next/static/css/045cc65741e38fbd.css +0 -3
  141. package/dist/webui/.next/static/PvkEd_BO6ZXxX99T_gUvs/_buildManifest.js +0 -1
  142. package/dist/webui/.next/static/chunks/179-78abc2eacbc41da9.js +0 -1
  143. package/dist/webui/.next/static/chunks/442-b1916bec348454b3.js +0 -1
  144. package/dist/webui/.next/static/chunks/544-c4a8f278ed1a25d7.js +0 -1
  145. package/dist/webui/.next/static/chunks/854-2a6d5a5297a15d52.js +0 -1
  146. package/dist/webui/.next/static/chunks/app/layout-dde711766eda096b.js +0 -1
  147. package/dist/webui/.next/static/chunks/app/page-5e94d5a49dc718d0.js +0 -1
  148. package/dist/webui/.next/static/chunks/app/playground/page-9ae40e0b219583e3.js +0 -1
  149. package/dist/webui/.next/static/css/045cc65741e38fbd.css +0 -3
  150. /package/dist/webui/.next/standalone/.next/static/{PvkEd_BO6ZXxX99T_gUvs → VoeDi3iuGmMdZu_kx-R2X}/_ssgManifest.js +0 -0
  151. /package/dist/webui/.next/standalone/packages/webui/.next/static/{PvkEd_BO6ZXxX99T_gUvs → VoeDi3iuGmMdZu_kx-R2X}/_ssgManifest.js +0 -0
  152. /package/dist/webui/.next/static/{PvkEd_BO6ZXxX99T_gUvs → VoeDi3iuGmMdZu_kx-R2X}/_ssgManifest.js +0 -0
@@ -1,10 +1,10 @@
1
- import { logger } from '@dexto/core';
1
+ import { logger, ApprovalType, ApprovalStatus } from '@dexto/core';
2
2
  import * as readline from 'readline';
3
3
  import chalk from 'chalk';
4
4
  import boxen from 'boxen';
5
5
  /**
6
- * CLI-specific subscriber for tool confirmation events
7
- * Implements EventSubscriber pattern to listen to AgentEventBus for tool confirmation requests
6
+ * CLI-specific subscriber for approval events
7
+ * Implements EventSubscriber pattern to listen to AgentEventBus for approval requests
8
8
  */
9
9
  export class CLIToolConfirmationSubscriber {
10
10
  agentEventBus;
@@ -12,54 +12,334 @@ export class CLIToolConfirmationSubscriber {
12
12
  // No configuration needed - CLI always shows interactive prompts
13
13
  }
14
14
  /**
15
- * Subscribe to tool confirmation events on the AgentEventBus
15
+ * Subscribe to approval events on the AgentEventBus
16
16
  */
17
17
  subscribe(eventBus) {
18
18
  this.agentEventBus = eventBus;
19
- this.agentEventBus.on('dexto:toolConfirmationRequest', this.handleConfirmationRequest.bind(this));
19
+ this.agentEventBus.on('dexto:approvalRequest', this.handleApprovalRequest.bind(this));
20
20
  }
21
21
  /**
22
- * Handle tool confirmation request events from the AgentEventBus
22
+ * Handle approval request events from the AgentEventBus
23
23
  */
24
- async handleConfirmationRequest(event) {
24
+ async handleApprovalRequest(event) {
25
25
  try {
26
- logger.info(`Handling tool confirmation request for ${event.toolName}, executionId: ${event.executionId}`);
27
- // Display tool call using the logger's built-in method
28
- logger.toolCall(event.toolName, event.args);
29
- // Collect user input with arrow key navigation
30
- const approved = await this.collectArrowKeyInput();
31
- // Send response back via AgentEventBus
32
- const response = {
33
- executionId: event.executionId,
34
- approved,
35
- rememberChoice: false, // CLI won't persist choice
36
- ...(event.sessionId && { sessionId: event.sessionId }),
37
- };
38
- this.sendConfirmationResponse(response);
39
- if (!approved) {
40
- logger.warn(`Tool '${event.toolName}' execution denied`);
26
+ if (event.type === ApprovalType.TOOL_CONFIRMATION) {
27
+ await this.handleToolConfirmation(event);
28
+ }
29
+ else if (event.type === ApprovalType.ELICITATION) {
30
+ await this.handleElicitation(event);
31
+ }
32
+ else {
33
+ logger.debug(`[CLI] Ignoring unsupported approval type: ${event.type}`);
41
34
  }
42
35
  }
43
36
  catch (error) {
44
- logger.error(`Error handling tool confirmation request: ${error}`);
37
+ // Use structured logging to preserve error stack and metadata
38
+ logger.error(`Error handling approval request: ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? { error } : undefined);
45
39
  // Send denial response on error
46
- this.sendConfirmationResponse({
47
- executionId: event.executionId,
48
- approved: false,
49
- ...(event.sessionId && { sessionId: event.sessionId }),
50
- });
40
+ const errorResponse = {
41
+ approvalId: event.approvalId,
42
+ status: ApprovalStatus.DENIED,
43
+ };
44
+ if (event.sessionId !== undefined) {
45
+ errorResponse.sessionId = event.sessionId;
46
+ }
47
+ this.sendApprovalResponse(errorResponse);
48
+ }
49
+ }
50
+ /**
51
+ * Handle tool confirmation approval
52
+ */
53
+ async handleToolConfirmation(event) {
54
+ const toolMetadata = event.metadata;
55
+ logger.info(`Handling tool confirmation request for ${toolMetadata.toolName}, approvalId: ${event.approvalId}`);
56
+ // Display tool call using the logger's built-in method
57
+ logger.toolCall(toolMetadata.toolName, toolMetadata.args);
58
+ // Collect user input with arrow key navigation
59
+ const approved = await this.collectArrowKeyInput();
60
+ // Send response back via AgentEventBus
61
+ const response = {
62
+ approvalId: event.approvalId,
63
+ status: approved ? ApprovalStatus.APPROVED : ApprovalStatus.DENIED,
64
+ data: {
65
+ rememberChoice: false, // CLI won't persist choice
66
+ },
67
+ };
68
+ if (event.sessionId !== undefined) {
69
+ response.sessionId = event.sessionId;
70
+ }
71
+ this.sendApprovalResponse(response);
72
+ if (!approved) {
73
+ logger.warn(`Tool '${toolMetadata.toolName}' execution denied`);
74
+ }
75
+ }
76
+ /**
77
+ * Handle elicitation approval (form-based input from MCP servers)
78
+ */
79
+ async handleElicitation(event) {
80
+ const elicitationMetadata = event.metadata;
81
+ logger.info(`Handling elicitation request from MCP server '${elicitationMetadata.serverName}', approvalId: ${event.approvalId}`);
82
+ // Display the elicitation prompt
83
+ console.log('\n' +
84
+ boxen(chalk.cyan.bold('📝 Information Request from MCP Server'), {
85
+ padding: 1,
86
+ margin: 1,
87
+ borderStyle: 'round',
88
+ borderColor: 'cyan',
89
+ }));
90
+ console.log(chalk.white(`Server: ${chalk.yellow(elicitationMetadata.serverName)}`));
91
+ console.log(chalk.white(`Message: ${chalk.white(elicitationMetadata.prompt)}\n`));
92
+ // Collect form data based on schema
93
+ const formData = await this.collectFormData(elicitationMetadata.schema);
94
+ if (formData === null) {
95
+ // User cancelled
96
+ const cancelResponse = {
97
+ approvalId: event.approvalId,
98
+ status: ApprovalStatus.CANCELLED,
99
+ };
100
+ if (event.sessionId !== undefined) {
101
+ cancelResponse.sessionId = event.sessionId;
102
+ }
103
+ this.sendApprovalResponse(cancelResponse);
104
+ logger.info('Elicitation cancelled by user');
51
105
  }
106
+ else {
107
+ // User provided data
108
+ const response = {
109
+ approvalId: event.approvalId,
110
+ status: ApprovalStatus.APPROVED,
111
+ data: { formData },
112
+ };
113
+ if (event.sessionId !== undefined) {
114
+ response.sessionId = event.sessionId;
115
+ }
116
+ this.sendApprovalResponse(response);
117
+ logger.info('Elicitation completed successfully');
118
+ }
119
+ }
120
+ /**
121
+ * Collect form data based on JSON Schema
122
+ * Returns null if user cancels
123
+ */
124
+ async collectFormData(schema) {
125
+ const formData = {};
126
+ if (!schema.properties || typeof schema.properties !== 'object') {
127
+ logger.warn('Invalid schema: no properties found');
128
+ return null;
129
+ }
130
+ const properties = schema.properties;
131
+ const required = schema.required || [];
132
+ for (const [fieldName, fieldSchema] of Object.entries(properties)) {
133
+ const field = fieldSchema;
134
+ const isRequired = required.includes(fieldName);
135
+ const fieldType = field.type || 'string';
136
+ // Display field prompt
137
+ const requiredLabel = isRequired ? chalk.red('*') : '';
138
+ console.log(chalk.cyan(`${fieldName}${requiredLabel}`) +
139
+ (field.description ? chalk.gray(` - ${field.description}`) : ''));
140
+ // Collect input based on field type
141
+ let value;
142
+ if (fieldType === 'boolean') {
143
+ value = await this.collectBooleanInput(fieldName, isRequired);
144
+ }
145
+ else if (fieldType === 'number' || fieldType === 'integer') {
146
+ value = await this.collectNumberInput(fieldName, fieldType === 'integer', isRequired);
147
+ }
148
+ else if (field.enum && Array.isArray(field.enum)) {
149
+ value = await this.collectEnumInput(fieldName, field.enum, isRequired);
150
+ }
151
+ else {
152
+ // Default to string input
153
+ value = await this.collectStringInput(fieldName, isRequired);
154
+ }
155
+ if (value === null) {
156
+ // User cancelled
157
+ return null;
158
+ }
159
+ // Only assign if value is not undefined (allows skipping optional fields)
160
+ if (value !== undefined) {
161
+ formData[fieldName] = value;
162
+ }
163
+ }
164
+ return formData;
165
+ }
166
+ /**
167
+ * Collect string input from user
168
+ */
169
+ collectStringInput(fieldName, required) {
170
+ return new Promise((resolve) => {
171
+ const rl = readline.createInterface({
172
+ input: process.stdin,
173
+ output: process.stdout,
174
+ });
175
+ const prompt = required
176
+ ? `${fieldName}: `
177
+ : `${fieldName} (optional, press Enter to skip): `;
178
+ rl.question(prompt, (answer) => {
179
+ rl.close();
180
+ if (answer.toLowerCase() === 'cancel') {
181
+ resolve(null);
182
+ return;
183
+ }
184
+ if (!answer && required) {
185
+ console.log(chalk.red('This field is required'));
186
+ resolve(this.collectStringInput(fieldName, required));
187
+ return;
188
+ }
189
+ // Return undefined for optional skipped fields, empty string for provided empty input
190
+ if (!answer && !required) {
191
+ resolve(undefined);
192
+ return;
193
+ }
194
+ resolve(answer);
195
+ });
196
+ });
197
+ }
198
+ /**
199
+ * Collect boolean input from user (yes/no)
200
+ */
201
+ collectBooleanInput(fieldName, required) {
202
+ return new Promise((resolve) => {
203
+ const rl = readline.createInterface({
204
+ input: process.stdin,
205
+ output: process.stdout,
206
+ });
207
+ const prompt = required
208
+ ? `${fieldName} (yes/no): `
209
+ : `${fieldName} (yes/no, press Enter to skip): `;
210
+ rl.question(prompt, (answer) => {
211
+ rl.close();
212
+ if (answer.toLowerCase() === 'cancel') {
213
+ resolve(null);
214
+ return;
215
+ }
216
+ const normalized = answer.toLowerCase().trim();
217
+ // Allow skipping optional fields
218
+ if (!normalized && !required) {
219
+ resolve(undefined);
220
+ return;
221
+ }
222
+ if (!normalized && required) {
223
+ console.log(chalk.red('This field is required'));
224
+ resolve(this.collectBooleanInput(fieldName, required));
225
+ return;
226
+ }
227
+ if (normalized === 'yes' || normalized === 'y' || normalized === 'true') {
228
+ resolve(true);
229
+ }
230
+ else if (normalized === 'no' || normalized === 'n' || normalized === 'false') {
231
+ resolve(false);
232
+ }
233
+ else {
234
+ console.log(chalk.red('Please answer yes or no'));
235
+ resolve(this.collectBooleanInput(fieldName, required));
236
+ }
237
+ });
238
+ });
239
+ }
240
+ /**
241
+ * Collect number input from user
242
+ */
243
+ collectNumberInput(fieldName, integer, required) {
244
+ return new Promise((resolve) => {
245
+ const rl = readline.createInterface({
246
+ input: process.stdin,
247
+ output: process.stdout,
248
+ });
249
+ const type = integer ? 'integer' : 'number';
250
+ const prompt = required
251
+ ? `${fieldName} (${type}): `
252
+ : `${fieldName} (${type}, press Enter to skip): `;
253
+ rl.question(prompt, (answer) => {
254
+ rl.close();
255
+ if (answer.toLowerCase() === 'cancel') {
256
+ resolve(null);
257
+ return;
258
+ }
259
+ // Allow skipping optional fields
260
+ if (!answer.trim() && !required) {
261
+ resolve(undefined);
262
+ return;
263
+ }
264
+ if (!answer.trim() && required) {
265
+ console.log(chalk.red('This field is required'));
266
+ resolve(this.collectNumberInput(fieldName, integer, required));
267
+ return;
268
+ }
269
+ const num = Number(answer);
270
+ if (isNaN(num)) {
271
+ console.log(chalk.red(`Please enter a valid ${type}`));
272
+ resolve(this.collectNumberInput(fieldName, integer, required));
273
+ return;
274
+ }
275
+ if (integer && !Number.isInteger(num)) {
276
+ console.log(chalk.red('Please enter an integer'));
277
+ resolve(this.collectNumberInput(fieldName, integer, required));
278
+ return;
279
+ }
280
+ resolve(num);
281
+ });
282
+ });
283
+ }
284
+ /**
285
+ * Collect enum input from user (select from list)
286
+ */
287
+ collectEnumInput(fieldName, options, required) {
288
+ return new Promise((resolve) => {
289
+ console.log(chalk.gray('Available options:'));
290
+ options.forEach((option, index) => {
291
+ console.log(chalk.gray(` ${index + 1}. ${option}`));
292
+ });
293
+ const rl = readline.createInterface({
294
+ input: process.stdin,
295
+ output: process.stdout,
296
+ });
297
+ const prompt = required
298
+ ? `${fieldName} (enter number or value): `
299
+ : `${fieldName} (enter number or value, press Enter to skip): `;
300
+ rl.question(prompt, (answer) => {
301
+ rl.close();
302
+ if (answer.toLowerCase() === 'cancel') {
303
+ resolve(null);
304
+ return;
305
+ }
306
+ // Allow skipping optional fields
307
+ if (!answer.trim() && !required) {
308
+ resolve(undefined);
309
+ return;
310
+ }
311
+ if (!answer.trim() && required) {
312
+ console.log(chalk.red('This field is required'));
313
+ resolve(this.collectEnumInput(fieldName, options, required));
314
+ return;
315
+ }
316
+ // Try as index first
317
+ const index = parseInt(answer) - 1;
318
+ if (!isNaN(index) && index >= 0 && index < options.length) {
319
+ resolve(options[index]);
320
+ return;
321
+ }
322
+ // Try as direct value
323
+ const directMatch = options.find((opt) => String(opt) === answer);
324
+ if (directMatch !== undefined) {
325
+ resolve(directMatch);
326
+ return;
327
+ }
328
+ console.log(chalk.red('Invalid selection'));
329
+ resolve(this.collectEnumInput(fieldName, options, required));
330
+ });
331
+ });
52
332
  }
53
333
  /**
54
- * Send confirmation response via AgentEventBus
334
+ * Send approval response via AgentEventBus
55
335
  */
56
- sendConfirmationResponse(response) {
336
+ sendApprovalResponse(response) {
57
337
  if (!this.agentEventBus) {
58
- logger.error('AgentEventBus not available for sending confirmation response');
338
+ logger.error('AgentEventBus not available for sending approval response');
59
339
  return;
60
340
  }
61
- logger.debug(`CLI sending toolConfirmationResponse for executionId ${response.executionId}, approved=${response.approved}, sessionId=${response.sessionId}`);
62
- this.agentEventBus.emit('dexto:toolConfirmationResponse', response);
341
+ logger.debug(`CLI sending approvalResponse for approvalId ${response.approvalId}, status=${response.status}, sessionId=${response.sessionId ?? 'global'}`);
342
+ this.agentEventBus.emit('dexto:approvalResponse', response);
63
343
  }
64
344
  /**
65
345
  * Collect user input with arrow key navigation
@@ -155,7 +435,7 @@ export class CLIToolConfirmationSubscriber {
155
435
  */
156
436
  cleanup() {
157
437
  if (this.agentEventBus) {
158
- this.agentEventBus.removeAllListeners('dexto:toolConfirmationRequest');
438
+ this.agentEventBus.removeAllListeners('dexto:approvalRequest');
159
439
  }
160
440
  }
161
441
  }
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ program
40
40
  .name('dexto')
41
41
  .description('AI-powered CLI and WebUI for interacting with MCP servers')
42
42
  .version(pkg.version, '-v, --version', 'output the current version')
43
- .option('-a, --agent <name|path>', 'Agent name or path to agent config file')
43
+ .option('-a, --agent <id|path>', 'Agent ID or path to agent config file')
44
44
  .option('-p, --prompt <text>', 'Run prompt and exit. Alternatively provide a single quoted string as positional argument.')
45
45
  .option('-s, --strict', 'Require all server connections to succeed')
46
46
  .option('--no-verbose', 'Disable verbose output')
@@ -156,10 +156,17 @@ program
156
156
  // 5) `install` SUB-COMMAND
157
157
  program
158
158
  .command('install [agents...]')
159
- .description('Install agents from the registry')
159
+ .description('Install agents from registry or custom YAML files/directories')
160
160
  .option('--all', 'Install all available agents from registry')
161
161
  .option('--no-inject-preferences', 'Skip injecting global preferences into installed agents')
162
162
  .option('--force', 'Force reinstall even if agent is already installed')
163
+ .addHelpText('after', `
164
+ Examples:
165
+ $ dexto install default-agent Install agent from registry
166
+ $ dexto install agent1 agent2 Install multiple registry agents
167
+ $ dexto install --all Install all available registry agents
168
+ $ dexto install ./my-agent.yml Install custom agent from YAML file
169
+ $ dexto install ./my-agent-dir/ Install custom agent from directory (interactive)`)
163
170
  .action(withAnalytics('install', async (agents = [], options) => {
164
171
  try {
165
172
  await handleInstallCommand(agents, options);
@@ -231,7 +238,7 @@ async function bootstrapAgentFromGlobalOpts() {
231
238
  const resolvedPath = await resolveAgentPath(globalOpts.agent, globalOpts.autoInstall !== false, true);
232
239
  const rawConfig = await loadAgentConfig(resolvedPath);
233
240
  const mergedConfig = applyCLIOverrides(rawConfig, globalOpts);
234
- const agent = new DextoAgent(mergedConfig, globalOpts.agent);
241
+ const agent = new DextoAgent(mergedConfig, resolvedPath);
235
242
  await agent.start();
236
243
  // Register graceful shutdown
237
244
  const shutdown = async () => {
@@ -541,51 +548,9 @@ program
541
548
  }
542
549
  }
543
550
  // DextoAgent will parse/validate again (parse-twice pattern)
544
- agent = new DextoAgent(validatedConfig, opts.agent);
551
+ agent = new DextoAgent(validatedConfig, resolvedPath);
545
552
  // Start the agent (initialize async services)
546
553
  await agent.start();
547
- // Handle session options - simplified logic
548
- if (opts.resume) {
549
- try {
550
- // Resume specific session by ID
551
- await agent.loadSessionAsDefault(opts.resume);
552
- logger.info(`Resumed session: ${opts.resume}`, null, 'cyan');
553
- }
554
- catch (err) {
555
- console.error(`❌ Failed to resume session '${opts.resume}': ${err instanceof Error ? err.message : String(err)}`);
556
- console.error('💡 Use `dexto session list` to see available sessions');
557
- safeExit('main', 1, 'resume-failed');
558
- }
559
- }
560
- else if (opts.continue) {
561
- try {
562
- // Continue from most recent session
563
- await loadMostRecentSession(agent);
564
- // If no sessions existed, create a new one to honor default-new invariant
565
- const sessionsAfter = await agent.listSessions();
566
- if (sessionsAfter.length === 0) {
567
- const session = await agent.createSession();
568
- await agent.loadSessionAsDefault(session.id);
569
- logger.info(`Created new session: ${session.id}`, null, 'green');
570
- }
571
- }
572
- catch (err) {
573
- console.error(`❌ Failed to continue session: ${err instanceof Error ? err.message : String(err)}`);
574
- safeExit('main', 1, 'continue-failed');
575
- }
576
- }
577
- else {
578
- // Default behavior: create new session
579
- try {
580
- const session = await agent.createSession();
581
- await agent.loadSessionAsDefault(session.id);
582
- logger.info(`Created new session: ${session.id}`, null, 'green');
583
- }
584
- catch (err) {
585
- console.error(`❌ Failed to create new session: ${err instanceof Error ? err.message : String(err)}`);
586
- safeExit('main', 1, 'create-session-failed');
587
- }
588
- }
589
554
  }
590
555
  catch (err) {
591
556
  if (err instanceof ExitSignal)
@@ -597,6 +562,48 @@ program
597
562
  // ——— Dispatch based on --mode ———
598
563
  switch (opts.mode) {
599
564
  case 'cli': {
565
+ // Handle session options - only for CLI mode
566
+ if (opts.resume) {
567
+ try {
568
+ // Resume specific session by ID
569
+ await agent.loadSessionAsDefault(opts.resume);
570
+ logger.info(`Resumed session: ${opts.resume}`, null, 'cyan');
571
+ }
572
+ catch (err) {
573
+ console.error(`❌ Failed to resume session '${opts.resume}': ${err instanceof Error ? err.message : String(err)}`);
574
+ console.error('💡 Use `dexto session list` to see available sessions');
575
+ safeExit('main', 1, 'resume-failed');
576
+ }
577
+ }
578
+ else if (opts.continue) {
579
+ try {
580
+ // Continue from most recent session
581
+ await loadMostRecentSession(agent);
582
+ // If no sessions existed, create a new one to honor default-new invariant
583
+ const sessionsAfter = await agent.listSessions();
584
+ if (sessionsAfter.length === 0) {
585
+ const session = await agent.createSession();
586
+ await agent.loadSessionAsDefault(session.id);
587
+ logger.info(`Created new session: ${session.id}`, null, 'green');
588
+ }
589
+ }
590
+ catch (err) {
591
+ console.error(`❌ Failed to continue session: ${err instanceof Error ? err.message : String(err)}`);
592
+ safeExit('main', 1, 'continue-failed');
593
+ }
594
+ }
595
+ else {
596
+ // Default behavior: create new session for CLI mode
597
+ try {
598
+ const session = await agent.createSession();
599
+ await agent.loadSessionAsDefault(session.id);
600
+ logger.info(`Created new session: ${session.id}`, null, 'green');
601
+ }
602
+ catch (err) {
603
+ console.error(`❌ Failed to create new session: ${err instanceof Error ? err.message : String(err)}`);
604
+ safeExit('main', 1, 'create-session-failed');
605
+ }
606
+ }
600
607
  const toolConfirmationMode = agent.getEffectiveConfig().toolConfirmation?.mode ?? 'event-based';
601
608
  if (toolConfirmationMode === 'event-based') {
602
609
  // Set up CLI tool confirmation subscriber
@@ -0,0 +1 @@
1
+ self.__BUILD_MANIFEST=function(e,r,t,s,_){return{__rewrites:{afterFiles:[{has:t,source:"/api/:path*",destination:t}],beforeFiles:[],fallback:[]},__routerFilterStatic:{numItems:3,errorRate:1e-4,numBits:58,numHashes:14,bitArray:[1,1,e,e,0,e,e,0,r,e,r,e,r,e,e,e,r,e,e,e,r,r,e,r,r,r,r,r,e,e,e,e,e,e,r,e,e,r,e,e,r,r,e,r,e,r,r,e,e,e,r,r,r,r,e,r,r,e]},__routerFilterDynamic:{numItems:e,errorRate:1e-4,numBits:20,numHashes:14,bitArray:[r,r,r,r,e,e,e,r,e,e,r,r,r,r,e,r,r,e,e,e]},"/_error":["static/chunks/pages/_error-162d61367b59fad2.js"],sortedPages:["/_app","/_error"]}}(1,0,void 0,1e-4,14),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();