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.
Files changed (68) hide show
  1. package/README.md +10 -2
  2. package/dist/analytics/events.d.ts +1 -1
  3. package/dist/analytics/events.d.ts.map +1 -1
  4. package/dist/cli/commands/agents/install.d.ts.map +1 -0
  5. package/dist/cli/commands/{install.js → agents/install.js} +4 -4
  6. package/dist/cli/commands/{list-agents.d.ts → agents/list.d.ts} +1 -1
  7. package/dist/cli/commands/agents/list.d.ts.map +1 -0
  8. package/dist/cli/commands/{list-agents.js → agents/list.js} +2 -2
  9. package/dist/cli/commands/agents/register.js +5 -5
  10. package/dist/cli/commands/{sync-agents.d.ts → agents/sync.d.ts} +10 -2
  11. package/dist/cli/commands/agents/sync.d.ts.map +1 -0
  12. package/dist/cli/commands/{sync-agents.js → agents/sync.js} +54 -5
  13. package/dist/cli/commands/agents/uninstall.d.ts +18 -0
  14. package/dist/cli/commands/agents/uninstall.d.ts.map +1 -0
  15. package/dist/cli/commands/agents/uninstall.js +141 -0
  16. package/dist/cli/commands/deploy/client.d.ts +44 -0
  17. package/dist/cli/commands/deploy/client.d.ts.map +1 -0
  18. package/dist/cli/commands/deploy/client.js +232 -0
  19. package/dist/cli/commands/deploy/config.d.ts +81 -0
  20. package/dist/cli/commands/deploy/config.d.ts.map +1 -0
  21. package/dist/cli/commands/deploy/config.js +144 -0
  22. package/dist/cli/commands/deploy/entry-agent.d.ts +3 -0
  23. package/dist/cli/commands/deploy/entry-agent.d.ts.map +1 -0
  24. package/dist/cli/commands/deploy/entry-agent.js +22 -0
  25. package/dist/cli/commands/deploy/index.d.ts +9 -0
  26. package/dist/cli/commands/deploy/index.d.ts.map +1 -0
  27. package/dist/cli/commands/deploy/index.js +204 -0
  28. package/dist/cli/commands/deploy/links.d.ts +3 -0
  29. package/dist/cli/commands/deploy/links.d.ts.map +1 -0
  30. package/dist/cli/commands/deploy/links.js +53 -0
  31. package/dist/cli/commands/deploy/register.d.ts +6 -0
  32. package/dist/cli/commands/deploy/register.d.ts.map +1 -0
  33. package/dist/cli/commands/deploy/register.js +75 -0
  34. package/dist/cli/commands/deploy/snapshot.d.ts +12 -0
  35. package/dist/cli/commands/deploy/snapshot.d.ts.map +1 -0
  36. package/dist/cli/commands/deploy/snapshot.js +76 -0
  37. package/dist/cli/commands/deploy/state.d.ts +21 -0
  38. package/dist/cli/commands/deploy/state.d.ts.map +1 -0
  39. package/dist/cli/commands/deploy/state.js +122 -0
  40. package/dist/cli/commands/index.d.ts +6 -4
  41. package/dist/cli/commands/index.d.ts.map +1 -1
  42. package/dist/cli/commands/index.js +6 -4
  43. package/dist/cli/commands/setup.d.ts.map +1 -1
  44. package/dist/cli/commands/setup.js +304 -31
  45. package/dist/cli/commands/uninstall.d.ts +9 -12
  46. package/dist/cli/commands/uninstall.d.ts.map +1 -1
  47. package/dist/cli/commands/uninstall.js +99 -113
  48. package/dist/cli/commands/upgrade.d.ts +15 -0
  49. package/dist/cli/commands/upgrade.d.ts.map +1 -0
  50. package/dist/cli/commands/upgrade.js +106 -0
  51. package/dist/cli/modes/cli.d.ts.map +1 -1
  52. package/dist/cli/modes/cli.js +0 -12
  53. package/dist/cli/utils/config-validation.d.ts.map +1 -1
  54. package/dist/cli/utils/config-validation.js +34 -20
  55. package/dist/cli/utils/self-management.d.ts +93 -0
  56. package/dist/cli/utils/self-management.d.ts.map +1 -0
  57. package/dist/cli/utils/self-management.js +423 -0
  58. package/dist/cli/utils/version-check.d.ts +1 -1
  59. package/dist/cli/utils/version-check.d.ts.map +1 -1
  60. package/dist/cli/utils/version-check.js +53 -19
  61. package/dist/index-main.js +59 -2
  62. package/dist/webui/assets/{index-CNiOYnOb.js → index-UDAdxmci.js} +187 -187
  63. package/dist/webui/index.html +1 -1
  64. package/package.json +13 -11
  65. package/dist/cli/commands/install.d.ts.map +0 -1
  66. package/dist/cli/commands/list-agents.d.ts.map +0 -1
  67. package/dist/cli/commands/sync-agents.d.ts.map +0 -1
  68. /package/dist/cli/commands/{install.d.ts → agents/install.d.ts} +0 -0
