dexto 1.6.16 → 1.6.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,4 @@
1
+ import type { StreamingEvent } from '@dexto/core';
1
2
  import { z } from 'zod';
2
3
  import type { DeployAgent } from './config.js';
3
4
  declare const CloudAgentStateSchema: z.ZodObject<{
@@ -7,6 +8,43 @@ declare const CloudAgentStateSchema: z.ZodObject<{
7
8
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
8
9
  status: z.ZodString;
9
10
  }, z.ZodTypeAny, "passthrough">>;
11
+ declare const CloudChatContentPartSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
12
+ type: z.ZodLiteral<"text">;
13
+ text: z.ZodString;
14
+ }, "strict", z.ZodTypeAny, {
15
+ type: "text";
16
+ text: string;
17
+ }, {
18
+ type: "text";
19
+ text: string;
20
+ }>, z.ZodObject<{
21
+ type: z.ZodLiteral<"image">;
22
+ image: z.ZodString;
23
+ mimeType: z.ZodOptional<z.ZodString>;
24
+ }, "strict", z.ZodTypeAny, {
25
+ type: "image";
26
+ image: string;
27
+ mimeType?: string | undefined;
28
+ }, {
29
+ type: "image";
30
+ image: string;
31
+ mimeType?: string | undefined;
32
+ }>, z.ZodObject<{
33
+ type: z.ZodLiteral<"file">;
34
+ data: z.ZodString;
35
+ mimeType: z.ZodString;
36
+ filename: z.ZodOptional<z.ZodString>;
37
+ }, "strict", z.ZodTypeAny, {
38
+ type: "file";
39
+ data: string;
40
+ mimeType: string;
41
+ filename?: string | undefined;
42
+ }, {
43
+ type: "file";
44
+ data: string;
45
+ mimeType: string;
46
+ filename?: string | undefined;
47
+ }>]>;
10
48
  export interface DeployCloudAgentResult {
11
49
  cloudAgentId: string;
12
50
  agentUrl: string;
@@ -35,6 +73,40 @@ export interface CloudAgentDeleteResult {
35
73
  cloudAgentId: string;
36
74
  agentUrl: string;
37
75
  }
76
+ export interface CloudChatSessionResult {
77
+ id: string;
78
+ createdAt: number | null;
79
+ lastActivity: number | null;
80
+ messageCount: number;
81
+ title: string | null;
82
+ workspaceId: string | null;
83
+ parentSessionId: string | null;
84
+ }
85
+ export interface CloudChatHistoryMessageResult {
86
+ role: 'user' | 'assistant' | 'system' | 'tool';
87
+ content: z.output<typeof CloudChatContentPartSchema>[];
88
+ timestamp?: number;
89
+ name?: string;
90
+ toolCallId?: string;
91
+ success?: boolean;
92
+ reasoning?: string;
93
+ model?: string;
94
+ provider?: string;
95
+ }
96
+ export interface CloudChatHistoryResult {
97
+ history: CloudChatHistoryMessageResult[];
98
+ isBusy: boolean;
99
+ stale: boolean;
100
+ }
101
+ export interface CloudChatApprovalDecision {
102
+ status: 'approved' | 'denied' | 'cancelled';
103
+ formData?: Record<string, unknown>;
104
+ rememberChoice?: boolean;
105
+ rememberPattern?: string;
106
+ rememberDirectory?: boolean;
107
+ reason?: string;
108
+ message?: string;
109
+ }
38
110
  export declare function resolveSandboxBaseUrl(): string;
39
111
  export declare function createDeployClient(): {
40
112
  deployWorkspace(input: {
@@ -46,6 +118,26 @@ export declare function createDeployClient(): {
46
118
  listCloudAgents(): Promise<CloudAgentListItemResult[]>;
47
119
  stopCloudAgent(cloudAgentId: string): Promise<CloudAgentStopResult>;
48
120
  deleteCloudAgent(cloudAgentId: string): Promise<CloudAgentDeleteResult>;
121
+ listCloudAgentSessions(cloudAgentId: string): Promise<CloudChatSessionResult[]>;
122
+ createCloudAgentSession(cloudAgentId: string, input?: {
123
+ sessionId?: string;
124
+ }): Promise<CloudChatSessionResult>;
125
+ getCloudAgentSessionHistory(cloudAgentId: string, sessionId: string): Promise<CloudChatHistoryResult>;
126
+ resetCloudAgentSession(cloudAgentId: string, sessionId: string): Promise<void>;
127
+ clearCloudAgentSessionContext(cloudAgentId: string, sessionId: string): Promise<void>;
128
+ deleteCloudAgentSession(cloudAgentId: string, sessionId: string): Promise<void>;
129
+ generateCloudAgentSessionTitle(cloudAgentId: string, sessionId: string): Promise<{
130
+ title: string | null;
131
+ sessionId: string;
132
+ } | null>;
133
+ cancelCloudAgentSessionRun(cloudAgentId: string, sessionId: string): Promise<void>;
134
+ listCloudAgentApprovals(cloudAgentId: string, sessionId: string): Promise<unknown[]>;
135
+ submitCloudAgentApproval(cloudAgentId: string, approvalId: string, decision: CloudChatApprovalDecision): Promise<void>;
136
+ streamCloudAgentMessage(cloudAgentId: string, input: {
137
+ sessionId: string;
138
+ content: string;
139
+ signal?: AbortSignal;
140
+ }): Promise<AsyncIterableIterator<StreamingEvent>>;
49
141
  };
50
142
  export {};
51
143
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C,QAAA,MAAM,qBAAqB;;;;;;gCAIT,CAAC;AAgGnB,MAAM,WAAW,sBAAsB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,sBAAsB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAC;IAC9C,KAAK,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,wBAAwB;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,oBAAoB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAaD,wBAAgB,qBAAqB,IAAI,MAAM,CAY9C;AAuED,wBAAgB,kBAAkB;2BAEG;QACzB,KAAK,EAAE,WAAW,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACzB,GAAG,OAAO,CAAC,sBAAsB,CAAC;gCAsCD,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;uBAkBjD,OAAO,CAAC,wBAAwB,EAAE,CAAC;iCAkBzB,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;mCA0BpC,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;EAgBpF"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/client.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import path from 'path';
3
+ import { createMessageStream } from '@dexto/client-sdk';
3
4
  import { z } from 'zod';
4
- import { getAuthToken, getDextoApiKey } from '../../auth/service.js';
5
+ import { getAuthToken, getDextoApiKey, loadAuth } from '../../auth/service.js';
5
6
  const SANDBOX_URL_ENV_VAR = 'DEXTO_SANDBOX_URL';
6
7
  const DEFAULT_SANDBOX_URL = 'https://sandbox.dexto.ai';
7
8
  const CloudAgentStateSchema = z
@@ -96,6 +97,90 @@ const DeleteResponseSchema = z
96
97
  .optional(),
97
98
  })
98
99
  .passthrough();
100
+ const CloudChatContentPartSchema = z
101
+ .discriminatedUnion('type', [
102
+ z
103
+ .object({
104
+ type: z.literal('text'),
105
+ text: z.string(),
106
+ })
107
+ .strict(),
108
+ z
109
+ .object({
110
+ type: z.literal('image'),
111
+ image: z.string(),
112
+ mimeType: z.string().optional(),
113
+ })
114
+ .strict(),
115
+ z
116
+ .object({
117
+ type: z.literal('file'),
118
+ data: z.string(),
119
+ mimeType: z.string(),
120
+ filename: z.string().optional(),
121
+ })
122
+ .strict(),
123
+ ])
124
+ .describe('Cloud chat content part');
125
+ const CloudChatSessionSchema = z
126
+ .object({
127
+ id: z.string(),
128
+ createdAt: z.number().nullable().optional(),
129
+ lastActivity: z.number().nullable().optional(),
130
+ messageCount: z.number().int().nonnegative().optional(),
131
+ title: z.string().nullable().optional(),
132
+ workspaceId: z.string().nullable().optional(),
133
+ parentSessionId: z.string().nullable().optional(),
134
+ })
135
+ .passthrough();
136
+ const CloudChatSessionListResponseSchema = z
137
+ .object({
138
+ sessions: z.array(CloudChatSessionSchema),
139
+ })
140
+ .passthrough();
141
+ const CloudChatSessionResponseSchema = z
142
+ .object({
143
+ session: CloudChatSessionSchema,
144
+ })
145
+ .passthrough();
146
+ const CloudChatHistoryMessageSchema = z
147
+ .object({
148
+ role: z.enum(['user', 'assistant', 'system', 'tool']),
149
+ content: z.array(CloudChatContentPartSchema),
150
+ timestamp: z.number().optional(),
151
+ name: z.string().optional(),
152
+ toolCallId: z.string().optional(),
153
+ success: z.boolean().optional(),
154
+ reasoning: z.string().optional(),
155
+ model: z.string().optional(),
156
+ provider: z.string().optional(),
157
+ displayData: z.unknown().optional(),
158
+ presentationSnapshot: z.unknown().optional(),
159
+ })
160
+ .passthrough();
161
+ const CloudChatHistoryResponseSchema = z
162
+ .object({
163
+ history: z.array(CloudChatHistoryMessageSchema),
164
+ isBusy: z.boolean().optional(),
165
+ stale: z.boolean().optional(),
166
+ })
167
+ .passthrough();
168
+ const CloudChatApprovalsResponseSchema = z
169
+ .object({
170
+ approvals: z.array(z.unknown()).default([]),
171
+ })
172
+ .passthrough();
173
+ function normalizeCloudChatSession(session) {
174
+ return {
175
+ id: session.id,
176
+ createdAt: session.createdAt ?? null,
177
+ lastActivity: session.lastActivity ?? null,
178
+ messageCount: session.messageCount ?? 0,
179
+ title: session.title ?? null,
180
+ workspaceId: session.workspaceId ?? null,
181
+ parentSessionId: session.parentSessionId ?? null,
182
+ };
183
+ }
99
184
  class SandboxApiError extends Error {
100
185
  status;
101
186
  constructor(message, status) {
@@ -117,14 +202,19 @@ export function resolveSandboxBaseUrl() {
117
202
  return DEFAULT_SANDBOX_URL;
118
203
  }
119
204
  async function resolveAccessToken() {
120
- const dextoApiKey = await getDextoApiKey();
121
- if (dextoApiKey && dextoApiKey.trim().length > 0) {
122
- return dextoApiKey.trim();
205
+ const auth = await loadAuth();
206
+ const storedDextoApiKey = auth?.dextoApiKey?.trim();
207
+ if (storedDextoApiKey && storedDextoApiKey.length > 0) {
208
+ return storedDextoApiKey;
123
209
  }
124
210
  const authToken = await getAuthToken();
125
211
  if (authToken && authToken.trim().length > 0) {
126
212
  return authToken.trim();
127
213
  }
214
+ const dextoApiKey = await getDextoApiKey();
215
+ if (dextoApiKey && dextoApiKey.trim().length > 0) {
216
+ return dextoApiKey.trim();
217
+ }
128
218
  throw new Error('Authentication required. Run `dexto login` before using `dexto deploy`.');
129
219
  }
130
220
  async function parseJsonResponse(response) {
@@ -265,5 +355,171 @@ export function createDeployClient() {
265
355
  agentUrl: data.agentUrl,
266
356
  };
267
357
  },
358
+ async listCloudAgentSessions(cloudAgentId) {
359
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/sessions`, {
360
+ method: 'GET',
361
+ });
362
+ if (!response.ok) {
363
+ await throwApiError(response);
364
+ }
365
+ const payload = CloudChatSessionListResponseSchema.parse(await response.json());
366
+ return payload.sessions.map(normalizeCloudChatSession);
367
+ },
368
+ async createCloudAgentSession(cloudAgentId, input) {
369
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/sessions`, {
370
+ method: 'POST',
371
+ headers: {
372
+ 'Content-Type': 'application/json',
373
+ },
374
+ body: JSON.stringify(input ?? {}),
375
+ });
376
+ if (!response.ok) {
377
+ await throwApiError(response);
378
+ }
379
+ const payload = CloudChatSessionResponseSchema.parse(await response.json());
380
+ return normalizeCloudChatSession(payload.session);
381
+ },
382
+ async getCloudAgentSessionHistory(cloudAgentId, sessionId) {
383
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/sessions/${encodeURIComponent(sessionId)}/history`, {
384
+ method: 'GET',
385
+ });
386
+ if (!response.ok) {
387
+ await throwApiError(response);
388
+ }
389
+ const payload = CloudChatHistoryResponseSchema.parse(await response.json());
390
+ return {
391
+ history: payload.history.map((entry) => ({
392
+ role: entry.role,
393
+ content: entry.content,
394
+ ...(entry.timestamp !== undefined ? { timestamp: entry.timestamp } : {}),
395
+ ...(entry.name !== undefined ? { name: entry.name } : {}),
396
+ ...(entry.toolCallId !== undefined ? { toolCallId: entry.toolCallId } : {}),
397
+ ...(entry.success !== undefined ? { success: entry.success } : {}),
398
+ ...(entry.reasoning !== undefined ? { reasoning: entry.reasoning } : {}),
399
+ ...(entry.model !== undefined ? { model: entry.model } : {}),
400
+ ...(entry.provider !== undefined ? { provider: entry.provider } : {}),
401
+ })),
402
+ isBusy: payload.isBusy ?? false,
403
+ stale: payload.stale === true,
404
+ };
405
+ },
406
+ async resetCloudAgentSession(cloudAgentId, sessionId) {
407
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/sessions/${encodeURIComponent(sessionId)}/reset`, {
408
+ method: 'POST',
409
+ });
410
+ if (!response.ok) {
411
+ await throwApiError(response);
412
+ }
413
+ },
414
+ async clearCloudAgentSessionContext(cloudAgentId, sessionId) {
415
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/sessions/${encodeURIComponent(sessionId)}/clear-context`, {
416
+ method: 'POST',
417
+ });
418
+ if (!response.ok) {
419
+ await throwApiError(response);
420
+ }
421
+ },
422
+ async deleteCloudAgentSession(cloudAgentId, sessionId) {
423
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/sessions/${encodeURIComponent(sessionId)}`, {
424
+ method: 'DELETE',
425
+ });
426
+ if (!response.ok) {
427
+ await throwApiError(response);
428
+ }
429
+ },
430
+ async generateCloudAgentSessionTitle(cloudAgentId, sessionId) {
431
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/sessions/${encodeURIComponent(sessionId)}/generate-title`, {
432
+ method: 'POST',
433
+ });
434
+ if (!response.ok) {
435
+ await throwApiError(response);
436
+ }
437
+ const payload = z
438
+ .object({
439
+ title: z.string().nullable().optional(),
440
+ sessionId: z.string().optional(),
441
+ })
442
+ .passthrough()
443
+ .parse(await response.json());
444
+ return {
445
+ title: payload.title ?? null,
446
+ sessionId: payload.sessionId ?? sessionId,
447
+ };
448
+ },
449
+ async cancelCloudAgentSessionRun(cloudAgentId, sessionId) {
450
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/sessions/${encodeURIComponent(sessionId)}/cancel`, {
451
+ method: 'POST',
452
+ });
453
+ if (!response.ok) {
454
+ await throwApiError(response);
455
+ }
456
+ },
457
+ async listCloudAgentApprovals(cloudAgentId, sessionId) {
458
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/approvals?sessionId=${encodeURIComponent(sessionId)}`, {
459
+ method: 'GET',
460
+ });
461
+ if (!response.ok) {
462
+ await throwApiError(response);
463
+ }
464
+ const payload = CloudChatApprovalsResponseSchema.parse(await response.json());
465
+ return payload.approvals;
466
+ },
467
+ async submitCloudAgentApproval(cloudAgentId, approvalId, decision) {
468
+ const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/approvals/${encodeURIComponent(approvalId)}`, {
469
+ method: 'POST',
470
+ headers: {
471
+ 'Content-Type': 'application/json',
472
+ },
473
+ body: JSON.stringify({
474
+ status: decision.status,
475
+ ...(decision.formData !== undefined ? { formData: decision.formData } : {}),
476
+ ...(decision.rememberChoice !== undefined
477
+ ? { rememberChoice: decision.rememberChoice }
478
+ : {}),
479
+ ...(decision.rememberPattern !== undefined
480
+ ? { rememberPattern: decision.rememberPattern }
481
+ : {}),
482
+ ...(decision.rememberDirectory !== undefined
483
+ ? { rememberDirectory: decision.rememberDirectory }
484
+ : {}),
485
+ ...(decision.reason !== undefined ? { reason: decision.reason } : {}),
486
+ ...(decision.message !== undefined ? { message: decision.message } : {}),
487
+ }),
488
+ });
489
+ if (!response.ok) {
490
+ await throwApiError(response);
491
+ }
492
+ },
493
+ async streamCloudAgentMessage(cloudAgentId, input) {
494
+ const responsePromise = request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/agent/message-stream`, {
495
+ method: 'POST',
496
+ headers: {
497
+ 'Content-Type': 'application/json',
498
+ Accept: 'text/event-stream',
499
+ },
500
+ body: JSON.stringify({
501
+ sessionId: input.sessionId,
502
+ content: input.content,
503
+ }),
504
+ ...(input.signal ? { signal: input.signal } : {}),
505
+ });
506
+ const response = await responsePromise;
507
+ if (response.status === 202 &&
508
+ response.headers.get('content-type')?.includes('application/json')) {
509
+ const busyPayload = await response.json().catch(() => null);
510
+ const parsed = z
511
+ .object({
512
+ hint: z.string().optional(),
513
+ })
514
+ .passthrough()
515
+ .safeParse(busyPayload);
516
+ throw new Error(parsed.success
517
+ ? (parsed.data.hint ?? 'Cloud session is busy')
518
+ : 'Cloud session is busy');
519
+ }
520
+ return createMessageStream(Promise.resolve(response), {
521
+ ...(input.signal ? { signal: input.signal } : {}),
522
+ });
523
+ },
268
524
  };
269
525
  }
@@ -7,5 +7,6 @@ export declare function handleDeployOpenCommand(): Promise<void>;
7
7
  export declare function handleDeployStatusCommand(): Promise<void>;
8
8
  export declare function handleDeployStopCommand(): Promise<void>;
9
9
  export declare function handleDeployDeleteCommand(options?: InteractiveOptions): Promise<void>;
10
+ export declare function handleDeployChatCommand(cloudAgentId?: string): Promise<void>;
10
11
  export {};
11
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/index.ts"],"names":[],"mappings":"AA4BA,UAAU,kBAAkB;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAyHD,wBAAsB,mBAAmB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8ErF;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiD7D;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAqB7D;AAED,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB/D;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4B7D;AAED,wBAAsB,yBAAyB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2C3F"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/index.ts"],"names":[],"mappings":"AA6BA,UAAU,kBAAkB;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AA4MD,wBAAsB,mBAAmB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8ErF;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiD7D;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAqB7D;AAED,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB/D;AAED,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CA4B7D;AAED,wBAAsB,yBAAyB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2C3F;AAED,wBAAsB,uBAAuB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlF"}
@@ -12,6 +12,7 @@ import { discoverPrimaryWorkspaceAgent, isAgentYamlPath } from './entry-agent.js
12
12
  import { getCloudAgentDashboardUrl } from './links.js';
13
13
  import { loadWorkspaceDeployLink, removeWorkspaceDeployLink, saveWorkspaceDeployLink, } from './state.js';
14
14
  import { createWorkspaceSnapshot } from './snapshot.js';
15
+ import { startCloudChatCli } from '../../cloud-chat.js';
15
16
  function isInteractive(options) {
16
17
  return options?.interactive !== false;
17
18
  }
@@ -58,6 +59,70 @@ function formatCloudAgentListItem(cloudAgent, linkedToWorkspace) {
58
59
  }
59
60
  return lines.join('\n');
60
61
  }
62
+ function formatCloudAgentSelectionLabel(cloudAgent) {
63
+ const trimmedName = cloudAgent.name?.trim();
64
+ const heading = trimmedName && trimmedName !== cloudAgent.cloudAgentId
65
+ ? `${trimmedName} (${cloudAgent.cloudAgentId})`
66
+ : cloudAgent.cloudAgentId;
67
+ return `${heading} ${chalk.gray('[')}${formatCloudAgentStatus(cloudAgent.state.status)}${chalk.gray(']')}`;
68
+ }
69
+ function sortCloudAgentsForChat(cloudAgents, linkedCloudAgentId) {
70
+ return cloudAgents.slice().sort((left, right) => {
71
+ const leftIsLinked = linkedCloudAgentId !== null && left.cloudAgentId === linkedCloudAgentId;
72
+ const rightIsLinked = linkedCloudAgentId !== null && right.cloudAgentId === linkedCloudAgentId;
73
+ if (leftIsLinked !== rightIsLinked) {
74
+ return leftIsLinked ? -1 : 1;
75
+ }
76
+ const leftReady = left.state.status === 'ready';
77
+ const rightReady = right.state.status === 'ready';
78
+ if (leftReady !== rightReady) {
79
+ return leftReady ? -1 : 1;
80
+ }
81
+ const leftName = (left.name?.trim() || left.cloudAgentId).toLowerCase();
82
+ const rightName = (right.name?.trim() || right.cloudAgentId).toLowerCase();
83
+ return leftName.localeCompare(rightName);
84
+ });
85
+ }
86
+ async function selectCloudAgentForChat(workspaceRoot) {
87
+ const deployLink = await loadWorkspaceDeployLink(workspaceRoot);
88
+ const spinner = p.spinner();
89
+ spinner.start('Loading cloud agents...');
90
+ const client = createDeployClient();
91
+ let cloudAgents;
92
+ try {
93
+ cloudAgents = await client.listCloudAgents();
94
+ }
95
+ catch (error) {
96
+ spinner.stop(chalk.red('✗ Failed to load cloud agents'));
97
+ throw error;
98
+ }
99
+ spinner.stop(chalk.green('✓ Cloud agents loaded'));
100
+ if (cloudAgents.length === 0) {
101
+ throw new Error('No cloud agents available yet. Run `dexto deploy` first, or pass a cloud agent ID explicitly.');
102
+ }
103
+ const linkedCloudAgentId = deployLink?.cloudAgentId ?? null;
104
+ const sortedCloudAgents = sortCloudAgentsForChat(cloudAgents, linkedCloudAgentId);
105
+ const selected = await p.select({
106
+ message: 'Choose a cloud agent to chat with',
107
+ options: sortedCloudAgents.map((cloudAgent) => {
108
+ const isLinked = linkedCloudAgentId !== null && cloudAgent.cloudAgentId === linkedCloudAgentId;
109
+ const hintParts = [cloudAgent.agentUrl];
110
+ if (isLinked) {
111
+ hintParts.unshift('Linked to this workspace');
112
+ }
113
+ return {
114
+ value: cloudAgent.cloudAgentId,
115
+ label: formatCloudAgentSelectionLabel(cloudAgent),
116
+ hint: hintParts.join(' • '),
117
+ };
118
+ }),
119
+ });
120
+ if (p.isCancel(selected)) {
121
+ p.cancel('Cloud chat cancelled');
122
+ process.exit(0);
123
+ }
124
+ return selected;
125
+ }
61
126
  function resolveWorkspaceRoot() {
62
127
  return findDextoProjectRoot(process.cwd()) ?? process.cwd();
63
128
  }
@@ -295,3 +360,11 @@ export async function handleDeployDeleteCommand(options) {
295
360
  throw error;
296
361
  }
297
362
  }
363
+ export async function handleDeployChatCommand(cloudAgentId) {
364
+ const workspaceRoot = resolveWorkspaceRoot();
365
+ const selectedCloudAgentId = cloudAgentId ?? (await selectCloudAgentForChat(workspaceRoot));
366
+ await startCloudChatCli({
367
+ cloudAgentId: selectedCloudAgentId,
368
+ workspaceRoot,
369
+ });
370
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,MAAM,WAAW,4BAA4B;IACzC,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,EAAE,4BAA4B,GAAG,IAAI,CAqHrF"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,MAAM,WAAW,4BAA4B;IACzC,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,EAAE,4BAA4B,GAAG,IAAI,CA4IrF"}
@@ -7,6 +7,8 @@ export function registerDeployCommand({ program }) {
7
7
  Examples:
8
8
  $ dexto deploy
9
9
  $ dexto deploy list
10
+ $ dexto deploy chat
11
+ $ dexto deploy chat sbx_123
10
12
  $ dexto deploy open
11
13
  $ dexto deploy status
12
14
  $ dexto deploy stop
@@ -25,6 +27,23 @@ Examples:
25
27
  safeExit('deploy', 1, 'error');
26
28
  }
27
29
  }));
30
+ deployCommand
31
+ .command('chat')
32
+ .description('Start Ink CLI chat against a selected or explicit cloud agent')
33
+ .argument('[cloudAgentId]', 'Cloud agent ID (omit to choose from your available cloud agents)')
34
+ .action(withAnalytics('deploy chat', async (cloudAgentId) => {
35
+ try {
36
+ const { handleDeployChatCommand } = await import('./index.js');
37
+ await handleDeployChatCommand(cloudAgentId);
38
+ safeExit('deploy chat', 0);
39
+ }
40
+ catch (err) {
41
+ if (err instanceof ExitSignal)
42
+ throw err;
43
+ console.error(`❌ dexto deploy chat command failed: ${err}`);
44
+ safeExit('deploy chat', 1, 'error');
45
+ }
46
+ }));
28
47
  deployCommand
29
48
  .command('list')
30
49
  .description('List cloud deployments for your account')
@@ -100,6 +100,7 @@ program
100
100
  .description('AI-powered CLI and WebUI for interacting with MCP servers.')
101
101
  .version(cliVersion, '-v, --version', 'output the current version')
102
102
  .option('-a, --agent <id|path>', 'Agent ID or path to agent config file')
103
+ .option('--cloud-agent <id>', 'Connect the interactive CLI to a deployed cloud agent by ID')
103
104
  .option('-p, --prompt <text>', 'Start the interactive CLI and immediately run the prompt')
104
105
  .option('-s, --strict', 'Require all server connections to succeed')
105
106
  .option('--no-verbose', 'Disable verbose output')
@@ -445,8 +446,9 @@ program
445
446
  // the first positional argument as an agent name to avoid ambiguity with prompts.
446
447
  // ——— FORCE CLI MODE FOR PROMPT/SESSION FLAGS ———
447
448
  // If a prompt or session flag was provided, force CLI mode.
448
- if ((initialPrompt || opts.continue || opts.resume) && opts.mode !== 'cli') {
449
- console.error(`ℹ️ Forcing CLI mode due to --prompt/--continue/--resume.`);
449
+ if ((initialPrompt || opts.continue || opts.resume || opts.cloudAgent) &&
450
+ opts.mode !== 'cli') {
451
+ console.error(`ℹ️ Forcing CLI mode due to --prompt/--continue/--resume/--cloud-agent.`);
450
452
  console.error(` Original mode: ${opts.mode} → Overridden to: cli`);
451
453
  opts.mode = 'cli';
452
454
  }
@@ -456,6 +458,28 @@ program
456
458
  console.error('💡 For non-interactive runs, use `dexto run "<prompt>"`, or use --mode server for automation.');
457
459
  safeExit('main', 1, 'no-tty');
458
460
  }
461
+ if (opts.cloudAgent) {
462
+ if (opts.agent) {
463
+ console.error('❌ `--agent` and `--cloud-agent` are mutually exclusive. Use one chat target at a time.');
464
+ safeExit('main', 1, 'cloud-agent-conflict');
465
+ }
466
+ try {
467
+ const { startCloudChatCli } = await import('./cli/cloud-chat.js');
468
+ await startCloudChatCli({
469
+ cloudAgentId: String(opts.cloudAgent),
470
+ ...(initialPrompt ? { initialPrompt } : {}),
471
+ ...(opts.resume ? { resume: String(opts.resume) } : {}),
472
+ ...(opts.continue ? { continueMostRecent: true } : {}),
473
+ });
474
+ safeExit('main', 0);
475
+ }
476
+ catch (err) {
477
+ if (err instanceof ExitSignal)
478
+ throw err;
479
+ console.error(`❌ Cloud chat failed: ${err}`);
480
+ safeExit('main', 1, 'cloud-chat-error');
481
+ }
482
+ }
459
483
  // ——— Infer provider & API key from model ———
460
484
  if (opts.model) {
461
485
  if (opts.model.includes('/')) {
@@ -1,4 +1,6 @@
1
- import type { DextoAgent } from '@dexto/core';
1
+ interface ShutdownTarget {
2
+ stop?: (() => Promise<void>) | undefined;
3
+ }
2
4
  export interface GracefulShutdownOptions {
3
5
  /**
4
6
  * When true, the first SIGINT is ignored to let the application handle it
@@ -11,5 +13,6 @@ export interface GracefulShutdownOptions {
11
13
  */
12
14
  forceExitTimeout?: number;
13
15
  }
14
- export declare function registerGracefulShutdown(getCurrentAgent: () => DextoAgent, options?: GracefulShutdownOptions): void;
16
+ export declare function registerGracefulShutdown(getCurrentAgent: () => ShutdownTarget, options?: GracefulShutdownOptions): void;
17
+ export {};
15
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":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,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,UAAU,EACjC,OAAO,GAAE,uBAA4B,GACtC,IAAI,CA6GN"}
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"}
@@ -14,7 +14,9 @@ export function registerGracefulShutdown(getCurrentAgent, options = {}) {
14
14
  logger.info(`Received ${signal}, shutting down gracefully...`);
15
15
  try {
16
16
  const agent = getCurrentAgent();
17
- await agent.stop();
17
+ if (typeof agent.stop === 'function') {
18
+ await agent.stop();
19
+ }
18
20
  process.exit(0);
19
21
  }
20
22
  catch (error) {
@@ -63,7 +65,9 @@ export function registerGracefulShutdown(getCurrentAgent, options = {}) {
63
65
  isShuttingDown = true;
64
66
  try {
65
67
  const agent = getCurrentAgent();
66
- await agent.stop();
68
+ if (typeof agent.stop === 'function') {
69
+ await agent.stop();
70
+ }
67
71
  }
68
72
  catch (innerError) {
69
73
  logger.error(`Error during shutdown initiated by uncaughtException: ${innerError instanceof Error ? innerError.message : String(innerError)}`, { error: innerError });
@@ -77,7 +81,9 @@ export function registerGracefulShutdown(getCurrentAgent, options = {}) {
77
81
  isShuttingDown = true;
78
82
  try {
79
83
  const agent = getCurrentAgent();
80
- await agent.stop();
84
+ if (typeof agent.stop === 'function') {
85
+ await agent.stop();
86
+ }
81
87
  }
82
88
  catch (innerError) {
83
89
  logger.error(`Error during shutdown initiated by unhandledRejection: ${innerError instanceof Error ? innerError.message : String(innerError)}`, { error: innerError });