@amodalai/amodal 0.1.11 → 0.1.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/CHANGELOG.md +22 -0
- package/dist/src/commands/admin.d.ts +11 -0
- package/dist/src/commands/admin.d.ts.map +1 -0
- package/dist/src/commands/admin.js +54 -0
- package/dist/src/commands/admin.js.map +1 -0
- package/dist/src/commands/dev.d.ts.map +1 -1
- package/dist/src/commands/dev.js +6 -3
- package/dist/src/commands/dev.js.map +1 -1
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +33 -10
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/shared/connection-preflight.d.ts.map +1 -1
- package/dist/src/shared/connection-preflight.js +37 -4
- package/dist/src/shared/connection-preflight.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -11
- package/src/commands/admin.ts +58 -0
- package/src/commands/dev.ts +8 -3
- package/src/commands/index.ts +0 -1
- package/src/commands/update.ts +38 -10
- package/src/shared/connection-preflight.ts +38 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amodalai/amodal",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"description": "Amodal CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -30,16 +30,9 @@
|
|
|
30
30
|
"semver": "^7.6.0",
|
|
31
31
|
"yargs": "^17.7.2",
|
|
32
32
|
"zod": "^4.3.6",
|
|
33
|
-
"@amodalai/core": "0.1.
|
|
34
|
-
"@amodalai/runtime": "0.1.
|
|
35
|
-
|
|
36
|
-
"peerDependencies": {
|
|
37
|
-
"@amodalai/runtime-app": "0.1.11"
|
|
38
|
-
},
|
|
39
|
-
"peerDependenciesMeta": {
|
|
40
|
-
"@amodalai/runtime-app": {
|
|
41
|
-
"optional": true
|
|
42
|
-
}
|
|
33
|
+
"@amodalai/core": "0.1.13",
|
|
34
|
+
"@amodalai/runtime": "0.1.13",
|
|
35
|
+
"@amodalai/runtime-app": "0.1.13"
|
|
43
36
|
},
|
|
44
37
|
"devDependencies": {
|
|
45
38
|
"@types/node": "^20.11.24",
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Amodal Labs, Inc.
|
|
4
|
+
* SPDX-License-Identifier: MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {readFile} from 'node:fs/promises';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import {
|
|
10
|
+
fetchAdminAgent,
|
|
11
|
+
getAdminAgentVersion,
|
|
12
|
+
} from '@amodalai/core';
|
|
13
|
+
import {findRepoRoot} from '../shared/repo-discovery.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Update the global admin agent cache from the registry.
|
|
17
|
+
* Called by `amodal update --admin-agent`.
|
|
18
|
+
*/
|
|
19
|
+
export async function updateAdminAgentCommand(): Promise<number> {
|
|
20
|
+
// Check if amodal.json overrides the admin agent
|
|
21
|
+
let repoPath: string | undefined;
|
|
22
|
+
try {
|
|
23
|
+
repoPath = findRepoRoot();
|
|
24
|
+
} catch {
|
|
25
|
+
// Not in a repo — that's fine
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (repoPath) {
|
|
29
|
+
try {
|
|
30
|
+
const configRaw = await readFile(path.join(repoPath, 'amodal.json'), 'utf-8');
|
|
31
|
+
const parsed: unknown = JSON.parse(configRaw);
|
|
32
|
+
if (parsed && typeof parsed === 'object' && 'adminAgent' in parsed) {
|
|
33
|
+
|
|
34
|
+
const adminPath = (parsed as Record<string, unknown>)['adminAgent'];
|
|
35
|
+
if (typeof adminPath === 'string') {
|
|
36
|
+
process.stderr.write(`[update] Admin agent is overridden in amodal.json (adminAgent: "${adminPath}").\n`);
|
|
37
|
+
process.stderr.write('[update] The global cache is not used. Update your local copy directly.\n');
|
|
38
|
+
return 1;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
} catch {
|
|
42
|
+
// No config or parse error — proceed
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
process.stderr.write('[update] Fetching latest admin agent from registry...\n');
|
|
47
|
+
try {
|
|
48
|
+
const dir = await fetchAdminAgent();
|
|
49
|
+
const version = await getAdminAgentVersion(dir);
|
|
50
|
+
process.stderr.write(`[update] Admin agent updated to v${version ?? 'unknown'}\n`);
|
|
51
|
+
process.stderr.write(`[update] Cached at ${dir}\n`);
|
|
52
|
+
return 0;
|
|
53
|
+
} catch (err) {
|
|
54
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
55
|
+
process.stderr.write(`[update] Admin agent update failed: ${msg}\n`);
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/commands/dev.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import type {CommandModule} from 'yargs';
|
|
8
8
|
import {existsSync} from 'node:fs';
|
|
9
|
+
import {createRequire} from 'node:module';
|
|
9
10
|
import path from 'node:path';
|
|
10
11
|
import {fileURLToPath} from 'node:url';
|
|
11
12
|
import {createLocalServer} from '@amodalai/runtime';
|
|
@@ -42,15 +43,19 @@ export async function runDev(options: DevOptions = {}): Promise<void> {
|
|
|
42
43
|
try {
|
|
43
44
|
let staticAppDir: string | undefined;
|
|
44
45
|
|
|
45
|
-
// Use pre-built static assets for the SPA
|
|
46
|
+
// Use pre-built static assets for the SPA.
|
|
46
47
|
// Vite dev middleware is only used inside the monorepo with `pnpm dev`.
|
|
47
48
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
48
49
|
const candidates = [
|
|
49
50
|
// esbuild bundle: bundle/app/
|
|
50
51
|
path.resolve(scriptDir, 'app'),
|
|
51
|
-
// global/local install: <pkg root>/node_modules/@amodalai/runtime-app/dist/
|
|
52
|
-
path.resolve(scriptDir, '..', '..', '..', 'node_modules', '@amodalai', 'runtime-app', 'dist'),
|
|
53
52
|
];
|
|
53
|
+
|
|
54
|
+
// Resolve @amodalai/runtime-app via Node module resolution (works regardless of install layout)
|
|
55
|
+
const require = createRequire(import.meta.url);
|
|
56
|
+
const runtimeAppPkg = require.resolve('@amodalai/runtime-app/package.json');
|
|
57
|
+
candidates.push(path.join(path.dirname(runtimeAppPkg), 'dist'));
|
|
58
|
+
|
|
54
59
|
for (const dir of candidates) {
|
|
55
60
|
if (existsSync(path.join(dir, 'index.html'))) {
|
|
56
61
|
process.stderr.write('[dev] Serving pre-built runtime app\n');
|
package/src/commands/index.ts
CHANGED
|
@@ -34,7 +34,6 @@ import {evalCommand} from './eval.js';
|
|
|
34
34
|
import {experimentCommand} from './experiment.js';
|
|
35
35
|
import {testQueryCommand} from './test-query.js';
|
|
36
36
|
import {automationsCommand} from './automations.js';
|
|
37
|
-
|
|
38
37
|
/**
|
|
39
38
|
* All amodal subcommands for flat registration on the root yargs instance.
|
|
40
39
|
*/
|
package/src/commands/update.ts
CHANGED
|
@@ -148,21 +148,49 @@ export async function runUpdate(options: UpdateOptions = {}): Promise<number> {
|
|
|
148
148
|
|
|
149
149
|
export const updateCommand: CommandModule = {
|
|
150
150
|
command: 'update [name]',
|
|
151
|
-
describe: 'Update
|
|
151
|
+
describe: 'Update packages. Use --all for all packages, --admin-agent for the admin agent, or specify a name.',
|
|
152
152
|
builder: (yargs) =>
|
|
153
153
|
yargs
|
|
154
154
|
.positional('name', {type: 'string', describe: 'Package name to update'})
|
|
155
|
+
.option('all', {type: 'boolean', default: false, describe: 'Update all installed packages'})
|
|
156
|
+
.option('admin-agent', {type: 'boolean', default: false, describe: 'Update the global admin agent cache'})
|
|
155
157
|
.option('latest', {type: 'boolean', default: false, describe: 'Allow major version updates'})
|
|
156
158
|
.option('dry-run', {type: 'boolean', default: false, describe: 'Show what would be updated'}),
|
|
157
159
|
handler: async (argv) => {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
160
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
161
|
+
const name = argv['name'] as string | undefined;
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
163
|
+
const all = argv['all'] as boolean;
|
|
164
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
165
|
+
const adminAgent = argv['adminAgent'] as boolean;
|
|
166
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
167
|
+
const latest = argv['latest'] as boolean;
|
|
168
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
169
|
+
const dryRun = argv['dryRun'] as boolean;
|
|
170
|
+
|
|
171
|
+
// Must specify at least one target
|
|
172
|
+
if (!name && !all && !adminAgent) {
|
|
173
|
+
process.stderr.write('Usage: amodal update <name> | --all | --admin-agent\n');
|
|
174
|
+
process.stderr.write(' <name> Update a specific package\n');
|
|
175
|
+
process.stderr.write(' --all Update all installed packages\n');
|
|
176
|
+
process.stderr.write(' --admin-agent Update the global admin agent\n');
|
|
177
|
+
process.stderr.write(' Flags can be combined: amodal update --all --admin-agent\n');
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let failures = 0;
|
|
182
|
+
|
|
183
|
+
// Update admin agent if requested
|
|
184
|
+
if (adminAgent) {
|
|
185
|
+
const {updateAdminAgentCommand} = await import('./admin.js');
|
|
186
|
+
failures += await updateAdminAgentCommand();
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Update packages if requested
|
|
190
|
+
if (name || all) {
|
|
191
|
+
failures += await runUpdate({name, latest, dryRun});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
process.exit(failures > 0 ? 1 : 0);
|
|
167
195
|
},
|
|
168
196
|
};
|
|
@@ -227,8 +227,34 @@ export async function runConnectionPreflight(repoPath: string): Promise<Prefligh
|
|
|
227
227
|
|
|
228
228
|
const results: LiveTestResult[] = [];
|
|
229
229
|
|
|
230
|
+
// Split connections by protocol
|
|
231
|
+
const restConnections: Array<[string, typeof repo.connections extends Map<string, infer V> ? V : never]> = [];
|
|
232
|
+
const mcpFromConnections: Record<string, {transport: 'stdio' | 'sse' | 'http'; command?: string; args?: string[]; env?: Record<string, string>; url?: string; headers?: Record<string, string>}> = {};
|
|
233
|
+
|
|
234
|
+
for (const [name, conn] of repo.connections) {
|
|
235
|
+
if (conn.spec.protocol === 'mcp') {
|
|
236
|
+
// Resolve env: references in headers
|
|
237
|
+
const resolvedHeaders: Record<string, string> = {};
|
|
238
|
+
if (conn.spec.headers) {
|
|
239
|
+
for (const [k, v] of Object.entries(conn.spec.headers)) {
|
|
240
|
+
resolvedHeaders[k] = v.startsWith('env:') ? (envVars.get(v.slice(4)) ?? process.env[v.slice(4)] ?? '') : v;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
mcpFromConnections[name] = {
|
|
244
|
+
transport: conn.spec.transport ?? 'stdio',
|
|
245
|
+
command: conn.spec.command,
|
|
246
|
+
args: conn.spec.args,
|
|
247
|
+
env: conn.spec.env,
|
|
248
|
+
url: conn.spec.url,
|
|
249
|
+
headers: Object.keys(resolvedHeaders).length > 0 ? resolvedHeaders : undefined,
|
|
250
|
+
};
|
|
251
|
+
} else {
|
|
252
|
+
restConnections.push([name, conn]);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
230
256
|
// Test REST connections in parallel
|
|
231
|
-
const restPromises =
|
|
257
|
+
const restPromises = restConnections.map(([name, conn]) =>
|
|
232
258
|
testRestConnection(name, conn.spec, envVars),
|
|
233
259
|
);
|
|
234
260
|
const restResults = await Promise.allSettled(restPromises);
|
|
@@ -238,9 +264,17 @@ export async function runConnectionPreflight(repoPath: string): Promise<Prefligh
|
|
|
238
264
|
}
|
|
239
265
|
}
|
|
240
266
|
|
|
241
|
-
// Test MCP servers
|
|
242
|
-
|
|
243
|
-
|
|
267
|
+
// Test MCP connections (from protocol:mcp connections + legacy mcp.servers)
|
|
268
|
+
const allMcpConfigs = {...mcpFromConnections};
|
|
269
|
+
if (repo.mcpServers) {
|
|
270
|
+
for (const [name, config] of Object.entries(repo.mcpServers)) {
|
|
271
|
+
if (!allMcpConfigs[name]) {
|
|
272
|
+
allMcpConfigs[name] = config;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (Object.keys(allMcpConfigs).length > 0) {
|
|
277
|
+
const mcpResults = await testMcpServers(allMcpConfigs);
|
|
244
278
|
results.push(...mcpResults);
|
|
245
279
|
}
|
|
246
280
|
|