@amodalai/amodal 0.3.89 → 0.3.91
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/CHANGELOG.md +46 -0
- package/dist/src/commands/audit.d.ts +1 -3
- package/dist/src/commands/audit.d.ts.map +1 -1
- package/dist/src/commands/audit.js +4 -53
- package/dist/src/commands/audit.js.map +1 -1
- package/dist/src/commands/build-manifest-types.js +1 -1
- package/dist/src/commands/build-tools.d.ts +3 -10
- package/dist/src/commands/build-tools.d.ts.map +1 -1
- package/dist/src/commands/build-tools.js +5 -118
- package/dist/src/commands/build-tools.js.map +1 -1
- package/dist/src/commands/build.d.ts +23 -5
- package/dist/src/commands/build.d.ts.map +1 -1
- package/dist/src/commands/build.js +53 -34
- package/dist/src/commands/build.js.map +1 -1
- package/dist/src/commands/chat.d.ts +1 -1
- package/dist/src/commands/chat.js +5 -5
- package/dist/src/commands/chat.js.map +1 -1
- package/dist/src/commands/deploy.d.ts +1 -1
- package/dist/src/commands/deploy.d.ts.map +1 -1
- package/dist/src/commands/deploy.js +3 -61
- package/dist/src/commands/deploy.js.map +1 -1
- package/dist/src/commands/deployments.d.ts.map +1 -1
- package/dist/src/commands/deployments.js +3 -36
- package/dist/src/commands/deployments.js.map +1 -1
- package/dist/src/commands/dev.d.ts.map +1 -1
- package/dist/src/commands/dev.js +7 -10
- package/dist/src/commands/dev.js.map +1 -1
- package/dist/src/commands/experiment.d.ts +1 -3
- package/dist/src/commands/experiment.d.ts.map +1 -1
- package/dist/src/commands/experiment.js +4 -102
- package/dist/src/commands/experiment.js.map +1 -1
- package/dist/src/commands/promote.d.ts.map +1 -1
- package/dist/src/commands/promote.js +3 -21
- package/dist/src/commands/promote.js.map +1 -1
- package/dist/src/commands/rollback.d.ts.map +1 -1
- package/dist/src/commands/rollback.js +3 -24
- package/dist/src/commands/rollback.js.map +1 -1
- package/dist/src/commands/secrets.d.ts.map +1 -1
- package/dist/src/commands/secrets.js +2 -102
- package/dist/src/commands/secrets.js.map +1 -1
- package/dist/src/commands/serve.d.ts +2 -11
- package/dist/src/commands/serve.d.ts.map +1 -1
- package/dist/src/commands/serve.js +44 -87
- package/dist/src/commands/serve.js.map +1 -1
- package/dist/src/commands/status.d.ts.map +1 -1
- package/dist/src/commands/status.js +3 -49
- package/dist/src/commands/status.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -8
- package/src/commands/audit.ts +4 -71
- package/src/commands/build-manifest-types.ts +1 -1
- package/src/commands/build-tools.ts +5 -142
- package/src/commands/build.test.ts +14 -9
- package/src/commands/build.ts +73 -33
- package/src/commands/chat.ts +5 -5
- package/src/commands/deploy.test.ts +2 -13
- package/src/commands/deploy.ts +5 -67
- package/src/commands/deployments.ts +3 -39
- package/src/commands/dev.ts +7 -10
- package/src/commands/experiment.ts +4 -110
- package/src/commands/promote.ts +3 -21
- package/src/commands/rollback.ts +3 -24
- package/src/commands/secrets.test.ts +12 -134
- package/src/commands/secrets.ts +2 -116
- package/src/commands/serve.ts +46 -93
- package/src/commands/status.ts +3 -51
- package/src/e2e-commands.test.ts +18 -17
- package/dist/src/shared/platform-client.d.ts +0 -123
- package/dist/src/shared/platform-client.d.ts.map +0 -1
- package/dist/src/shared/platform-client.js +0 -280
- package/dist/src/shared/platform-client.js.map +0 -1
- package/src/commands/audit.test.ts +0 -92
- package/src/commands/experiment.test.ts +0 -125
- package/src/shared/platform-client.test.ts +0 -106
- package/src/shared/platform-client.ts +0 -367
package/src/commands/secrets.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type {CommandModule} from 'yargs';
|
|
8
|
-
import {resolvePlatformConfig} from '../shared/platform-client.js';
|
|
9
8
|
|
|
10
9
|
export interface SecretsOptions {
|
|
11
10
|
cwd?: string;
|
|
@@ -20,121 +19,8 @@ export interface SecretsOptions {
|
|
|
20
19
|
* Returns 0 on success, 1 on error.
|
|
21
20
|
*/
|
|
22
21
|
export async function runSecrets(options: SecretsOptions): Promise<number> {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
config = await resolvePlatformConfig();
|
|
26
|
-
} catch (err) {
|
|
27
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
28
|
-
process.stderr.write(`[secrets] ${msg}\n`);
|
|
29
|
-
return 1;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const headers: Record<string, string> = {
|
|
33
|
-
'Authorization': `Bearer ${config.apiKey}`,
|
|
34
|
-
'Content-Type': 'application/json',
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
switch (options.subcommand) {
|
|
38
|
-
case 'set': {
|
|
39
|
-
if (!options.key) {
|
|
40
|
-
process.stderr.write('[secrets] Missing key. Usage: amodal secrets set <key> <value>\n');
|
|
41
|
-
return 1;
|
|
42
|
-
}
|
|
43
|
-
if (options.value === undefined) {
|
|
44
|
-
process.stderr.write('[secrets] Missing value. Usage: amodal secrets set <key> <value>\n');
|
|
45
|
-
return 1;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
const response = await fetch(`${config.url}/api/secrets`, {
|
|
50
|
-
method: 'PUT',
|
|
51
|
-
headers,
|
|
52
|
-
body: JSON.stringify({key: options.key, value: options.value}),
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
if (!response.ok) {
|
|
56
|
-
process.stderr.write(`[secrets] Failed to set secret: ${response.status} ${response.statusText}\n`);
|
|
57
|
-
return 1;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
process.stderr.write(`[secrets] Secret "${options.key}" set successfully.\n`);
|
|
61
|
-
return 0;
|
|
62
|
-
} catch (err) {
|
|
63
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
64
|
-
process.stderr.write(`[secrets] Failed to set secret: ${msg}\n`);
|
|
65
|
-
return 1;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
case 'list': {
|
|
70
|
-
try {
|
|
71
|
-
const response = await fetch(`${config.url}/api/secrets`, {
|
|
72
|
-
method: 'GET',
|
|
73
|
-
headers,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (!response.ok) {
|
|
77
|
-
process.stderr.write(`[secrets] Failed to list secrets: ${response.status} ${response.statusText}\n`);
|
|
78
|
-
return 1;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
82
|
-
const secrets = (await response.json()) as Array<{key: string}>;
|
|
83
|
-
|
|
84
|
-
if (secrets.length === 0) {
|
|
85
|
-
process.stderr.write('[secrets] No secrets configured.\n');
|
|
86
|
-
return 0;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (options.json) {
|
|
90
|
-
process.stdout.write(JSON.stringify(secrets, null, 2) + '\n');
|
|
91
|
-
return 0;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
process.stdout.write('KEY\n');
|
|
95
|
-
for (const secret of secrets) {
|
|
96
|
-
process.stdout.write(`${secret.key}\n`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
process.stderr.write(`[secrets] ${secrets.length} secret${secrets.length === 1 ? '' : 's'} configured.\n`);
|
|
100
|
-
return 0;
|
|
101
|
-
} catch (err) {
|
|
102
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
103
|
-
process.stderr.write(`[secrets] Failed to list secrets: ${msg}\n`);
|
|
104
|
-
return 1;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
case 'delete': {
|
|
109
|
-
if (!options.key) {
|
|
110
|
-
process.stderr.write('[secrets] Missing key. Usage: amodal secrets delete <key>\n');
|
|
111
|
-
return 1;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
try {
|
|
115
|
-
const response = await fetch(`${config.url}/api/secrets/${encodeURIComponent(options.key)}`, {
|
|
116
|
-
method: 'DELETE',
|
|
117
|
-
headers,
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
if (!response.ok) {
|
|
121
|
-
process.stderr.write(`[secrets] Failed to delete secret: ${response.status} ${response.statusText}\n`);
|
|
122
|
-
return 1;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
process.stderr.write(`[secrets] Secret "${options.key}" deleted.\n`);
|
|
126
|
-
return 0;
|
|
127
|
-
} catch (err) {
|
|
128
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
129
|
-
process.stderr.write(`[secrets] Failed to delete secret: ${msg}\n`);
|
|
130
|
-
return 1;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
default:
|
|
135
|
-
break;
|
|
136
|
-
}
|
|
137
|
-
|
|
22
|
+
void options;
|
|
23
|
+
process.stderr.write('[secrets] Hosted secret management is not included in the OSS CLI.\n');
|
|
138
24
|
return 1;
|
|
139
25
|
}
|
|
140
26
|
|
package/src/commands/serve.ts
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright
|
|
3
|
+
* Copyright 2026 Amodal Labs, Inc.
|
|
4
4
|
* SPDX-License-Identifier: MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import {execSync} from 'node:child_process';
|
|
8
|
+
import {mkdtempSync, statSync} from 'node:fs';
|
|
9
|
+
import {tmpdir} from 'node:os';
|
|
10
|
+
import {join, resolve} from 'node:path';
|
|
7
11
|
import type {CommandModule} from 'yargs';
|
|
8
|
-
import {
|
|
9
|
-
import type {AgentBundle} from '@amodalai/core';
|
|
10
|
-
import {createLocalServer, initLogLevel, interceptConsole} from '@amodalai/runtime';
|
|
11
|
-
import {PlatformClient} from '../shared/platform-client.js';
|
|
12
|
+
import {createBundleServer, initLogLevel, interceptConsole} from '@amodalai/runtime';
|
|
12
13
|
|
|
13
14
|
export interface ServeOptions {
|
|
14
15
|
config?: string;
|
|
15
|
-
platform?: boolean;
|
|
16
|
-
project?: string;
|
|
17
|
-
env?: string;
|
|
18
16
|
port?: number;
|
|
19
17
|
host?: string;
|
|
20
18
|
verbose?: number;
|
|
@@ -24,83 +22,59 @@ export interface ServeOptions {
|
|
|
24
22
|
const DEFAULT_PORT = 3847;
|
|
25
23
|
|
|
26
24
|
/**
|
|
27
|
-
*
|
|
25
|
+
* Resolve the `--config` argument to a directory `createBundleServer`
|
|
26
|
+
* can load via `loadRepoFromDisk`. Accepts either a directory or a
|
|
27
|
+
* `.tar.gz` tarball produced by `amodal build` (extracted to a tempdir).
|
|
28
28
|
*/
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
process.stderr.write(`[serve] Failed to load snapshot: ${msg}\n`);
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
29
|
+
function resolveBundlePath(configArg: string): string {
|
|
30
|
+
const absolute = resolve(configArg);
|
|
31
|
+
const stat = statSync(absolute);
|
|
32
|
+
if (stat.isDirectory()) return absolute;
|
|
33
|
+
|
|
34
|
+
if (absolute.endsWith('.tar.gz') || absolute.endsWith('.tgz')) {
|
|
35
|
+
const dir = mkdtempSync(join(tmpdir(), 'amodal-serve-'));
|
|
36
|
+
process.stderr.write(`[serve] Extracting ${absolute} → ${dir}\n`);
|
|
37
|
+
execSync(`tar -xzf "${absolute}" -C "${dir}"`, {stdio: 'pipe'});
|
|
38
|
+
return dir;
|
|
42
39
|
}
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
process.stderr.write('[serve] Fetching active snapshot from platform...\n');
|
|
46
|
-
let client: PlatformClient;
|
|
47
|
-
try {
|
|
48
|
-
client = await PlatformClient.create();
|
|
49
|
-
} catch (err) {
|
|
50
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
51
|
-
process.stderr.write(`[serve] ${msg}\n`);
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const environment = options.env ?? 'production';
|
|
56
|
-
try {
|
|
57
|
-
const snapshot = await client.getActiveSnapshot(environment);
|
|
58
|
-
const repo = snapshotToBundle(snapshot, `platform:${environment}`);
|
|
59
|
-
process.stderr.write(`[serve] Loaded ${snapshot.deployId} from ${environment}\n`);
|
|
60
|
-
return repo;
|
|
61
|
-
} catch (err) {
|
|
62
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
63
|
-
process.stderr.write(`[serve] Failed to fetch snapshot: ${msg}\n`);
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
process.stderr.write('[serve] Specify --config <file> or --platform to load a snapshot.\n');
|
|
69
|
-
return null;
|
|
41
|
+
throw new Error(`Unsupported --config target: ${absolute} (expected a directory or .tar.gz tarball)`);
|
|
70
42
|
}
|
|
71
43
|
|
|
72
|
-
|
|
73
|
-
* Load an agent runtime from a snapshot (file or platform) and start the server.
|
|
74
|
-
*
|
|
75
|
-
* Returns the loaded repo, or exits with error.
|
|
76
|
-
*/
|
|
77
|
-
export async function runServe(options: ServeOptions): Promise<AgentBundle | null> {
|
|
44
|
+
export async function runServe(options: ServeOptions): Promise<boolean> {
|
|
78
45
|
initLogLevel({verbosity: options.verbose ?? 0, quiet: options.quiet ?? false});
|
|
79
46
|
interceptConsole();
|
|
80
47
|
|
|
81
|
-
|
|
82
|
-
|
|
48
|
+
if (!options.config) {
|
|
49
|
+
process.stderr.write('[serve] --config <dir-or-tarball> is required.\n');
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let bundlePath: string;
|
|
54
|
+
try {
|
|
55
|
+
bundlePath = resolveBundlePath(options.config);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
58
|
+
process.stderr.write(`[serve] ${msg}\n`);
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
83
61
|
|
|
84
|
-
// Start the runtime server
|
|
85
62
|
const port = options.port ?? DEFAULT_PORT;
|
|
86
63
|
const host = options.host ?? '0.0.0.0';
|
|
87
64
|
|
|
88
|
-
process.stderr.write(`[serve] Starting server on ${host}:${port}...\n`);
|
|
65
|
+
process.stderr.write(`[serve] Starting bundle server from ${bundlePath} on ${host}:${port}...\n`);
|
|
89
66
|
|
|
90
67
|
try {
|
|
91
|
-
const server = await
|
|
92
|
-
|
|
68
|
+
const server = await createBundleServer({
|
|
69
|
+
bundlePath,
|
|
93
70
|
port,
|
|
94
71
|
host,
|
|
95
|
-
hotReload: false,
|
|
96
72
|
corsOrigin: '*',
|
|
97
73
|
});
|
|
98
74
|
|
|
99
75
|
await server.start();
|
|
76
|
+
process.stderr.write(`[serve] Serving at http://${host}:${port}\n`);
|
|
100
77
|
|
|
101
|
-
process.stderr.write(`[serve] Agent "${repo.config.name}" serving at http://${host}:${port}\n`);
|
|
102
|
-
|
|
103
|
-
// Graceful shutdown
|
|
104
78
|
const shutdown = async (signal: string): Promise<void> => {
|
|
105
79
|
process.stderr.write(`\n[serve] Received ${signal}, shutting down...\n`);
|
|
106
80
|
await server.stop();
|
|
@@ -112,33 +86,21 @@ export async function runServe(options: ServeOptions): Promise<AgentBundle | nul
|
|
|
112
86
|
} catch (err) {
|
|
113
87
|
const msg = err instanceof Error ? err.message : String(err);
|
|
114
88
|
process.stderr.write(`[serve] Failed to start server: ${msg}\n`);
|
|
115
|
-
return
|
|
89
|
+
return false;
|
|
116
90
|
}
|
|
117
91
|
|
|
118
|
-
return
|
|
92
|
+
return true;
|
|
119
93
|
}
|
|
120
94
|
|
|
121
95
|
export const serveCommand: CommandModule = {
|
|
122
96
|
command: 'serve',
|
|
123
|
-
describe: '
|
|
97
|
+
describe: 'Serve an agent from a built bundle (directory or .tar.gz from `amodal build`)',
|
|
124
98
|
builder: (yargs) =>
|
|
125
99
|
yargs
|
|
126
100
|
.option('config', {
|
|
127
101
|
type: 'string',
|
|
128
|
-
describe: 'Path to
|
|
129
|
-
|
|
130
|
-
.option('platform', {
|
|
131
|
-
type: 'boolean',
|
|
132
|
-
describe: 'Fetch active snapshot from platform',
|
|
133
|
-
default: false,
|
|
134
|
-
})
|
|
135
|
-
.option('project', {
|
|
136
|
-
type: 'string',
|
|
137
|
-
describe: 'Platform project name',
|
|
138
|
-
})
|
|
139
|
-
.option('env', {
|
|
140
|
-
type: 'string',
|
|
141
|
-
describe: 'Platform environment (default: production)',
|
|
102
|
+
describe: 'Path to a bundle directory or .tar.gz tarball',
|
|
103
|
+
demandOption: true,
|
|
142
104
|
})
|
|
143
105
|
.option('port', {
|
|
144
106
|
type: 'number',
|
|
@@ -161,15 +123,9 @@ export const serveCommand: CommandModule = {
|
|
|
161
123
|
default: false,
|
|
162
124
|
}),
|
|
163
125
|
handler: async (argv) => {
|
|
164
|
-
const
|
|
165
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
166
|
-
config: argv['config'] as string | undefined,
|
|
167
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
168
|
-
platform: argv['platform'] as boolean | undefined,
|
|
169
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
170
|
-
project: argv['project'] as string | undefined,
|
|
126
|
+
const ok = await runServe({
|
|
171
127
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
172
|
-
|
|
128
|
+
config: argv['config'] as string,
|
|
173
129
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
174
130
|
port: argv['port'] as number | undefined,
|
|
175
131
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
@@ -179,9 +135,6 @@ export const serveCommand: CommandModule = {
|
|
|
179
135
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
180
136
|
quiet: argv['quiet'] as boolean,
|
|
181
137
|
});
|
|
182
|
-
if (!
|
|
183
|
-
process.exit(1);
|
|
184
|
-
}
|
|
185
|
-
// Server is running — process stays alive until SIGTERM/SIGINT
|
|
138
|
+
if (!ok) process.exit(1);
|
|
186
139
|
},
|
|
187
140
|
};
|
package/src/commands/status.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type {CommandModule} from 'yargs';
|
|
8
|
-
import {PlatformClient} from '../shared/platform-client.js';
|
|
9
8
|
|
|
10
9
|
export interface StatusOptions {
|
|
11
10
|
env?: string;
|
|
@@ -16,56 +15,9 @@ export interface StatusOptions {
|
|
|
16
15
|
* Show current deployment status per environment.
|
|
17
16
|
*/
|
|
18
17
|
export async function runStatus(options: StatusOptions = {}): Promise<number> {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} catch (err) {
|
|
23
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
24
|
-
process.stderr.write(`[status] ${msg}\n`);
|
|
25
|
-
return 1;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const environments = options.env ? [options.env] : ['production', 'staging'];
|
|
29
|
-
|
|
30
|
-
try {
|
|
31
|
-
const results: Array<{environment: string; id?: string; createdAt?: string; createdBy?: string; commitSha?: string}> = [];
|
|
32
|
-
|
|
33
|
-
for (const env of environments) {
|
|
34
|
-
const deployments = await client.listDeployments({environment: env, limit: 1});
|
|
35
|
-
const active = deployments.find((d) => d.isActive);
|
|
36
|
-
if (active) {
|
|
37
|
-
results.push({
|
|
38
|
-
environment: env,
|
|
39
|
-
id: active.id,
|
|
40
|
-
createdAt: active.createdAt,
|
|
41
|
-
createdBy: active.createdBy ?? undefined,
|
|
42
|
-
commitSha: active.commitSha ?? undefined,
|
|
43
|
-
});
|
|
44
|
-
} else {
|
|
45
|
-
results.push({environment: env});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (options.json) {
|
|
50
|
-
process.stdout.write(JSON.stringify(results, null, 2) + '\n');
|
|
51
|
-
return 0;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
for (const r of results) {
|
|
55
|
-
if (r.id) {
|
|
56
|
-
const sha = r.commitSha ? ` (${r.commitSha.slice(0, 7)})` : '';
|
|
57
|
-
process.stdout.write(`${r.environment}: ${r.id}${sha} — ${r.createdBy ?? 'unknown'} at ${r.createdAt}\n`);
|
|
58
|
-
} else {
|
|
59
|
-
process.stdout.write(`${r.environment}: no active deployment\n`);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return 0;
|
|
64
|
-
} catch (err) {
|
|
65
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
66
|
-
process.stderr.write(`[status] Failed: ${msg}\n`);
|
|
67
|
-
return 1;
|
|
68
|
-
}
|
|
18
|
+
void options;
|
|
19
|
+
process.stderr.write('[status] Hosted deployment status is not included in the OSS CLI.\n');
|
|
20
|
+
return 1;
|
|
69
21
|
}
|
|
70
22
|
|
|
71
23
|
export const statusCommand: CommandModule = {
|
package/src/e2e-commands.test.ts
CHANGED
|
@@ -147,15 +147,20 @@ describe('E2E Commands: Local repo', () => {
|
|
|
147
147
|
|
|
148
148
|
// --- build ---
|
|
149
149
|
|
|
150
|
-
it('should
|
|
151
|
-
const
|
|
152
|
-
const code = await runBuild({cwd: repoDir, output:
|
|
150
|
+
it('should pack a tarball + manifest from the repo', async () => {
|
|
151
|
+
const outputDir = join(repoDir, 'test-build');
|
|
152
|
+
const code = await runBuild({cwd: repoDir, output: outputDir});
|
|
153
153
|
expect(code).toBe(0);
|
|
154
|
-
expect(existsSync(outputPath)).toBe(true);
|
|
155
154
|
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
expect((
|
|
155
|
+
const tarballPath = join(outputDir, 'agent.tar.gz');
|
|
156
|
+
const manifestPath = join(outputDir, 'manifest.json');
|
|
157
|
+
expect(existsSync(tarballPath)).toBe(true);
|
|
158
|
+
expect(existsSync(manifestPath)).toBe(true);
|
|
159
|
+
|
|
160
|
+
const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as Record<string, unknown>;
|
|
161
|
+
expect(manifest['deployId']).toBeDefined();
|
|
162
|
+
expect(manifest['agentName']).toBe('e2e-commands-test');
|
|
163
|
+
expect(manifest['source']).toBe('cli');
|
|
159
164
|
});
|
|
160
165
|
|
|
161
166
|
// --- docker init ---
|
|
@@ -272,16 +277,12 @@ describe.skipIf(!hasDb)('E2E Commands: Runtime', () => {
|
|
|
272
277
|
await runEval({cwd: repoDir});
|
|
273
278
|
});
|
|
274
279
|
|
|
275
|
-
// ---
|
|
276
|
-
|
|
277
|
-
it('should boot a snapshot server and serve health', async () => {
|
|
278
|
-
const snapshotPath = join(repoDir, 'cmd-test-snapshot.json');
|
|
279
|
-
const buildCode = await runBuild({cwd: repoDir, output: snapshotPath});
|
|
280
|
-
expect(buildCode).toBe(0);
|
|
280
|
+
// --- bundle server ---
|
|
281
281
|
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
|
|
282
|
+
it('should boot a bundle server and serve health', async () => {
|
|
283
|
+
const {createBundleServer} = await import('@amodalai/runtime');
|
|
284
|
+
const snapServer = await createBundleServer({
|
|
285
|
+
bundlePath: repoDir,
|
|
285
286
|
port: 0,
|
|
286
287
|
host: '127.0.0.1',
|
|
287
288
|
});
|
|
@@ -295,7 +296,7 @@ describe.skipIf(!hasDb)('E2E Commands: Runtime', () => {
|
|
|
295
296
|
expect(resp.ok).toBe(true);
|
|
296
297
|
const data = (await resp.json()) as Record<string, unknown>;
|
|
297
298
|
expect(data['status']).toBe('ok');
|
|
298
|
-
expect(data['mode']).toBe('
|
|
299
|
+
expect(data['mode']).toBe('bundle');
|
|
299
300
|
expect(data['agent_name']).toBe('e2e-commands-test');
|
|
300
301
|
} finally {
|
|
301
302
|
await snapServer.stop();
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
-
* SPDX-License-Identifier: MIT
|
|
5
|
-
*/
|
|
6
|
-
import type { DeploySnapshot } from '@amodalai/core';
|
|
7
|
-
/**
|
|
8
|
-
* Metadata returned for a snapshot deployment.
|
|
9
|
-
*/
|
|
10
|
-
export interface SnapshotDeploymentMeta {
|
|
11
|
-
id: string;
|
|
12
|
-
environment: string;
|
|
13
|
-
isActive: boolean;
|
|
14
|
-
createdAt: string;
|
|
15
|
-
createdBy: string;
|
|
16
|
-
source: string;
|
|
17
|
-
commitSha?: string;
|
|
18
|
-
branch?: string;
|
|
19
|
-
message?: string;
|
|
20
|
-
snapshotSize: number;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Resolve platform URL and API key from multiple sources:
|
|
24
|
-
* 1. Explicit options (flags)
|
|
25
|
-
* 2. .amodal/project.json (platformUrl from `amodal link`)
|
|
26
|
-
* 3. ~/.amodalrc (auth token from `amodal login`)
|
|
27
|
-
* 4. Env vars (fallback)
|
|
28
|
-
*/
|
|
29
|
-
export declare function resolvePlatformConfig(options?: {
|
|
30
|
-
url?: string;
|
|
31
|
-
apiKey?: string;
|
|
32
|
-
}): Promise<{
|
|
33
|
-
url: string;
|
|
34
|
-
apiKey: string;
|
|
35
|
-
}>;
|
|
36
|
-
/**
|
|
37
|
-
* Platform API client for snapshot deployments.
|
|
38
|
-
*
|
|
39
|
-
* Resolves credentials from: explicit options → project link → rc file → env vars.
|
|
40
|
-
* Use `PlatformClient.create()` for async auto-discovery, or `new PlatformClient()` for sync usage.
|
|
41
|
-
*/
|
|
42
|
-
export declare class PlatformClient {
|
|
43
|
-
private readonly baseUrl;
|
|
44
|
-
private readonly apiKey;
|
|
45
|
-
constructor(options?: {
|
|
46
|
-
url?: string;
|
|
47
|
-
apiKey?: string;
|
|
48
|
-
});
|
|
49
|
-
/**
|
|
50
|
-
* Create a PlatformClient with auto-discovery of credentials.
|
|
51
|
-
* Resolves from: explicit options → project link → rc file → env vars.
|
|
52
|
-
*/
|
|
53
|
-
static create(options?: {
|
|
54
|
-
url?: string;
|
|
55
|
-
apiKey?: string;
|
|
56
|
-
}): Promise<PlatformClient>;
|
|
57
|
-
private headers;
|
|
58
|
-
private request;
|
|
59
|
-
/**
|
|
60
|
-
* Try to refresh the token using the stored refresh token.
|
|
61
|
-
* Updates both the in-memory key and the rc file on success.
|
|
62
|
-
*/
|
|
63
|
-
private tryRefreshToken;
|
|
64
|
-
/**
|
|
65
|
-
* Upload a snapshot and deploy it.
|
|
66
|
-
*/
|
|
67
|
-
uploadSnapshot(snapshot: DeploySnapshot, options?: {
|
|
68
|
-
environment?: string;
|
|
69
|
-
appId?: string;
|
|
70
|
-
}): Promise<SnapshotDeploymentMeta>;
|
|
71
|
-
/**
|
|
72
|
-
* Trigger a runtime-app build on the build server.
|
|
73
|
-
* Sends the repo tarball to the build server which builds the SPA and uploads to R2.
|
|
74
|
-
*/
|
|
75
|
-
triggerBuild(buildServerUrl: string, appId: string, deployId: string, repoTarball: import('node:fs').ReadStream): Promise<void>;
|
|
76
|
-
/**
|
|
77
|
-
* Trigger a remote build:
|
|
78
|
-
* 1. Get scoped R2 temp credentials from the platform API
|
|
79
|
-
* 2. Upload the tarball directly to R2 with those creds
|
|
80
|
-
* 3. Tell the platform API to trigger a Fly Machine build
|
|
81
|
-
*
|
|
82
|
-
* Returns a buildId for polling.
|
|
83
|
-
*/
|
|
84
|
-
triggerRemoteBuild(appId: string, environment: string, tarballPath: string, message?: string): Promise<{
|
|
85
|
-
buildId: string;
|
|
86
|
-
}>;
|
|
87
|
-
/**
|
|
88
|
-
* Poll build status.
|
|
89
|
-
*/
|
|
90
|
-
getBuildStatus(buildId: string): Promise<{
|
|
91
|
-
status: 'building' | 'complete' | 'error';
|
|
92
|
-
deployId?: string;
|
|
93
|
-
environment?: string;
|
|
94
|
-
error?: string;
|
|
95
|
-
}>;
|
|
96
|
-
/**
|
|
97
|
-
* List deployments for the authenticated app.
|
|
98
|
-
*/
|
|
99
|
-
listDeployments(options?: {
|
|
100
|
-
environment?: string;
|
|
101
|
-
limit?: number;
|
|
102
|
-
}): Promise<SnapshotDeploymentMeta[]>;
|
|
103
|
-
/**
|
|
104
|
-
* Rollback to a previous deployment.
|
|
105
|
-
*/
|
|
106
|
-
rollback(options?: {
|
|
107
|
-
deployId?: string;
|
|
108
|
-
environment?: string;
|
|
109
|
-
}): Promise<SnapshotDeploymentMeta>;
|
|
110
|
-
/**
|
|
111
|
-
* Promote a deployment from one environment to another.
|
|
112
|
-
*/
|
|
113
|
-
promote(fromEnv: string, toEnv?: string): Promise<SnapshotDeploymentMeta>;
|
|
114
|
-
/**
|
|
115
|
-
* Get status of a specific deployment.
|
|
116
|
-
*/
|
|
117
|
-
getStatus(deployId: string): Promise<SnapshotDeploymentMeta>;
|
|
118
|
-
/**
|
|
119
|
-
* Get the active snapshot for an environment.
|
|
120
|
-
*/
|
|
121
|
-
getActiveSnapshot(environment?: string): Promise<DeploySnapshot>;
|
|
122
|
-
}
|
|
123
|
-
//# sourceMappingURL=platform-client.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"platform-client.d.ts","sourceRoot":"","sources":["../../../src/shared/platform-client.ts"],"names":[],"mappings":"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"}
|