dexto 1.6.12 → 1.6.13
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.
- package/README.md +10 -2
- package/dist/analytics/events.d.ts +1 -1
- package/dist/analytics/events.d.ts.map +1 -1
- package/dist/cli/commands/agents/install.d.ts.map +1 -0
- package/dist/cli/commands/{install.js → agents/install.js} +4 -4
- package/dist/cli/commands/{list-agents.d.ts → agents/list.d.ts} +1 -1
- package/dist/cli/commands/agents/list.d.ts.map +1 -0
- package/dist/cli/commands/{list-agents.js → agents/list.js} +2 -2
- package/dist/cli/commands/agents/register.js +5 -5
- package/dist/cli/commands/{sync-agents.d.ts → agents/sync.d.ts} +10 -2
- package/dist/cli/commands/agents/sync.d.ts.map +1 -0
- package/dist/cli/commands/{sync-agents.js → agents/sync.js} +54 -5
- package/dist/cli/commands/agents/uninstall.d.ts +18 -0
- package/dist/cli/commands/agents/uninstall.d.ts.map +1 -0
- package/dist/cli/commands/agents/uninstall.js +141 -0
- package/dist/cli/commands/deploy/client.d.ts +44 -0
- package/dist/cli/commands/deploy/client.d.ts.map +1 -0
- package/dist/cli/commands/deploy/client.js +232 -0
- package/dist/cli/commands/deploy/config.d.ts +81 -0
- package/dist/cli/commands/deploy/config.d.ts.map +1 -0
- package/dist/cli/commands/deploy/config.js +144 -0
- package/dist/cli/commands/deploy/entry-agent.d.ts +3 -0
- package/dist/cli/commands/deploy/entry-agent.d.ts.map +1 -0
- package/dist/cli/commands/deploy/entry-agent.js +22 -0
- package/dist/cli/commands/deploy/index.d.ts +9 -0
- package/dist/cli/commands/deploy/index.d.ts.map +1 -0
- package/dist/cli/commands/deploy/index.js +204 -0
- package/dist/cli/commands/deploy/links.d.ts +3 -0
- package/dist/cli/commands/deploy/links.d.ts.map +1 -0
- package/dist/cli/commands/deploy/links.js +53 -0
- package/dist/cli/commands/deploy/register.d.ts +6 -0
- package/dist/cli/commands/deploy/register.d.ts.map +1 -0
- package/dist/cli/commands/deploy/register.js +75 -0
- package/dist/cli/commands/deploy/snapshot.d.ts +12 -0
- package/dist/cli/commands/deploy/snapshot.d.ts.map +1 -0
- package/dist/cli/commands/deploy/snapshot.js +76 -0
- package/dist/cli/commands/deploy/state.d.ts +21 -0
- package/dist/cli/commands/deploy/state.d.ts.map +1 -0
- package/dist/cli/commands/deploy/state.js +122 -0
- package/dist/cli/commands/index.d.ts +6 -4
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +6 -4
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +304 -31
- package/dist/cli/commands/uninstall.d.ts +9 -12
- package/dist/cli/commands/uninstall.d.ts.map +1 -1
- package/dist/cli/commands/uninstall.js +99 -113
- package/dist/cli/commands/upgrade.d.ts +15 -0
- package/dist/cli/commands/upgrade.d.ts.map +1 -0
- package/dist/cli/commands/upgrade.js +106 -0
- package/dist/cli/modes/cli.d.ts.map +1 -1
- package/dist/cli/modes/cli.js +0 -12
- package/dist/cli/utils/config-validation.d.ts.map +1 -1
- package/dist/cli/utils/config-validation.js +34 -20
- package/dist/cli/utils/self-management.d.ts +93 -0
- package/dist/cli/utils/self-management.d.ts.map +1 -0
- package/dist/cli/utils/self-management.js +423 -0
- package/dist/cli/utils/version-check.d.ts +1 -1
- package/dist/cli/utils/version-check.d.ts.map +1 -1
- package/dist/cli/utils/version-check.js +53 -19
- package/dist/index-main.js +59 -2
- package/dist/webui/assets/{index-CNiOYnOb.js → index-UDAdxmci.js} +187 -187
- package/dist/webui/index.html +1 -1
- package/package.json +13 -11
- package/dist/cli/commands/install.d.ts.map +0 -1
- package/dist/cli/commands/list-agents.d.ts.map +0 -1
- package/dist/cli/commands/sync-agents.d.ts.map +0 -1
- /package/dist/cli/commands/{install.d.ts → agents/install.d.ts} +0 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { getAuthToken, getDextoApiKey } from '../../auth/service.js';
|
|
5
|
+
const SANDBOX_URL_ENV_VAR = 'DEXTO_SANDBOX_URL';
|
|
6
|
+
const DEFAULT_SANDBOX_URL = 'https://sandbox.dexto.ai';
|
|
7
|
+
const CloudAgentStateSchema = z
|
|
8
|
+
.object({
|
|
9
|
+
status: z.string(),
|
|
10
|
+
})
|
|
11
|
+
.passthrough();
|
|
12
|
+
const CloudAgentSummarySchema = z
|
|
13
|
+
.object({
|
|
14
|
+
runId: z.string(),
|
|
15
|
+
agentUrl: z.string(),
|
|
16
|
+
hostUrl: z.string().nullable().optional(),
|
|
17
|
+
state: CloudAgentStateSchema,
|
|
18
|
+
})
|
|
19
|
+
.passthrough();
|
|
20
|
+
const DeployResponseSchema = z
|
|
21
|
+
.object({
|
|
22
|
+
success: z.boolean(),
|
|
23
|
+
error: z.string().optional(),
|
|
24
|
+
data: z
|
|
25
|
+
.object({
|
|
26
|
+
cloudAgentId: z.string(),
|
|
27
|
+
agentUrl: z.string(),
|
|
28
|
+
cloudAgent: CloudAgentSummarySchema,
|
|
29
|
+
})
|
|
30
|
+
.passthrough()
|
|
31
|
+
.optional(),
|
|
32
|
+
})
|
|
33
|
+
.passthrough();
|
|
34
|
+
const StatusResponseSchema = z
|
|
35
|
+
.object({
|
|
36
|
+
success: z.boolean(),
|
|
37
|
+
error: z.string().optional(),
|
|
38
|
+
data: z
|
|
39
|
+
.object({
|
|
40
|
+
cloudAgentId: z.string(),
|
|
41
|
+
agentUrl: z.string(),
|
|
42
|
+
cloudAgent: CloudAgentSummarySchema,
|
|
43
|
+
stale: z.boolean().optional(),
|
|
44
|
+
})
|
|
45
|
+
.passthrough()
|
|
46
|
+
.optional(),
|
|
47
|
+
})
|
|
48
|
+
.passthrough();
|
|
49
|
+
const StopResponseSchema = z
|
|
50
|
+
.object({
|
|
51
|
+
success: z.boolean(),
|
|
52
|
+
error: z.string().optional(),
|
|
53
|
+
data: z
|
|
54
|
+
.object({
|
|
55
|
+
cloudAgentId: z.string(),
|
|
56
|
+
agentUrl: z.string(),
|
|
57
|
+
stopped: z.boolean(),
|
|
58
|
+
alreadyStopped: z.boolean(),
|
|
59
|
+
snapshotStatus: z.string(),
|
|
60
|
+
})
|
|
61
|
+
.passthrough()
|
|
62
|
+
.optional(),
|
|
63
|
+
})
|
|
64
|
+
.passthrough();
|
|
65
|
+
const DeleteResponseSchema = z
|
|
66
|
+
.object({
|
|
67
|
+
success: z.boolean(),
|
|
68
|
+
error: z.string().optional(),
|
|
69
|
+
data: z
|
|
70
|
+
.object({
|
|
71
|
+
cloudAgentId: z.string(),
|
|
72
|
+
agentUrl: z.string(),
|
|
73
|
+
})
|
|
74
|
+
.passthrough()
|
|
75
|
+
.optional(),
|
|
76
|
+
})
|
|
77
|
+
.passthrough();
|
|
78
|
+
class SandboxApiError extends Error {
|
|
79
|
+
status;
|
|
80
|
+
constructor(message, status) {
|
|
81
|
+
super(message);
|
|
82
|
+
Object.setPrototypeOf(this, SandboxApiError.prototype);
|
|
83
|
+
this.name = 'SandboxApiError';
|
|
84
|
+
this.status = status;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export function resolveSandboxBaseUrl() {
|
|
88
|
+
const explicit = process.env[SANDBOX_URL_ENV_VAR]?.trim();
|
|
89
|
+
if (explicit && explicit.length > 0) {
|
|
90
|
+
return explicit.replace(/\/+$/, '');
|
|
91
|
+
}
|
|
92
|
+
const apiUrl = process.env.DEXTO_API_URL?.trim();
|
|
93
|
+
if (apiUrl?.startsWith('http://localhost:')) {
|
|
94
|
+
return 'http://localhost:3004';
|
|
95
|
+
}
|
|
96
|
+
return DEFAULT_SANDBOX_URL;
|
|
97
|
+
}
|
|
98
|
+
async function resolveAccessToken() {
|
|
99
|
+
const dextoApiKey = await getDextoApiKey();
|
|
100
|
+
if (dextoApiKey && dextoApiKey.trim().length > 0) {
|
|
101
|
+
return dextoApiKey.trim();
|
|
102
|
+
}
|
|
103
|
+
const authToken = await getAuthToken();
|
|
104
|
+
if (authToken && authToken.trim().length > 0) {
|
|
105
|
+
return authToken.trim();
|
|
106
|
+
}
|
|
107
|
+
throw new Error('Authentication required. Run `dexto login` before using `dexto deploy`.');
|
|
108
|
+
}
|
|
109
|
+
async function parseJsonResponse(response) {
|
|
110
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
111
|
+
if (!contentType.toLowerCase().includes('application/json')) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return response.json().catch(() => null);
|
|
115
|
+
}
|
|
116
|
+
async function request(pathName, init) {
|
|
117
|
+
const accessToken = await resolveAccessToken();
|
|
118
|
+
const headers = new globalThis.Headers(init.headers);
|
|
119
|
+
headers.set('Authorization', `Bearer ${accessToken}`);
|
|
120
|
+
return fetch(`${resolveSandboxBaseUrl()}/api${pathName}`, {
|
|
121
|
+
...init,
|
|
122
|
+
headers,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function requireSuccessData(payload, response, schema) {
|
|
126
|
+
const parsed = schema.parse(payload);
|
|
127
|
+
if (!parsed.success || !parsed.data) {
|
|
128
|
+
throw new SandboxApiError(parsed.error ?? 'Sandbox request failed', response.status);
|
|
129
|
+
}
|
|
130
|
+
return parsed.data;
|
|
131
|
+
}
|
|
132
|
+
async function throwApiError(response) {
|
|
133
|
+
const payload = await parseJsonResponse(response);
|
|
134
|
+
const parsed = payload && typeof payload === 'object' && payload !== null && 'error' in payload
|
|
135
|
+
? z
|
|
136
|
+
.object({
|
|
137
|
+
error: z.string().optional(),
|
|
138
|
+
hint: z.string().optional(),
|
|
139
|
+
})
|
|
140
|
+
.passthrough()
|
|
141
|
+
.safeParse(payload)
|
|
142
|
+
: null;
|
|
143
|
+
const errorMessage = parsed?.success && parsed.data.error
|
|
144
|
+
? parsed.data.hint
|
|
145
|
+
? `${parsed.data.error} (${parsed.data.hint})`
|
|
146
|
+
: parsed.data.error
|
|
147
|
+
: `Sandbox request failed with status ${response.status}`;
|
|
148
|
+
throw new SandboxApiError(errorMessage, response.status);
|
|
149
|
+
}
|
|
150
|
+
export function createDeployClient() {
|
|
151
|
+
return {
|
|
152
|
+
async deployWorkspace(input) {
|
|
153
|
+
const snapshotBuffer = await fs.readFile(input.snapshotPath);
|
|
154
|
+
const formData = new globalThis.FormData();
|
|
155
|
+
formData.set('agentType', input.agent.type);
|
|
156
|
+
if (input.agent.type === 'workspace') {
|
|
157
|
+
formData.set('entryAgent', input.agent.path);
|
|
158
|
+
}
|
|
159
|
+
if (input.cloudAgentId && input.cloudAgentId.trim().length > 0) {
|
|
160
|
+
formData.set('cloudAgentId', input.cloudAgentId.trim());
|
|
161
|
+
}
|
|
162
|
+
formData.set('workspaceSnapshot', new globalThis.File([new Uint8Array(snapshotBuffer)], path.basename(input.snapshotPath), {
|
|
163
|
+
type: 'application/gzip',
|
|
164
|
+
}));
|
|
165
|
+
const response = await request('/cloud-agents/deploy', {
|
|
166
|
+
method: 'POST',
|
|
167
|
+
body: formData,
|
|
168
|
+
});
|
|
169
|
+
if (!response.ok) {
|
|
170
|
+
await throwApiError(response);
|
|
171
|
+
}
|
|
172
|
+
const payload = await parseJsonResponse(response);
|
|
173
|
+
const data = requireSuccessData(payload, response, DeployResponseSchema);
|
|
174
|
+
return {
|
|
175
|
+
cloudAgentId: data.cloudAgentId,
|
|
176
|
+
agentUrl: data.agentUrl,
|
|
177
|
+
state: data.cloudAgent.state,
|
|
178
|
+
};
|
|
179
|
+
},
|
|
180
|
+
async getCloudAgent(cloudAgentId) {
|
|
181
|
+
const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}`, {
|
|
182
|
+
method: 'GET',
|
|
183
|
+
});
|
|
184
|
+
if (!response.ok) {
|
|
185
|
+
await throwApiError(response);
|
|
186
|
+
}
|
|
187
|
+
const payload = await parseJsonResponse(response);
|
|
188
|
+
const data = requireSuccessData(payload, response, StatusResponseSchema);
|
|
189
|
+
return {
|
|
190
|
+
cloudAgentId: data.cloudAgentId,
|
|
191
|
+
agentUrl: data.agentUrl,
|
|
192
|
+
state: data.cloudAgent.state,
|
|
193
|
+
stale: data.stale === true,
|
|
194
|
+
};
|
|
195
|
+
},
|
|
196
|
+
async stopCloudAgent(cloudAgentId) {
|
|
197
|
+
const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}/stop`, {
|
|
198
|
+
method: 'POST',
|
|
199
|
+
headers: {
|
|
200
|
+
'Content-Type': 'application/json',
|
|
201
|
+
},
|
|
202
|
+
body: JSON.stringify({}),
|
|
203
|
+
});
|
|
204
|
+
if (!response.ok) {
|
|
205
|
+
await throwApiError(response);
|
|
206
|
+
}
|
|
207
|
+
const payload = await parseJsonResponse(response);
|
|
208
|
+
const data = requireSuccessData(payload, response, StopResponseSchema);
|
|
209
|
+
return {
|
|
210
|
+
cloudAgentId: data.cloudAgentId,
|
|
211
|
+
agentUrl: data.agentUrl,
|
|
212
|
+
stopped: data.stopped,
|
|
213
|
+
alreadyStopped: data.alreadyStopped,
|
|
214
|
+
snapshotStatus: data.snapshotStatus,
|
|
215
|
+
};
|
|
216
|
+
},
|
|
217
|
+
async deleteCloudAgent(cloudAgentId) {
|
|
218
|
+
const response = await request(`/cloud-agents/${encodeURIComponent(cloudAgentId)}`, {
|
|
219
|
+
method: 'DELETE',
|
|
220
|
+
});
|
|
221
|
+
if (!response.ok) {
|
|
222
|
+
await throwApiError(response);
|
|
223
|
+
}
|
|
224
|
+
const payload = await parseJsonResponse(response);
|
|
225
|
+
const data = requireSuccessData(payload, response, DeleteResponseSchema);
|
|
226
|
+
return {
|
|
227
|
+
cloudAgentId: data.cloudAgentId,
|
|
228
|
+
agentUrl: data.agentUrl,
|
|
229
|
+
};
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const DEPLOY_CONFIG_RELATIVE_PATH: string;
|
|
3
|
+
export declare const DEFAULT_DEPLOY_EXCLUDES: readonly [".git", "node_modules", "dist", ".next", ".turbo", ".env*"];
|
|
4
|
+
export declare function normalizeWorkspaceRelativePath(value: string): string;
|
|
5
|
+
declare const WorkspaceDeployAgentSchema: z.ZodObject<{
|
|
6
|
+
type: z.ZodLiteral<"workspace">;
|
|
7
|
+
path: z.ZodEffects<z.ZodString, string, string>;
|
|
8
|
+
}, "strict", z.ZodTypeAny, {
|
|
9
|
+
type: "workspace";
|
|
10
|
+
path: string;
|
|
11
|
+
}, {
|
|
12
|
+
type: "workspace";
|
|
13
|
+
path: string;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const DeployAgentSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
16
|
+
type: z.ZodLiteral<"cloud-default">;
|
|
17
|
+
}, "strict", z.ZodTypeAny, {
|
|
18
|
+
type: "cloud-default";
|
|
19
|
+
}, {
|
|
20
|
+
type: "cloud-default";
|
|
21
|
+
}>, z.ZodObject<{
|
|
22
|
+
type: z.ZodLiteral<"workspace">;
|
|
23
|
+
path: z.ZodEffects<z.ZodString, string, string>;
|
|
24
|
+
}, "strict", z.ZodTypeAny, {
|
|
25
|
+
type: "workspace";
|
|
26
|
+
path: string;
|
|
27
|
+
}, {
|
|
28
|
+
type: "workspace";
|
|
29
|
+
path: string;
|
|
30
|
+
}>]>;
|
|
31
|
+
export declare const DeployConfigSchema: z.ZodObject<{
|
|
32
|
+
version: z.ZodDefault<z.ZodLiteral<1>>;
|
|
33
|
+
agent: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
34
|
+
type: z.ZodLiteral<"cloud-default">;
|
|
35
|
+
}, "strict", z.ZodTypeAny, {
|
|
36
|
+
type: "cloud-default";
|
|
37
|
+
}, {
|
|
38
|
+
type: "cloud-default";
|
|
39
|
+
}>, z.ZodObject<{
|
|
40
|
+
type: z.ZodLiteral<"workspace">;
|
|
41
|
+
path: z.ZodEffects<z.ZodString, string, string>;
|
|
42
|
+
}, "strict", z.ZodTypeAny, {
|
|
43
|
+
type: "workspace";
|
|
44
|
+
path: string;
|
|
45
|
+
}, {
|
|
46
|
+
type: "workspace";
|
|
47
|
+
path: string;
|
|
48
|
+
}>]>;
|
|
49
|
+
exclude: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
50
|
+
}, "strict", z.ZodTypeAny, {
|
|
51
|
+
agent: {
|
|
52
|
+
type: "cloud-default";
|
|
53
|
+
} | {
|
|
54
|
+
type: "workspace";
|
|
55
|
+
path: string;
|
|
56
|
+
};
|
|
57
|
+
version: 1;
|
|
58
|
+
exclude: string[];
|
|
59
|
+
}, {
|
|
60
|
+
agent: {
|
|
61
|
+
type: "cloud-default";
|
|
62
|
+
} | {
|
|
63
|
+
type: "workspace";
|
|
64
|
+
path: string;
|
|
65
|
+
};
|
|
66
|
+
version?: 1 | undefined;
|
|
67
|
+
exclude?: string[] | undefined;
|
|
68
|
+
}>;
|
|
69
|
+
export type DeployConfig = z.output<typeof DeployConfigSchema>;
|
|
70
|
+
export type DeployConfigInput = z.input<typeof DeployConfigSchema>;
|
|
71
|
+
export type DeployAgent = z.output<typeof DeployAgentSchema>;
|
|
72
|
+
export type WorkspaceDeployAgent = z.output<typeof WorkspaceDeployAgentSchema>;
|
|
73
|
+
export declare function getDeployConfigPath(workspaceRoot: string): string;
|
|
74
|
+
export declare function loadDeployConfig(workspaceRoot: string): Promise<DeployConfig | null>;
|
|
75
|
+
export declare function saveDeployConfig(workspaceRoot: string, config: DeployConfigInput): Promise<DeployConfig>;
|
|
76
|
+
export declare function createCloudDefaultDeployConfig(exclude?: readonly string[]): DeployConfig;
|
|
77
|
+
export declare function createWorkspaceDeployConfig(agentPath: string, exclude?: readonly string[]): DeployConfig;
|
|
78
|
+
export declare function isWorkspaceDeployAgent(agent: DeployAgent): agent is WorkspaceDeployAgent;
|
|
79
|
+
export declare function resolveWorkspaceDeployAgentPath(workspaceRoot: string, agentPath: string): string;
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,2BAA2B,QAAqC,CAAC;AAE9E,eAAO,MAAM,uBAAuB,uEAO1B,CAAC;AAEX,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAkBpE;AAwBD,QAAA,MAAM,0BAA0B;;;;;;;;;EAOnB,CAAC;AAEd,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;IAG5B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMlB,CAAC;AAYd,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC/D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AACnE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC7D,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE/E,wBAAgB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAsB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAmB1F;AAED,wBAAsB,gBAAgB,CAClC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,iBAAiB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAMvB;AAgBD,wBAAgB,8BAA8B,CAC1C,OAAO,GAAE,SAAS,MAAM,EAA4B,GACrD,YAAY,CAQd;AAED,wBAAgB,2BAA2B,CACvC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,SAAS,MAAM,EAA4B,GACrD,YAAY,CASd;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,IAAI,oBAAoB,CAExF;AAED,wBAAgB,+BAA+B,CAAC,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAahG"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { existsSync, promises as fs } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export const DEPLOY_CONFIG_RELATIVE_PATH = path.join('.dexto', 'deploy.json');
|
|
5
|
+
export const DEFAULT_DEPLOY_EXCLUDES = [
|
|
6
|
+
'.git',
|
|
7
|
+
'node_modules',
|
|
8
|
+
'dist',
|
|
9
|
+
'.next',
|
|
10
|
+
'.turbo',
|
|
11
|
+
'.env*',
|
|
12
|
+
];
|
|
13
|
+
export function normalizeWorkspaceRelativePath(value) {
|
|
14
|
+
const trimmed = value.trim().replace(/\\/g, '/');
|
|
15
|
+
if (trimmed.length === 0) {
|
|
16
|
+
throw new Error('Path must not be empty');
|
|
17
|
+
}
|
|
18
|
+
if (path.posix.isAbsolute(trimmed)) {
|
|
19
|
+
throw new Error('Path must be relative to the workspace root');
|
|
20
|
+
}
|
|
21
|
+
const normalized = path.posix.normalize(trimmed);
|
|
22
|
+
if (normalized === '.' || normalized.length === 0) {
|
|
23
|
+
throw new Error('Path must point to a file inside the workspace');
|
|
24
|
+
}
|
|
25
|
+
if (normalized === '..' || normalized.startsWith('../')) {
|
|
26
|
+
throw new Error('Path must stay inside the workspace');
|
|
27
|
+
}
|
|
28
|
+
return normalized;
|
|
29
|
+
}
|
|
30
|
+
const WorkspaceRelativePathSchema = z
|
|
31
|
+
.string()
|
|
32
|
+
.trim()
|
|
33
|
+
.min(1)
|
|
34
|
+
.transform((value, ctx) => {
|
|
35
|
+
try {
|
|
36
|
+
return normalizeWorkspaceRelativePath(value);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
ctx.addIssue({
|
|
40
|
+
code: z.ZodIssueCode.custom,
|
|
41
|
+
message: error instanceof Error ? error.message : 'Invalid workspace-relative path',
|
|
42
|
+
});
|
|
43
|
+
return z.NEVER;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const CloudDefaultDeployAgentSchema = z
|
|
47
|
+
.object({
|
|
48
|
+
type: z.literal('cloud-default'),
|
|
49
|
+
})
|
|
50
|
+
.strict();
|
|
51
|
+
const WorkspaceDeployAgentSchema = z
|
|
52
|
+
.object({
|
|
53
|
+
type: z.literal('workspace'),
|
|
54
|
+
path: WorkspaceRelativePathSchema.describe('Repo-relative path to the agent YAML that should boot in cloud'),
|
|
55
|
+
})
|
|
56
|
+
.strict();
|
|
57
|
+
export const DeployAgentSchema = z.discriminatedUnion('type', [
|
|
58
|
+
CloudDefaultDeployAgentSchema,
|
|
59
|
+
WorkspaceDeployAgentSchema,
|
|
60
|
+
]);
|
|
61
|
+
export const DeployConfigSchema = z
|
|
62
|
+
.object({
|
|
63
|
+
version: z.literal(1).default(1),
|
|
64
|
+
agent: DeployAgentSchema,
|
|
65
|
+
exclude: z.array(z.string().trim().min(1)).default([...DEFAULT_DEPLOY_EXCLUDES]),
|
|
66
|
+
})
|
|
67
|
+
.strict();
|
|
68
|
+
const LegacyDeployConfigSchema = z
|
|
69
|
+
.object({
|
|
70
|
+
version: z.literal(1).default(1),
|
|
71
|
+
entryAgent: WorkspaceRelativePathSchema.describe('Repo-relative path to the agent YAML that should boot in cloud'),
|
|
72
|
+
exclude: z.array(z.string().trim().min(1)).default([...DEFAULT_DEPLOY_EXCLUDES]),
|
|
73
|
+
})
|
|
74
|
+
.strict();
|
|
75
|
+
export function getDeployConfigPath(workspaceRoot) {
|
|
76
|
+
return path.join(workspaceRoot, DEPLOY_CONFIG_RELATIVE_PATH);
|
|
77
|
+
}
|
|
78
|
+
export async function loadDeployConfig(workspaceRoot) {
|
|
79
|
+
const configPath = getDeployConfigPath(workspaceRoot);
|
|
80
|
+
if (!existsSync(configPath)) {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
const raw = await fs.readFile(configPath, 'utf8');
|
|
84
|
+
let parsed;
|
|
85
|
+
try {
|
|
86
|
+
parsed = JSON.parse(raw);
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw new Error(`Failed to parse deploy config at ${configPath}: ${error instanceof Error ? error.message : 'Invalid JSON'}`);
|
|
90
|
+
}
|
|
91
|
+
return parseDeployConfig(parsed);
|
|
92
|
+
}
|
|
93
|
+
export async function saveDeployConfig(workspaceRoot, config) {
|
|
94
|
+
const normalized = DeployConfigSchema.parse(config);
|
|
95
|
+
const configPath = getDeployConfigPath(workspaceRoot);
|
|
96
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true });
|
|
97
|
+
await fs.writeFile(configPath, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8');
|
|
98
|
+
return normalized;
|
|
99
|
+
}
|
|
100
|
+
function parseDeployConfig(value) {
|
|
101
|
+
const parsed = DeployConfigSchema.safeParse(value);
|
|
102
|
+
if (parsed.success) {
|
|
103
|
+
return parsed.data;
|
|
104
|
+
}
|
|
105
|
+
const legacyParsed = LegacyDeployConfigSchema.safeParse(value);
|
|
106
|
+
if (legacyParsed.success) {
|
|
107
|
+
return createWorkspaceDeployConfig(legacyParsed.data.entryAgent, legacyParsed.data.exclude);
|
|
108
|
+
}
|
|
109
|
+
throw parsed.error;
|
|
110
|
+
}
|
|
111
|
+
export function createCloudDefaultDeployConfig(exclude = DEFAULT_DEPLOY_EXCLUDES) {
|
|
112
|
+
return DeployConfigSchema.parse({
|
|
113
|
+
version: 1,
|
|
114
|
+
agent: {
|
|
115
|
+
type: 'cloud-default',
|
|
116
|
+
},
|
|
117
|
+
exclude: [...exclude],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
export function createWorkspaceDeployConfig(agentPath, exclude = DEFAULT_DEPLOY_EXCLUDES) {
|
|
121
|
+
return DeployConfigSchema.parse({
|
|
122
|
+
version: 1,
|
|
123
|
+
agent: {
|
|
124
|
+
type: 'workspace',
|
|
125
|
+
path: agentPath,
|
|
126
|
+
},
|
|
127
|
+
exclude: [...exclude],
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
export function isWorkspaceDeployAgent(agent) {
|
|
131
|
+
return agent.type === 'workspace';
|
|
132
|
+
}
|
|
133
|
+
export function resolveWorkspaceDeployAgentPath(workspaceRoot, agentPath) {
|
|
134
|
+
const normalizedAgentPath = normalizeWorkspaceRelativePath(agentPath);
|
|
135
|
+
const resolvedPath = path.resolve(workspaceRoot, normalizedAgentPath);
|
|
136
|
+
const relativeToWorkspace = path.relative(path.resolve(workspaceRoot), resolvedPath);
|
|
137
|
+
if (relativeToWorkspace.length === 0 ||
|
|
138
|
+
relativeToWorkspace === '..' ||
|
|
139
|
+
relativeToWorkspace.startsWith(`..${path.sep}`) ||
|
|
140
|
+
path.isAbsolute(relativeToWorkspace)) {
|
|
141
|
+
throw new Error(`Workspace agent path must stay inside the workspace: ${agentPath}`);
|
|
142
|
+
}
|
|
143
|
+
return resolvedPath;
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entry-agent.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/entry-agent.ts"],"names":[],"mappings":"AAWA,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,wBAAgB,6BAA6B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWlF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { normalizeWorkspaceRelativePath } from './config.js';
|
|
4
|
+
const PRIMARY_WORKSPACE_AGENT_PATHS = [
|
|
5
|
+
path.join('agents', 'coding-agent', 'coding-agent.yml'),
|
|
6
|
+
path.join('agents', 'coding-agent', 'coding-agent.yaml'),
|
|
7
|
+
path.join('agents', 'coding-agent.yml'),
|
|
8
|
+
path.join('agents', 'coding-agent.yaml'),
|
|
9
|
+
];
|
|
10
|
+
export function isAgentYamlPath(filePath) {
|
|
11
|
+
return /\.(ya?ml)$/i.test(filePath);
|
|
12
|
+
}
|
|
13
|
+
export function discoverPrimaryWorkspaceAgent(workspaceRoot) {
|
|
14
|
+
for (const relativePath of PRIMARY_WORKSPACE_AGENT_PATHS) {
|
|
15
|
+
const absolutePath = path.join(workspaceRoot, relativePath);
|
|
16
|
+
if (!existsSync(absolutePath)) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
return normalizeWorkspaceRelativePath(relativePath);
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface InteractiveOptions {
|
|
2
|
+
interactive?: boolean;
|
|
3
|
+
}
|
|
4
|
+
export declare function handleDeployCommand(options?: InteractiveOptions): Promise<void>;
|
|
5
|
+
export declare function handleDeployStatusCommand(): Promise<void>;
|
|
6
|
+
export declare function handleDeployStopCommand(): Promise<void>;
|
|
7
|
+
export declare function handleDeployDeleteCommand(options?: InteractiveOptions): Promise<void>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/index.ts"],"names":[],"mappings":"AA0BA,UAAU,kBAAkB;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAwED,wBAAsB,mBAAmB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2ErF;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"}
|