@@ -0,0 +1,204 @@
1
+ import { existsSync } from 'fs';
2
+ import path from 'path';
3
+ import * as p from '@clack/prompts';
4
+ import { findDextoProjectRoot } from '@dexto/agent-management';
5
+ import chalk from 'chalk';
6
+ import { confirmOrExit } from '../../utils/prompt-helpers.js';
7
+ import { createCloudDefaultDeployConfig, createWorkspaceDeployConfig, getDeployConfigPath, isWorkspaceDeployAgent, loadDeployConfig, resolveWorkspaceDeployAgentPath, saveDeployConfig, } from './config.js';
8
+ import { createDeployClient } from './client.js';
9
+ import { discoverPrimaryWorkspaceAgent, isAgentYamlPath } from './entry-agent.js';
10
+ import { getCloudAgentDashboardUrl } from './links.js';
11
+ import { loadWorkspaceDeployLink, removeWorkspaceDeployLink, saveWorkspaceDeployLink, } from './state.js';
12
+ import { createWorkspaceSnapshot } from './snapshot.js';
13
+ function isInteractive(options) {
14
+ return options?.interactive !== false;
15
+ }
16
+ function describeDeployAgent(config) {
17
+ if (isWorkspaceDeployAgent(config.agent)) {
18
+ return `workspace agent (${config.agent.path})`;
19
+ }
20
+ return 'default cloud agent';
21
+ }
22
+ function formatCloudAgentSummary(input) {
23
+ return [
24
+ `Cloud agent: ${input.cloudAgentId}`,
25
+ `Status: ${input.status}`,
26
+ `Agent URL: ${input.agentUrl}`,
27
+ `Dashboard: ${getCloudAgentDashboardUrl(input.cloudAgentId)}`,
28
+ ].join('\n');
29
+ }
30
+ function getErrorMessage(error) {
31
+ return error instanceof Error ? error.message : String(error);
32
+ }
33
+ function resolveWorkspaceRoot() {
34
+ return findDextoProjectRoot(process.cwd()) ?? process.cwd();
35
+ }
36
+ async function resolveDeployConfig(workspaceRoot) {
37
+ const existingConfig = await loadDeployConfig(workspaceRoot);
38
+ if (existingConfig) {
39
+ return existingConfig;
40
+ }
41
+ const primaryWorkspaceAgent = await discoverPrimaryWorkspaceAgent(workspaceRoot);
42
+ const nextConfig = primaryWorkspaceAgent
43
+ ? createWorkspaceDeployConfig(primaryWorkspaceAgent)
44
+ : createCloudDefaultDeployConfig();
45
+ await saveDeployConfig(workspaceRoot, nextConfig);
46
+ p.note(`${describeDeployAgent(nextConfig)}\n${path.relative(workspaceRoot, getDeployConfigPath(workspaceRoot))}`, 'Saved deploy config');
47
+ return nextConfig;
48
+ }
49
+ function ensureWorkspaceAgentExists(workspaceRoot, config) {
50
+ if (!isWorkspaceDeployAgent(config.agent)) {
51
+ return null;
52
+ }
53
+ const entryAgentPath = resolveWorkspaceDeployAgentPath(workspaceRoot, config.agent.path);
54
+ if (!existsSync(entryAgentPath)) {
55
+ throw new Error(`Workspace agent not found: ${config.agent.path}. Update ${path.relative(workspaceRoot, getDeployConfigPath(workspaceRoot))} before deploying.`);
56
+ }
57
+ if (!isAgentYamlPath(config.agent.path)) {
58
+ throw new Error(`Workspace agent must be a .yml or .yaml file: ${config.agent.path}`);
59
+ }
60
+ return entryAgentPath;
61
+ }
62
+ export async function handleDeployCommand(options) {
63
+ void options;
64
+ p.intro(chalk.inverse('Deploy Workspace'));
65
+ const workspaceRoot = resolveWorkspaceRoot();
66
+ const deployConfig = await resolveDeployConfig(workspaceRoot);
67
+ ensureWorkspaceAgentExists(workspaceRoot, deployConfig);
68
+ const deployLink = await loadWorkspaceDeployLink(workspaceRoot);
69
+ const spinner = p.spinner();
70
+ const client = createDeployClient();
71
+ const workspaceSnapshotInput = isWorkspaceDeployAgent(deployConfig.agent)
72
+ ? {
73
+ workspaceRoot,
74
+ workspaceAgentPath: deployConfig.agent.path,
75
+ exclude: deployConfig.exclude,
76
+ }
77
+ : {
78
+ workspaceRoot,
79
+ exclude: deployConfig.exclude,
80
+ };
81
+ let snapshot = null;
82
+ try {
83
+ spinner.start('Packaging workspace snapshot...');
84
+ snapshot = await createWorkspaceSnapshot({
85
+ ...workspaceSnapshotInput,
86
+ });
87
+ spinner.message('Uploading workspace and provisioning sandbox...');
88
+ const deployed = await client.deployWorkspace({
89
+ agent: deployConfig.agent,
90
+ snapshotPath: snapshot.archivePath,
91
+ ...(deployLink?.cloudAgentId ? { cloudAgentId: deployLink.cloudAgentId } : {}),
92
+ });
93
+ let linkSyncError = null;
94
+ try {
95
+ await saveWorkspaceDeployLink(workspaceRoot, {
96
+ cloudAgentId: deployed.cloudAgentId,
97
+ agentUrl: deployed.agentUrl,
98
+ });
99
+ }
100
+ catch (error) {
101
+ linkSyncError = error;
102
+ }
103
+ spinner.stop(chalk.green('✓ Workspace deployed'));
104
+ p.outro([
105
+ formatCloudAgentSummary({
106
+ cloudAgentId: deployed.cloudAgentId,
107
+ status: deployed.state.status,
108
+ agentUrl: deployed.agentUrl,
109
+ }),
110
+ ...(linkSyncError
111
+ ? [
112
+ '',
113
+ `Warning: deployment succeeded, but failed to save local link state (${getErrorMessage(linkSyncError)})`,
114
+ 'Run `dexto deploy` again in this workspace to re-link.',
115
+ ]
116
+ : []),
117
+ '',
118
+ 'Next steps:',
119
+ `- Open the dashboard to inspect and interact with the deployment`,
120
+ `- Run \`dexto deploy status\` from this workspace`,
121
+ ].join('\n'));
122
+ }
123
+ catch (error) {
124
+ spinner.stop(chalk.red('✗ Deploy failed'));
125
+ throw error;
126
+ }
127
+ finally {
128
+ if (snapshot) {
129
+ await snapshot.cleanup();
130
+ }
131
+ }
132
+ }
133
+ export async function handleDeployStatusCommand() {
134
+ const workspaceRoot = resolveWorkspaceRoot();
135
+ const deployLink = await loadWorkspaceDeployLink(workspaceRoot);
136
+ if (!deployLink) {
137
+ throw new Error('This workspace is not linked to a cloud deployment yet. Run `dexto deploy` first.');
138
+ }
139
+ const client = createDeployClient();
140
+ const status = await client.getCloudAgent(deployLink.cloudAgentId);
141
+ p.outro(formatCloudAgentSummary({
142
+ cloudAgentId: status.cloudAgentId,
143
+ status: status.state.status,
144
+ agentUrl: status.agentUrl,
145
+ }));
146
+ }
147
+ export async function handleDeployStopCommand() {
148
+ const workspaceRoot = resolveWorkspaceRoot();
149
+ const deployLink = await loadWorkspaceDeployLink(workspaceRoot);
150
+ if (!deployLink) {
151
+ throw new Error('This workspace is not linked to a cloud deployment yet. Run `dexto deploy` first.');
152
+ }
153
+ const spinner = p.spinner();
154
+ spinner.start('Stopping cloud sandbox...');
155
+ try {
156
+ const client = createDeployClient();
157
+ const result = await client.stopCloudAgent(deployLink.cloudAgentId);
158
+ spinner.stop(chalk.green('✓ Cloud sandbox stopped'));
159
+ p.outro([
160
+ `Cloud agent: ${result.cloudAgentId}`,
161
+ `Stopped: ${result.stopped ? 'yes' : 'no'}`,
162
+ `Already stopped: ${result.alreadyStopped ? 'yes' : 'no'}`,
163
+ `Snapshot status: ${result.snapshotStatus}`,
164
+ ].join('\n'));
165
+ }
166
+ catch (error) {
167
+ spinner.stop(chalk.red('✗ Stop failed'));
168
+ throw error;
169
+ }
170
+ }
171
+ export async function handleDeployDeleteCommand(options) {
172
+ const workspaceRoot = resolveWorkspaceRoot();
173
+ const deployLink = await loadWorkspaceDeployLink(workspaceRoot);
174
+ if (!deployLink) {
175
+ throw new Error('This workspace is not linked to a cloud deployment yet. Run `dexto deploy` first.');
176
+ }
177
+ if (isInteractive(options)) {
178
+ await confirmOrExit({
179
+ message: `Delete cloud deployment ${deployLink.cloudAgentId}?`,
180
+ initialValue: false,
181
+ }, 'Delete cancelled');
182
+ }
183
+ const spinner = p.spinner();
184
+ spinner.start('Deleting cloud deployment...');
185
+ try {
186
+ const client = createDeployClient();
187
+ const result = await client.deleteCloudAgent(deployLink.cloudAgentId);
188
+ let linkRemoveError = null;
189
+ try {
190
+ await removeWorkspaceDeployLink(workspaceRoot);
191
+ }
192
+ catch (error) {
193
+ linkRemoveError = error;
194
+ }
195
+ spinner.stop(chalk.green('✓ Cloud deployment deleted'));
196
+ p.outro(linkRemoveError
197
+ ? `Deleted ${result.cloudAgentId}\nWarning: failed to remove local deploy link state (${getErrorMessage(linkRemoveError)})`
198
+ : `Deleted ${result.cloudAgentId}`);
199
+ }
200
+ catch (error) {
201
+ spinner.stop(chalk.red('✗ Delete failed'));
202
+ throw error;
203
+ }
204
+ }
@@ -0,0 +1,3 @@
1
+ export declare function resolveDashboardBaseUrl(): string;
2
+ export declare function getCloudAgentDashboardUrl(cloudAgentId: string): string;
3
+ //# sourceMappingURL=links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"links.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/links.ts"],"names":[],"mappings":"AAgCA,wBAAgB,uBAAuB,IAAI,MAAM,CA2BhD;AAED,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEtE"}
@@ -0,0 +1,53 @@
1
+ const APP_URL_ENV_VAR = 'DEXTO_APP_URL';
2
+ const SANDBOX_URL_ENV_VAR = 'DEXTO_SANDBOX_URL';
3
+ const DEFAULT_APP_URL = 'https://app.dexto.ai';
4
+ const LOCAL_DASHBOARD_URL = 'http://localhost:5173';
5
+ function normalizeBaseUrl(value) {
6
+ const trimmed = value?.trim();
7
+ if (!trimmed) {
8
+ return null;
9
+ }
10
+ try {
11
+ const url = new URL(trimmed);
12
+ url.pathname = '';
13
+ url.search = '';
14
+ url.hash = '';
15
+ return url.toString().replace(/\/$/, '');
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ function isLocalHostUrl(value) {
22
+ const normalized = normalizeBaseUrl(value);
23
+ if (!normalized) {
24
+ return false;
25
+ }
26
+ const hostname = new URL(normalized).hostname;
27
+ return hostname === 'localhost' || hostname === '127.0.0.1';
28
+ }
29
+ export function resolveDashboardBaseUrl() {
30
+ const explicitAppUrl = normalizeBaseUrl(process.env[APP_URL_ENV_VAR]);
31
+ if (explicitAppUrl) {
32
+ return explicitAppUrl;
33
+ }
34
+ if (isLocalHostUrl(process.env[SANDBOX_URL_ENV_VAR]) ||
35
+ isLocalHostUrl(process.env.DEXTO_API_URL)) {
36
+ return LOCAL_DASHBOARD_URL;
37
+ }
38
+ const normalizedApiUrl = normalizeBaseUrl(process.env.DEXTO_API_URL);
39
+ if (normalizedApiUrl) {
40
+ const apiUrl = new URL(normalizedApiUrl);
41
+ if (apiUrl.hostname === 'api.dexto.ai') {
42
+ return DEFAULT_APP_URL;
43
+ }
44
+ if (apiUrl.hostname.startsWith('api.')) {
45
+ apiUrl.hostname = `app.${apiUrl.hostname.slice('api.'.length)}`;
46
+ return apiUrl.toString().replace(/\/$/, '');
47
+ }
48
+ }
49
+ return DEFAULT_APP_URL;
50
+ }
51
+ export function getCloudAgentDashboardUrl(cloudAgentId) {
52
+ return `${resolveDashboardBaseUrl()}/dashboard/cloud-agents/${encodeURIComponent(cloudAgentId)}`;
53
+ }
@@ -0,0 +1,6 @@
1
+ import type { Command } from 'commander';
2
+ export interface DeployCommandRegisterContext {
3
+ program: Command;
4
+ }
5
+ export declare function registerDeployCommand({ program }: DeployCommandRegisterContext): void;
6
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +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,CAiFrF"}
@@ -0,0 +1,75 @@
1
+ import { ExitSignal, safeExit, withAnalytics } from '../../../analytics/wrapper.js';
2
+ export function registerDeployCommand({ program }) {
3
+ const deployCommand = program
4
+ .command('deploy')
5
+ .description('Deploy the current workspace to a cloud sandbox');
6
+ deployCommand.addHelpText('after', `
7
+ Examples:
8
+ $ dexto deploy
9
+ $ dexto deploy status
10
+ $ dexto deploy stop
11
+ $ dexto deploy delete
12
+ `);
13
+ deployCommand.option('--no-interactive', 'Disable interactive prompts').action(withAnalytics('deploy', async (options) => {
14
+ try {
15
+ const { handleDeployCommand } = await import('./index.js');
16
+ await handleDeployCommand(options);
17
+ safeExit('deploy', 0);
18
+ }
19
+ catch (err) {
20
+ if (err instanceof ExitSignal)
21
+ throw err;
22
+ console.error(`❌ dexto deploy command failed: ${err}`);
23
+ safeExit('deploy', 1, 'error');
24
+ }
25
+ }));
26
+ deployCommand
27
+ .command('status')
28
+ .description('Show the linked cloud deployment for the current workspace')
29
+ .action(withAnalytics('deploy status', async () => {
30
+ try {
31
+ const { handleDeployStatusCommand } = await import('./index.js');
32
+ await handleDeployStatusCommand();
33
+ safeExit('deploy status', 0);
34
+ }
35
+ catch (err) {
36
+ if (err instanceof ExitSignal)
37
+ throw err;
38
+ console.error(`❌ dexto deploy status command failed: ${err}`);
39
+ safeExit('deploy status', 1, 'error');
40
+ }
41
+ }));
42
+ deployCommand
43
+ .command('stop')
44
+ .description('Stop the linked cloud sandbox for the current workspace')
45
+ .action(withAnalytics('deploy stop', async () => {
46
+ try {
47
+ const { handleDeployStopCommand } = await import('./index.js');
48
+ await handleDeployStopCommand();
49
+ safeExit('deploy stop', 0);
50
+ }
51
+ catch (err) {
52
+ if (err instanceof ExitSignal)
53
+ throw err;
54
+ console.error(`❌ dexto deploy stop command failed: ${err}`);
55
+ safeExit('deploy stop', 1, 'error');
56
+ }
57
+ }));
58
+ deployCommand
59
+ .command('delete')
60
+ .description('Delete the linked cloud deployment and unlink this workspace')
61
+ .option('--no-interactive', 'Disable confirmation prompts')
62
+ .action(withAnalytics('deploy delete', async (options) => {
63
+ try {
64
+ const { handleDeployDeleteCommand } = await import('./index.js');
65
+ await handleDeployDeleteCommand(options);
66
+ safeExit('deploy delete', 0);
67
+ }
68
+ catch (err) {
69
+ if (err instanceof ExitSignal)
70
+ throw err;
71
+ console.error(`❌ dexto deploy delete command failed: ${err}`);
72
+ safeExit('deploy delete', 1, 'error');
73
+ }
74
+ }));
75
+ }
@@ -0,0 +1,12 @@
1
+ export interface WorkspaceSnapshotResult {
2
+ archivePath: string;
3
+ sizeBytes: number;
4
+ cleanup: () => Promise<void>;
5
+ }
6
+ export declare function shouldExcludeRelativePath(relativePath: string, excludePatterns: string[]): boolean;
7
+ export declare function createWorkspaceSnapshot(input: {
8
+ workspaceRoot: string;
9
+ workspaceAgentPath?: string;
10
+ exclude: string[];
11
+ }): Promise<WorkspaceSnapshotResult>;
12
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/snapshot.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,uBAAuB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAiBD,wBAAgB,yBAAyB,CACrC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,EAAE,GAC1B,OAAO,CAoBT;AAED,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACjD,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;CACrB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAiDnC"}
@@ -0,0 +1,76 @@
1
+ import { promises as fs } from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { minimatch } from 'minimatch';
5
+ import { create as createTar } from 'tar';
6
+ import { normalizeWorkspaceRelativePath } from './config.js';
7
+ function normalizeArchivePath(value) {
8
+ return value
9
+ .replace(/\\/g, '/')
10
+ .replace(/^\.\/+/, '')
11
+ .replace(/\/+$/, '');
12
+ }
13
+ function normalizeExcludePattern(value) {
14
+ return value
15
+ .trim()
16
+ .replace(/\\/g, '/')
17
+ .replace(/^\.\/+/, '')
18
+ .replace(/\/+$/, '');
19
+ }
20
+ export function shouldExcludeRelativePath(relativePath, excludePatterns) {
21
+ const normalizedRelativePath = normalizeWorkspaceRelativePath(relativePath);
22
+ const basename = path.posix.basename(normalizedRelativePath);
23
+ return excludePatterns.some((pattern) => {
24
+ const normalizedPattern = normalizeExcludePattern(pattern);
25
+ if (normalizedPattern.length === 0) {
26
+ return false;
27
+ }
28
+ if (normalizedRelativePath === normalizedPattern ||
29
+ normalizedRelativePath.startsWith(`${normalizedPattern}/`)) {
30
+ return true;
31
+ }
32
+ return (minimatch(normalizedRelativePath, normalizedPattern, { dot: true }) ||
33
+ minimatch(basename, normalizedPattern, { dot: true }));
34
+ });
35
+ }
36
+ export async function createWorkspaceSnapshot(input) {
37
+ const workspaceRoot = path.resolve(input.workspaceRoot);
38
+ const workspaceAgentPath = typeof input.workspaceAgentPath === 'string'
39
+ ? normalizeWorkspaceRelativePath(input.workspaceAgentPath)
40
+ : null;
41
+ if (workspaceAgentPath && shouldExcludeRelativePath(workspaceAgentPath, input.exclude)) {
42
+ throw new Error(`Deploy config excludes the selected workspace agent: ${workspaceAgentPath}. Remove it from exclude before deploying.`);
43
+ }
44
+ const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'dexto-deploy-'));
45
+ const archivePath = path.join(tempDir, 'workspace.tar.gz');
46
+ const topLevelEntries = await fs.readdir(workspaceRoot);
47
+ try {
48
+ await createTar({
49
+ cwd: workspaceRoot,
50
+ file: archivePath,
51
+ gzip: true,
52
+ portable: true,
53
+ noMtime: true,
54
+ prefix: 'workspace',
55
+ filter: (entryPath) => {
56
+ const relativePath = normalizeArchivePath(entryPath);
57
+ if (relativePath.length === 0) {
58
+ return false;
59
+ }
60
+ return !shouldExcludeRelativePath(relativePath, input.exclude);
61
+ },
62
+ }, topLevelEntries);
63
+ const stats = await fs.stat(archivePath);
64
+ return {
65
+ archivePath,
66
+ sizeBytes: stats.size,
67
+ cleanup: async () => {
68
+ await fs.rm(tempDir, { recursive: true, force: true });
69
+ },
70
+ };
71
+ }
72
+ catch (error) {
73
+ await fs.rm(tempDir, { recursive: true, force: true });
74
+ throw error;
75
+ }
76
+ }
@@ -0,0 +1,21 @@
1
+ import { z } from 'zod';
2
+ declare const DeployLinkSchema: z.ZodObject<{
3
+ cloudAgentId: z.ZodString;
4
+ agentUrl: z.ZodOptional<z.ZodString>;
5
+ updatedAt: z.ZodString;
6
+ }, "strict", z.ZodTypeAny, {
7
+ cloudAgentId: string;
8
+ updatedAt: string;
9
+ agentUrl?: string | undefined;
10
+ }, {
11
+ cloudAgentId: string;
12
+ updatedAt: string;
13
+ agentUrl?: string | undefined;
14
+ }>;
15
+ export type DeployLink = z.output<typeof DeployLinkSchema>;
16
+ type DeployLinkInput = Pick<z.input<typeof DeployLinkSchema>, 'cloudAgentId' | 'agentUrl'>;
17
+ export declare function loadWorkspaceDeployLink(workspaceRoot: string): Promise<DeployLink | null>;
18
+ export declare function saveWorkspaceDeployLink(workspaceRoot: string, link: DeployLinkInput): Promise<void>;
19
+ export declare function removeWorkspaceDeployLink(workspaceRoot: string): Promise<void>;
20
+ export {};
21
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/deploy/state.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,QAAA,MAAM,gBAAgB;;;;;;;;;;;;EAMT,CAAC;AASd,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC3D,KAAK,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,EAAE,cAAc,GAAG,UAAU,CAAC,CAAC;AA4F3F,wBAAsB,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAG/F;AAED,wBAAsB,uBAAuB,CACzC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,eAAe,GACtB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,yBAAyB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpF"}
@@ -0,0 +1,122 @@
1
+ import { existsSync, promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import { setTimeout as delay } from 'timers/promises';
4
+ import { getDextoGlobalPath } from '@dexto/core';
5
+ import { z } from 'zod';
6
+ const DEPLOY_LINKS_FILENAME = 'links.json';
7
+ const DEPLOY_LOCK_SUFFIX = '.lock';
8
+ const DEPLOY_LOCK_RETRY_MS = 25;
9
+ const DEPLOY_LOCK_TIMEOUT_MS = 5_000;
10
+ const DEPLOY_LOCK_STALE_MS = DEPLOY_LOCK_TIMEOUT_MS;
11
+ const DeployLinkSchema = z
12
+ .object({
13
+ cloudAgentId: z.string().trim().min(1),
14
+ agentUrl: z.string().trim().min(1).optional(),
15
+ updatedAt: z.string().datetime(),
16
+ })
17
+ .strict();
18
+ const DeployStateSchema = z
19
+ .object({
20
+ version: z.literal(1).default(1),
21
+ links: z.record(z.string(), DeployLinkSchema).default({}),
22
+ })
23
+ .strict();
24
+ function getDeployLinksPath() {
25
+ return getDextoGlobalPath('deployments', DEPLOY_LINKS_FILENAME);
26
+ }
27
+ function getDeployLockPath(filePath) {
28
+ return `${filePath}${DEPLOY_LOCK_SUFFIX}`;
29
+ }
30
+ function normalizeWorkspaceKey(workspaceRoot) {
31
+ return path.resolve(workspaceRoot);
32
+ }
33
+ async function loadDeployStateFromPath(filePath) {
34
+ if (!existsSync(filePath)) {
35
+ return DeployStateSchema.parse({ version: 1, links: {} });
36
+ }
37
+ const raw = await fs.readFile(filePath, 'utf8');
38
+ return DeployStateSchema.parse(JSON.parse(raw));
39
+ }
40
+ async function loadDeployState() {
41
+ return loadDeployStateFromPath(getDeployLinksPath());
42
+ }
43
+ async function writeDeployStateAtomic(filePath, state) {
44
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
45
+ const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
46
+ try {
47
+ await fs.writeFile(tempPath, `${JSON.stringify(state, null, 2)}\n`, 'utf8');
48
+ await fs.rename(tempPath, filePath);
49
+ }
50
+ catch (error) {
51
+ await fs.rm(tempPath, { force: true }).catch(() => undefined);
52
+ throw error;
53
+ }
54
+ }
55
+ async function reclaimStaleDeployLock(lockPath) {
56
+ try {
57
+ const stat = await fs.stat(lockPath);
58
+ if (Date.now() - stat.mtimeMs < DEPLOY_LOCK_STALE_MS) {
59
+ return false;
60
+ }
61
+ await fs.rm(lockPath, { recursive: true, force: true });
62
+ return true;
63
+ }
64
+ catch (error) {
65
+ if (error.code === 'ENOENT') {
66
+ return true;
67
+ }
68
+ throw error;
69
+ }
70
+ }
71
+ async function withDeployStateLock(operation) {
72
+ const filePath = getDeployLinksPath();
73
+ const lockPath = getDeployLockPath(filePath);
74
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
75
+ const deadline = Date.now() + DEPLOY_LOCK_TIMEOUT_MS;
76
+ for (;;) {
77
+ try {
78
+ await fs.mkdir(lockPath);
79
+ break;
80
+ }
81
+ catch (error) {
82
+ if (error.code !== 'EEXIST') {
83
+ throw error;
84
+ }
85
+ if (await reclaimStaleDeployLock(lockPath)) {
86
+ continue;
87
+ }
88
+ if (Date.now() >= deadline) {
89
+ throw new Error(`Timed out waiting for deploy state lock: ${lockPath}`);
90
+ }
91
+ await delay(DEPLOY_LOCK_RETRY_MS);
92
+ }
93
+ }
94
+ try {
95
+ return await operation(filePath);
96
+ }
97
+ finally {
98
+ await fs.rm(lockPath, { recursive: true, force: true });
99
+ }
100
+ }
101
+ export async function loadWorkspaceDeployLink(workspaceRoot) {
102
+ const state = await loadDeployState();
103
+ return state.links[normalizeWorkspaceKey(workspaceRoot)] ?? null;
104
+ }
105
+ export async function saveWorkspaceDeployLink(workspaceRoot, link) {
106
+ await withDeployStateLock(async (filePath) => {
107
+ const state = await loadDeployStateFromPath(filePath);
108
+ state.links[normalizeWorkspaceKey(workspaceRoot)] = DeployLinkSchema.parse({
109
+ cloudAgentId: link.cloudAgentId,
110
+ agentUrl: link.agentUrl,
111
+ updatedAt: new Date().toISOString(),
112
+ });
113
+ await writeDeployStateAtomic(filePath, state);
114
+ });
115
+ }
116
+ export async function removeWorkspaceDeployLink(workspaceRoot) {
117
+ await withDeployStateLock(async (filePath) => {
118
+ const state = await loadDeployStateFromPath(filePath);
119
+ delete state.links[normalizeWorkspaceKey(workspaceRoot)];
120
+ await writeDeployStateAtomic(filePath, state);
121
+ });
122
+ }
@@ -2,11 +2,13 @@ export { createDextoProject, type CreateAppOptions } from './create-app.js';
2
2
  export { createImage } from './create-image.js';
3
3
  export { getUserInputToInitDextoApp, initDexto, postInitDexto } from './init-app.js';
4
4
  export { handleSetupCommand, type CLISetupOptions, type CLISetupOptionsInput } from './setup.js';
5
- export { handleInstallCommand, type InstallCommandOptions } from './install.js';
6
- export { handleUninstallCommand, type UninstallCommandOptions } from './uninstall.js';
7
- export { handleListAgentsCommand, type ListAgentsCommandOptions, type ListAgentsCommandOptionsInput, } from './list-agents.js';
5
+ export { handleInstallCommand, type InstallCommandOptions } from './agents/install.js';
6
+ export { handleUninstallCommand, type UninstallCommandOptions } from './agents/uninstall.js';
7
+ export { handleUpgradeCommand, type UpgradeCommandOptions } from './upgrade.js';
8
+ export { handleUninstallCliCommand, type UninstallCliCommandOptions } from './uninstall.js';
9
+ export { handleListAgentsCommand, type ListAgentsCommandOptions, type ListAgentsCommandOptionsInput, } from './agents/list.js';
8
10
  export { handleWhichCommand, type WhichCommandOptions } from './which.js';
9
- export { handleSyncAgentsCommand, shouldPromptForSync, type SyncAgentsCommandOptions, } from './sync-agents.js';
11
+ export { handleSyncAgentsCommand, shouldPromptForSync, type SyncAgentsCommandOptions, } from './agents/sync.js';
10
12
  export { handleImageInstallCommand, handleImageListCommand, handleImageUseCommand, handleImageRemoveCommand, handleImageDoctorCommand, type ImageInstallCommandOptions, type ImageInstallCommandOptionsInput, } from './image.js';
11
13
  export { handleLoginCommand, handleLogoutCommand, handleStatusCommand } from './auth/index.js';
12
14
  export { handleBillingStatusCommand } from './billing/index.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAE5E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,0BAA0B,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAErF,OAAO,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,sBAAsB,EAAE,KAAK,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACtF,OAAO,EACH,uBAAuB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,GACrC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EACH,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,wBAAwB,GAChC,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACH,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,+BAA+B,GACvC,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG/F,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAGhE,OAAO,EACH,uBAAuB,EACvB,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,EAE3B,2BAA2B,EAC3B,8BAA8B,EAC9B,8BAA8B,EAC9B,4BAA4B,EAC5B,+BAA+B,EAC/B,+BAA+B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACrC,KAAK,6BAA6B,EAClC,KAAK,kCAAkC,EACvC,KAAK,4BAA4B,EACjC,KAAK,iCAAiC,EAEtC,KAAK,iCAAiC,EACtC,KAAK,oCAAoC,EACzC,KAAK,oCAAoC,EACzC,KAAK,kCAAkC,EACvC,KAAK,qCAAqC,GAC7C,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAE5E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,0BAA0B,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAErF,OAAO,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,YAAY,CAAC;AACjG,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,KAAK,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAChF,OAAO,EAAE,yBAAyB,EAAE,KAAK,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5F,OAAO,EACH,uBAAuB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,GACrC,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC1E,OAAO,EACH,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,wBAAwB,GAChC,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACH,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,+BAA+B,GACvC,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG/F,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAGhE,OAAO,EACH,uBAAuB,EACvB,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,EAE3B,2BAA2B,EAC3B,8BAA8B,EAC9B,8BAA8B,EAC9B,4BAA4B,EAC5B,+BAA+B,EAC/B,+BAA+B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,gCAAgC,EACrC,KAAK,6BAA6B,EAClC,KAAK,kCAAkC,EACvC,KAAK,4BAA4B,EACjC,KAAK,iCAAiC,EAEtC,KAAK,iCAAiC,EACtC,KAAK,oCAAoC,EACzC,KAAK,oCAAoC,EACzC,KAAK,kCAAkC,EACvC,KAAK,qCAAqC,GAC7C,MAAM,aAAa,CAAC"}
@@ -4,11 +4,13 @@ export { createDextoProject } from './create-app.js';
4
4
  export { createImage } from './create-image.js';
5
5
  export { getUserInputToInitDextoApp, initDexto, postInitDexto } from './init-app.js';
6
6
  export { handleSetupCommand } from './setup.js';
7
- export { handleInstallCommand } from './install.js';
8
- export { handleUninstallCommand } from './uninstall.js';
9
- export { handleListAgentsCommand, } from './list-agents.js';
7
+ export { handleInstallCommand } from './agents/install.js';
8
+ export { handleUninstallCommand } from './agents/uninstall.js';
9
+ export { handleUpgradeCommand } from './upgrade.js';
10
+ export { handleUninstallCliCommand } from './uninstall.js';
11
+ export { handleListAgentsCommand, } from './agents/list.js';
10
12
  export { handleWhichCommand } from './which.js';
11
- export { handleSyncAgentsCommand, shouldPromptForSync, } from './sync-agents.js';
13
+ export { handleSyncAgentsCommand, shouldPromptForSync, } from './agents/sync.js';
12
14
  // Image commands
13
15
  export { handleImageInstallCommand, handleImageListCommand, handleImageUseCommand, handleImageRemoveCommand, handleImageDoctorCommand, } from './image.js';
14
16
  // Auth commands
@@ -1 +1 @@
1
- {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAuDxB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0ClB,CAAC;AAEP,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAClE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AA6JtE;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC9F"}
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/setup.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA6DxB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0ClB,CAAC;AAEP,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAClE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AA6JtE;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC9F"}