@amodalai/amodal 0.2.10 → 0.3.0
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 +16 -0
- package/dist/src/commands/dev.d.ts +6 -1
- package/dist/src/commands/dev.d.ts.map +1 -1
- package/dist/src/commands/dev.js +351 -21
- package/dist/src/commands/dev.js.map +1 -1
- package/dist/src/shared/env-resolution.d.ts +13 -0
- package/dist/src/shared/env-resolution.d.ts.map +1 -0
- package/dist/src/shared/env-resolution.js +54 -0
- package/dist/src/shared/env-resolution.js.map +1 -0
- package/dist/src/shared/find-free-port.d.ts +21 -0
- package/dist/src/shared/find-free-port.d.ts.map +1 -0
- package/dist/src/shared/find-free-port.js +62 -0
- package/dist/src/shared/find-free-port.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -5
- package/src/commands/dev.test.ts +96 -33
- package/src/commands/dev.ts +440 -19
- package/src/shared/env-resolution.test.ts +93 -0
- package/src/shared/env-resolution.ts +52 -0
- package/src/shared/find-free-port.ts +67 -0
- package/tsconfig.json +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amodalai/amodal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Amodal CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -30,10 +30,11 @@
|
|
|
30
30
|
"semver": "^7.6.0",
|
|
31
31
|
"yargs": "^17.7.2",
|
|
32
32
|
"zod": "^4.3.6",
|
|
33
|
-
"@amodalai/types": "0.
|
|
34
|
-
"@amodalai/core": "0.
|
|
35
|
-
"@amodalai/
|
|
36
|
-
"@amodalai/runtime
|
|
33
|
+
"@amodalai/types": "0.3.0",
|
|
34
|
+
"@amodalai/core": "0.3.0",
|
|
35
|
+
"@amodalai/db": "0.0.0",
|
|
36
|
+
"@amodalai/runtime": "0.3.0",
|
|
37
|
+
"@amodalai/runtime-app": "0.3.0"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"@types/node": "^20.11.24",
|
package/src/commands/dev.test.ts
CHANGED
|
@@ -1,63 +1,126 @@
|
|
|
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 {describe, it, expect, vi} from 'vitest';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}));
|
|
7
|
+
import {describe, it, expect, beforeEach, afterEach, vi} from 'vitest';
|
|
8
|
+
import {mkdtempSync, writeFileSync, rmSync} from 'node:fs';
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import os from 'node:os';
|
|
12
11
|
|
|
12
|
+
// Mock runtime dependencies that we don't need for the DATABASE_URL check
|
|
13
13
|
vi.mock('@amodalai/runtime', () => ({
|
|
14
14
|
createLocalServer: vi.fn().mockResolvedValue({
|
|
15
15
|
app: {},
|
|
16
16
|
start: vi.fn().mockResolvedValue({}),
|
|
17
17
|
stop: vi.fn().mockResolvedValue(undefined),
|
|
18
18
|
}),
|
|
19
|
+
initLogLevel: vi.fn(),
|
|
20
|
+
interceptConsole: vi.fn(),
|
|
21
|
+
log: {
|
|
22
|
+
info: vi.fn(),
|
|
23
|
+
warn: vi.fn(),
|
|
24
|
+
error: vi.fn(),
|
|
25
|
+
debug: vi.fn(),
|
|
26
|
+
},
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
vi.mock('@amodalai/db', () => ({
|
|
30
|
+
getDb: vi.fn(),
|
|
31
|
+
ensureSchema: vi.fn().mockResolvedValue(undefined),
|
|
32
|
+
closeDb: vi.fn().mockResolvedValue(undefined),
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
vi.mock('@amodalai/core', () => ({
|
|
36
|
+
resolveAdminAgent: vi.fn().mockResolvedValue(null),
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
vi.mock('../shared/connection-preflight.js', () => ({
|
|
40
|
+
runConnectionPreflight: vi.fn().mockResolvedValue({results: [], hasFailures: false}),
|
|
41
|
+
printPreflightTable: vi.fn(),
|
|
19
42
|
}));
|
|
20
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Smoke test: `amodal dev` without DATABASE_URL should print instructions
|
|
46
|
+
* and exit with code 1.
|
|
47
|
+
*/
|
|
21
48
|
describe('dev command', () => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
49
|
+
let tmpDir: string;
|
|
50
|
+
let fakeHome: string;
|
|
51
|
+
let origHome: string;
|
|
52
|
+
let origDatabaseUrl: string | undefined;
|
|
53
|
+
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
tmpDir = mkdtempSync(path.join(os.tmpdir(), 'dev-test-'));
|
|
56
|
+
fakeHome = mkdtempSync(path.join(os.tmpdir(), 'dev-test-home-'));
|
|
57
|
+
|
|
58
|
+
// Create a minimal amodal.json so findRepoRoot succeeds
|
|
59
|
+
writeFileSync(path.join(tmpDir, 'amodal.json'), JSON.stringify({name: 'test-agent'}));
|
|
60
|
+
|
|
61
|
+
origHome = process.env['HOME'] ?? '';
|
|
62
|
+
origDatabaseUrl = process.env['DATABASE_URL'];
|
|
63
|
+
delete process.env['DATABASE_URL'];
|
|
64
|
+
process.env['HOME'] = fakeHome;
|
|
26
65
|
});
|
|
27
66
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
process.env['HOME'] = origHome;
|
|
69
|
+
if (origDatabaseUrl !== undefined) {
|
|
70
|
+
process.env['DATABASE_URL'] = origDatabaseUrl;
|
|
71
|
+
} else {
|
|
72
|
+
delete process.env['DATABASE_URL'];
|
|
73
|
+
}
|
|
74
|
+
rmSync(tmpDir, {recursive: true, force: true});
|
|
75
|
+
rmSync(fakeHome, {recursive: true, force: true});
|
|
76
|
+
vi.restoreAllMocks();
|
|
32
77
|
});
|
|
33
78
|
|
|
34
|
-
it('
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
79
|
+
it('exits with code 1 and prints instructions when DATABASE_URL is missing', async () => {
|
|
80
|
+
// Capture stderr output
|
|
81
|
+
const stderrChunks: string[] = [];
|
|
82
|
+
vi.spyOn(process.stderr, 'write').mockImplementation((chunk: string | Uint8Array) => {
|
|
83
|
+
stderrChunks.push(String(chunk));
|
|
84
|
+
return true;
|
|
38
85
|
});
|
|
39
86
|
|
|
40
|
-
//
|
|
87
|
+
// Mock process.exit to throw so we can catch it
|
|
88
|
+
vi.spyOn(process, 'exit').mockImplementation((code?: number | string | null | undefined) => {
|
|
89
|
+
throw new ExitError(typeof code === 'number' ? code : 1);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const {runDev} = await import('./dev.js');
|
|
93
|
+
|
|
41
94
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
95
|
+
await runDev({cwd: tmpDir});
|
|
96
|
+
expect.unreachable('runDev should have called process.exit');
|
|
97
|
+
} catch (err: unknown) {
|
|
98
|
+
if (err instanceof ExitError) {
|
|
99
|
+
expect(err.code).toBe(1);
|
|
100
|
+
} else {
|
|
101
|
+
throw err;
|
|
102
|
+
}
|
|
47
103
|
}
|
|
48
104
|
|
|
49
|
-
|
|
50
|
-
|
|
105
|
+
const output = stderrChunks.join('');
|
|
106
|
+
expect(output).toContain('DATABASE_URL is required');
|
|
107
|
+
expect(output).toContain('docker run');
|
|
108
|
+
expect(output).toContain('~/.amodal/.env');
|
|
51
109
|
});
|
|
52
110
|
|
|
53
|
-
it('should
|
|
54
|
-
const mod = await import('./dev.js');
|
|
55
|
-
// Just verify the export exists — actual server test is integration
|
|
56
|
-
expect(mod.runDev).toBeDefined();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('should accept custom port', async () => {
|
|
111
|
+
it('should import without error', async () => {
|
|
60
112
|
const mod = await import('./dev.js');
|
|
61
113
|
expect(mod.runDev).toBeDefined();
|
|
114
|
+
expect(typeof mod.runDev).toBe('function');
|
|
62
115
|
});
|
|
63
116
|
});
|
|
117
|
+
|
|
118
|
+
/** Sentinel error thrown by our process.exit mock. */
|
|
119
|
+
class ExitError extends Error {
|
|
120
|
+
readonly code: number;
|
|
121
|
+
constructor(code: number) {
|
|
122
|
+
super(`process.exit(${String(code)})`);
|
|
123
|
+
this.name = 'ExitError';
|
|
124
|
+
this.code = code;
|
|
125
|
+
}
|
|
126
|
+
}
|