@ash-ai/server 0.0.1

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 (106) hide show
  1. package/LICENSE +21 -0
  2. package/dist/__tests__/auth.test.d.ts +2 -0
  3. package/dist/__tests__/auth.test.d.ts.map +1 -0
  4. package/dist/__tests__/auth.test.js +111 -0
  5. package/dist/__tests__/auth.test.js.map +1 -0
  6. package/dist/__tests__/backpressure.test.d.ts +2 -0
  7. package/dist/__tests__/backpressure.test.d.ts.map +1 -0
  8. package/dist/__tests__/backpressure.test.js +81 -0
  9. package/dist/__tests__/backpressure.test.js.map +1 -0
  10. package/dist/__tests__/db.test.d.ts +2 -0
  11. package/dist/__tests__/db.test.d.ts.map +1 -0
  12. package/dist/__tests__/db.test.js +111 -0
  13. package/dist/__tests__/db.test.js.map +1 -0
  14. package/dist/__tests__/files.test.d.ts +2 -0
  15. package/dist/__tests__/files.test.d.ts.map +1 -0
  16. package/dist/__tests__/files.test.js +171 -0
  17. package/dist/__tests__/files.test.js.map +1 -0
  18. package/dist/__tests__/openapi.test.d.ts +2 -0
  19. package/dist/__tests__/openapi.test.d.ts.map +1 -0
  20. package/dist/__tests__/openapi.test.js +88 -0
  21. package/dist/__tests__/openapi.test.js.map +1 -0
  22. package/dist/__tests__/pool.test.d.ts +2 -0
  23. package/dist/__tests__/pool.test.d.ts.map +1 -0
  24. package/dist/__tests__/pool.test.js +352 -0
  25. package/dist/__tests__/pool.test.js.map +1 -0
  26. package/dist/__tests__/resource-limits.test.d.ts +2 -0
  27. package/dist/__tests__/resource-limits.test.d.ts.map +1 -0
  28. package/dist/__tests__/resource-limits.test.js +119 -0
  29. package/dist/__tests__/resource-limits.test.js.map +1 -0
  30. package/dist/__tests__/sandbox-env.test.d.ts +2 -0
  31. package/dist/__tests__/sandbox-env.test.d.ts.map +1 -0
  32. package/dist/__tests__/sandbox-env.test.js +40 -0
  33. package/dist/__tests__/sandbox-env.test.js.map +1 -0
  34. package/dist/__tests__/snapshot-store.test.d.ts +2 -0
  35. package/dist/__tests__/snapshot-store.test.d.ts.map +1 -0
  36. package/dist/__tests__/snapshot-store.test.js +101 -0
  37. package/dist/__tests__/snapshot-store.test.js.map +1 -0
  38. package/dist/__tests__/state-persistence.test.d.ts +2 -0
  39. package/dist/__tests__/state-persistence.test.d.ts.map +1 -0
  40. package/dist/__tests__/state-persistence.test.js +116 -0
  41. package/dist/__tests__/state-persistence.test.js.map +1 -0
  42. package/dist/auth.d.ts +10 -0
  43. package/dist/auth.d.ts.map +1 -0
  44. package/dist/auth.js +30 -0
  45. package/dist/auth.js.map +1 -0
  46. package/dist/db/index.d.ts +54 -0
  47. package/dist/db/index.d.ts.map +1 -0
  48. package/dist/db/index.js +91 -0
  49. package/dist/db/index.js.map +1 -0
  50. package/dist/db/pg.d.ts +31 -0
  51. package/dist/db/pg.d.ts.map +1 -0
  52. package/dist/db/pg.js +214 -0
  53. package/dist/db/pg.js.map +1 -0
  54. package/dist/db/sqlite.d.ts +30 -0
  55. package/dist/db/sqlite.d.ts.map +1 -0
  56. package/dist/db/sqlite.js +195 -0
  57. package/dist/db/sqlite.js.map +1 -0
  58. package/dist/index.d.ts +2 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +122 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/routes/agents.d.ts +3 -0
  63. package/dist/routes/agents.d.ts.map +1 -0
  64. package/dist/routes/agents.js +103 -0
  65. package/dist/routes/agents.js.map +1 -0
  66. package/dist/routes/files.d.ts +4 -0
  67. package/dist/routes/files.d.ts.map +1 -0
  68. package/dist/routes/files.js +189 -0
  69. package/dist/routes/files.js.map +1 -0
  70. package/dist/routes/health.d.ts +5 -0
  71. package/dist/routes/health.d.ts.map +1 -0
  72. package/dist/routes/health.js +72 -0
  73. package/dist/routes/health.js.map +1 -0
  74. package/dist/routes/runners.d.ts +8 -0
  75. package/dist/routes/runners.d.ts.map +1 -0
  76. package/dist/routes/runners.js +33 -0
  77. package/dist/routes/runners.js.map +1 -0
  78. package/dist/routes/sessions.d.ts +10 -0
  79. package/dist/routes/sessions.d.ts.map +1 -0
  80. package/dist/routes/sessions.js +392 -0
  81. package/dist/routes/sessions.js.map +1 -0
  82. package/dist/runner/coordinator.d.ts +52 -0
  83. package/dist/runner/coordinator.d.ts.map +1 -0
  84. package/dist/runner/coordinator.js +157 -0
  85. package/dist/runner/coordinator.js.map +1 -0
  86. package/dist/runner/local-backend.d.ts +26 -0
  87. package/dist/runner/local-backend.d.ts.map +1 -0
  88. package/dist/runner/local-backend.js +79 -0
  89. package/dist/runner/local-backend.js.map +1 -0
  90. package/dist/runner/remote-backend.d.ts +32 -0
  91. package/dist/runner/remote-backend.d.ts.map +1 -0
  92. package/dist/runner/remote-backend.js +81 -0
  93. package/dist/runner/remote-backend.js.map +1 -0
  94. package/dist/runner/runner-client.d.ts +53 -0
  95. package/dist/runner/runner-client.d.ts.map +1 -0
  96. package/dist/runner/runner-client.js +157 -0
  97. package/dist/runner/runner-client.js.map +1 -0
  98. package/dist/runner/types.d.ts +37 -0
  99. package/dist/runner/types.d.ts.map +1 -0
  100. package/dist/runner/types.js +2 -0
  101. package/dist/runner/types.js.map +1 -0
  102. package/dist/schemas.d.ts +3 -0
  103. package/dist/schemas.d.ts.map +1 -0
  104. package/dist/schemas.js +73 -0
  105. package/dist/schemas.js.map +1 -0
  106. package/package.json +44 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ash Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=auth.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/auth.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,111 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
2
+ import Fastify from 'fastify';
3
+ import { registerAuth } from '../auth.js';
4
+ /** Build a minimal Fastify app with auth + a test route. */
5
+ async function buildApp(apiKey) {
6
+ const app = Fastify({ logger: false });
7
+ registerAuth(app, apiKey);
8
+ // Stub routes to test against
9
+ app.get('/health', async () => ({ status: 'ok' }));
10
+ app.get('/docs/json', async () => ({ spec: true }));
11
+ app.get('/api/agents', async () => ({ agents: [] }));
12
+ app.post('/api/sessions', async () => ({ session: {} }));
13
+ await app.ready();
14
+ return app;
15
+ }
16
+ describe('API key auth middleware', () => {
17
+ describe('when ASH_API_KEY is set', () => {
18
+ const API_KEY = 'test-secret-key-12345';
19
+ let app;
20
+ beforeAll(async () => { app = await buildApp(API_KEY); });
21
+ afterAll(async () => { await app.close(); });
22
+ it('rejects requests without Authorization header', async () => {
23
+ const res = await app.inject({ method: 'GET', url: '/api/agents' });
24
+ expect(res.statusCode).toBe(401);
25
+ expect(res.json().error).toBe('Missing Authorization header');
26
+ });
27
+ it('rejects requests with wrong API key', async () => {
28
+ const res = await app.inject({
29
+ method: 'GET',
30
+ url: '/api/agents',
31
+ headers: { authorization: 'Bearer wrong-key' },
32
+ });
33
+ expect(res.statusCode).toBe(401);
34
+ expect(res.json().error).toBe('Invalid API key');
35
+ });
36
+ it('rejects requests with malformed Authorization header', async () => {
37
+ const res = await app.inject({
38
+ method: 'GET',
39
+ url: '/api/agents',
40
+ headers: { authorization: `Basic ${API_KEY}` },
41
+ });
42
+ expect(res.statusCode).toBe(401);
43
+ expect(res.json().error).toBe('Invalid API key');
44
+ });
45
+ it('allows requests with correct API key', async () => {
46
+ const res = await app.inject({
47
+ method: 'GET',
48
+ url: '/api/agents',
49
+ headers: { authorization: `Bearer ${API_KEY}` },
50
+ });
51
+ expect(res.statusCode).toBe(200);
52
+ expect(res.json()).toEqual({ agents: [] });
53
+ });
54
+ it('allows /health without auth', async () => {
55
+ const res = await app.inject({ method: 'GET', url: '/health' });
56
+ expect(res.statusCode).toBe(200);
57
+ expect(res.json().status).toBe('ok');
58
+ });
59
+ it('allows /docs without auth', async () => {
60
+ const res = await app.inject({ method: 'GET', url: '/docs/json' });
61
+ expect(res.statusCode).toBe(200);
62
+ });
63
+ it('protects POST routes too', async () => {
64
+ const res = await app.inject({ method: 'POST', url: '/api/sessions' });
65
+ expect(res.statusCode).toBe(401);
66
+ });
67
+ });
68
+ describe('when ASH_API_KEY is not set', () => {
69
+ let app;
70
+ beforeAll(async () => { app = await buildApp(undefined); });
71
+ afterAll(async () => { await app.close(); });
72
+ it('allows all requests without auth', async () => {
73
+ const res = await app.inject({ method: 'GET', url: '/api/agents' });
74
+ expect(res.statusCode).toBe(200);
75
+ });
76
+ });
77
+ describe('real HTTP requests against auth-protected server', () => {
78
+ const API_KEY = 'test-secret-key-12345';
79
+ let app;
80
+ let serverUrl;
81
+ beforeAll(async () => {
82
+ app = await buildApp(API_KEY);
83
+ const address = await app.listen({ port: 0, host: '127.0.0.1' });
84
+ serverUrl = address;
85
+ });
86
+ afterAll(async () => { await app.close(); });
87
+ it('rejects when no API key is provided', async () => {
88
+ const res = await fetch(`${serverUrl}/api/agents`);
89
+ expect(res.status).toBe(401);
90
+ const body = await res.json();
91
+ expect(body.error).toBe('Missing Authorization header');
92
+ });
93
+ it('rejects when wrong API key is provided', async () => {
94
+ const res = await fetch(`${serverUrl}/api/agents`, {
95
+ headers: { authorization: 'Bearer wrong-key' },
96
+ });
97
+ expect(res.status).toBe(401);
98
+ const body = await res.json();
99
+ expect(body.error).toBe('Invalid API key');
100
+ });
101
+ it('succeeds when correct API key is provided', async () => {
102
+ const res = await fetch(`${serverUrl}/api/agents`, {
103
+ headers: { authorization: `Bearer ${API_KEY}` },
104
+ });
105
+ expect(res.status).toBe(200);
106
+ const body = await res.json();
107
+ expect(body.agents).toEqual([]);
108
+ });
109
+ });
110
+ });
111
+ //# sourceMappingURL=auth.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.test.js","sourceRoot":"","sources":["../../src/__tests__/auth.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=backpressure.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backpressure.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/backpressure.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,81 @@
1
+ import { describe, it, expect, vi, afterEach } from 'vitest';
2
+ import { PassThrough } from 'node:stream';
3
+ import { writeSSE } from '../routes/sessions.js';
4
+ describe('writeSSE backpressure', () => {
5
+ afterEach(() => {
6
+ vi.useRealTimers();
7
+ });
8
+ it('writes immediately when buffer has room', async () => {
9
+ const written = [];
10
+ const fakeRaw = {
11
+ write: (data) => {
12
+ written.push(data);
13
+ return true; // buffer has room
14
+ },
15
+ once: () => { },
16
+ };
17
+ await writeSSE(fakeRaw, 'event: message\ndata: {"hello":"world"}\n\n');
18
+ expect(written).toHaveLength(1);
19
+ expect(written[0]).toContain('hello');
20
+ });
21
+ it('waits for drain when write returns false', async () => {
22
+ const written = [];
23
+ let drainCb = null;
24
+ const fakeRaw = {
25
+ write: (data) => {
26
+ written.push(data);
27
+ return false; // buffer full
28
+ },
29
+ once: (event, cb) => {
30
+ if (event === 'drain')
31
+ drainCb = cb;
32
+ },
33
+ };
34
+ let resolved = false;
35
+ const writePromise = writeSSE(fakeRaw, 'event: test\ndata: {}\n\n').then(() => {
36
+ resolved = true;
37
+ });
38
+ // Give the microtask queue a tick — writeSSE should be waiting for drain
39
+ await new Promise((r) => setTimeout(r, 10));
40
+ expect(resolved).toBe(false);
41
+ expect(drainCb).not.toBeNull();
42
+ // Simulate drain
43
+ drainCb();
44
+ await writePromise;
45
+ expect(resolved).toBe(true);
46
+ expect(written).toHaveLength(1);
47
+ });
48
+ it('blocks when client never drains (timeout behavior)', async () => {
49
+ const fakeRaw = {
50
+ write: () => false,
51
+ once: (_event, _cb) => {
52
+ // Never call the callback — simulates a dead client
53
+ },
54
+ };
55
+ // writeSSE will wait up to SSE_WRITE_TIMEOUT_MS (30s) — verify it doesn't
56
+ // resolve within a short window, proving it's blocked on drain
57
+ const result = await Promise.race([
58
+ writeSSE(fakeRaw, 'event: test\ndata: {}\n\n').then(() => 'resolved').catch(() => 'rejected'),
59
+ new Promise((resolve) => setTimeout(() => resolve('still-waiting'), 200)),
60
+ ]);
61
+ expect(result).toBe('still-waiting');
62
+ });
63
+ it('handles multiple sequential writes when buffer drains', async () => {
64
+ // Use a PassThrough with a large enough buffer and consume output
65
+ const stream = new PassThrough({ highWaterMark: 64 * 1024 });
66
+ const raw = stream;
67
+ const chunks = [];
68
+ // Consume output so the buffer stays drained
69
+ stream.on('data', (chunk) => {
70
+ chunks.push(chunk.toString());
71
+ });
72
+ for (let i = 0; i < 10; i++) {
73
+ await writeSSE(raw, `event: message\ndata: {"i":${i}}\n\n`);
74
+ }
75
+ expect(chunks).toHaveLength(10);
76
+ expect(chunks[0]).toContain('"i":0');
77
+ expect(chunks[9]).toContain('"i":9');
78
+ stream.destroy();
79
+ });
80
+ });
81
+ //# sourceMappingURL=backpressure.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backpressure.test.js","sourceRoot":"","sources":["../../src/__tests__/backpressure.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=db.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/db.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,111 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdtempSync, rmSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import { initDb, closeDb, upsertAgent, getAgent, listAgents, deleteAgent, insertSession, getSession, listSessions, updateSessionStatus, updateSessionSandbox, touchSession, } from '../db/index.js';
6
+ describe('database', () => {
7
+ let dataDir;
8
+ beforeEach(async () => {
9
+ dataDir = mkdtempSync(join(tmpdir(), 'ash-test-db-'));
10
+ await initDb({ dataDir });
11
+ });
12
+ afterEach(async () => {
13
+ await closeDb();
14
+ rmSync(dataDir, { recursive: true, force: true });
15
+ });
16
+ it('uses SQLite by default when no databaseUrl is provided', async () => {
17
+ // initDb was already called in beforeEach without databaseUrl — verify it works
18
+ const agent = await upsertAgent('default-backend-test', '/tmp/test');
19
+ expect(agent.name).toBe('default-backend-test');
20
+ });
21
+ // -- Agents -----------------------------------------------------------------
22
+ describe('agents', () => {
23
+ it('creates an agent', async () => {
24
+ const agent = await upsertAgent('test-agent', '/tmp/agent');
25
+ expect(agent.name).toBe('test-agent');
26
+ expect(agent.version).toBe(1);
27
+ expect(agent.path).toBe('/tmp/agent');
28
+ });
29
+ it('increments version on upsert', async () => {
30
+ await upsertAgent('test-agent', '/tmp/v1');
31
+ const v2 = await upsertAgent('test-agent', '/tmp/v2');
32
+ expect(v2.version).toBe(2);
33
+ expect(v2.path).toBe('/tmp/v2');
34
+ });
35
+ it('gets an agent by name', async () => {
36
+ await upsertAgent('my-agent', '/tmp/path');
37
+ const agent = await getAgent('my-agent');
38
+ expect(agent).not.toBeNull();
39
+ expect(agent.name).toBe('my-agent');
40
+ });
41
+ it('returns null for nonexistent agent', async () => {
42
+ expect(await getAgent('ghost')).toBeNull();
43
+ });
44
+ it('lists all agents', async () => {
45
+ await upsertAgent('a', '/tmp/a');
46
+ await upsertAgent('b', '/tmp/b');
47
+ const agents = await listAgents();
48
+ expect(agents).toHaveLength(2);
49
+ expect(agents.map((a) => a.name)).toEqual(['a', 'b']);
50
+ });
51
+ it('deletes an agent', async () => {
52
+ await upsertAgent('doomed', '/tmp/doomed');
53
+ expect(await deleteAgent('doomed')).toBe(true);
54
+ expect(await getAgent('doomed')).toBeNull();
55
+ });
56
+ it('returns false when deleting nonexistent agent', async () => {
57
+ expect(await deleteAgent('ghost')).toBe(false);
58
+ });
59
+ });
60
+ // -- Sessions ---------------------------------------------------------------
61
+ describe('sessions', () => {
62
+ beforeEach(async () => {
63
+ await upsertAgent('test-agent', '/tmp/agent');
64
+ });
65
+ it('creates a session', async () => {
66
+ const session = await insertSession('s1', 'test-agent', 'sandbox-1');
67
+ expect(session.id).toBe('s1');
68
+ expect(session.agentName).toBe('test-agent');
69
+ expect(session.status).toBe('starting');
70
+ });
71
+ it('updates session status', async () => {
72
+ await insertSession('s1', 'test-agent', 'sandbox-1');
73
+ await updateSessionStatus('s1', 'active');
74
+ const session = await getSession('s1');
75
+ expect(session.status).toBe('active');
76
+ });
77
+ it('follows status lifecycle: starting → active → ended', async () => {
78
+ await insertSession('s1', 'test-agent', 'sandbox-1');
79
+ expect((await getSession('s1')).status).toBe('starting');
80
+ await updateSessionStatus('s1', 'active');
81
+ expect((await getSession('s1')).status).toBe('active');
82
+ await updateSessionStatus('s1', 'ended');
83
+ expect((await getSession('s1')).status).toBe('ended');
84
+ });
85
+ it('lists sessions (newest first)', async () => {
86
+ await insertSession('s1', 'test-agent', 'sb1');
87
+ await insertSession('s2', 'test-agent', 'sb2');
88
+ const sessions = await listSessions();
89
+ expect(sessions).toHaveLength(2);
90
+ });
91
+ it('returns null for nonexistent session', async () => {
92
+ expect(await getSession('ghost')).toBeNull();
93
+ });
94
+ it('touch updates lastActiveAt', async () => {
95
+ await insertSession('s1', 'test-agent', 'sb1');
96
+ const before = (await getSession('s1')).lastActiveAt;
97
+ // Small delay to ensure timestamp difference
98
+ await touchSession('s1');
99
+ const after = (await getSession('s1')).lastActiveAt;
100
+ expect(after).toBeTruthy();
101
+ });
102
+ it('updates sandbox ID', async () => {
103
+ await insertSession('s1', 'test-agent', 'sb-old');
104
+ expect((await getSession('s1')).sandboxId).toBe('sb-old');
105
+ await updateSessionSandbox('s1', 'sb-new');
106
+ const session = (await getSession('s1'));
107
+ expect(session.sandboxId).toBe('sb-new');
108
+ });
109
+ });
110
+ });
111
+ //# sourceMappingURL=db.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.test.js","sourceRoot":"","sources":["../../src/__tests__/db.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EACL,MAAM,EACN,OAAO,EACP,WAAW,EACX,QAAQ,EACR,UAAU,EACV,WAAW,EACX,aAAa,EACb,UAAU,EACV,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,YAAY,GACb,MAAM,gBAAgB,CAAC;AAExB,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,IAAI,OAAe,CAAC;IAEpB,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,cAAc,CAAC,CAAC,CAAC;QACtD,MAAM,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,OAAO,EAAE,CAAC;QAChB,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,KAAK,IAAI,EAAE;QACtE,gFAAgF;QAChF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,sBAAsB,EAAE,WAAW,CAAC,CAAC;QACrE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,8EAA8E;IAE9E,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;QACtB,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;YAChC,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;YAC5D,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACtC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,WAAW,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;YAC3C,MAAM,EAAE,GAAG,MAAM,WAAW,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;YACtD,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3B,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;YACrC,MAAM,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;YAC3C,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC;YACzC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC7B,MAAM,CAAC,KAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,CAAC,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;YAChC,MAAM,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACjC,MAAM,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;YAClC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE;YAChC,MAAM,WAAW,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC9C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;YAC7D,MAAM,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,8EAA8E;IAE9E,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;QACxB,UAAU,CAAC,KAAK,IAAI,EAAE;YACpB,MAAM,WAAW,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;YACjC,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;YACrE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9B,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC7C,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wBAAwB,EAAE,KAAK,IAAI,EAAE;YACtC,MAAM,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;YACrD,MAAM,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC1C,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;YACvC,MAAM,CAAC,OAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;YACnE,MAAM,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;YACrD,MAAM,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAE1D,MAAM,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC1C,MAAM,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAExD,MAAM,mBAAmB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACzC,MAAM,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC7C,MAAM,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;YAC/C,MAAM,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAC;YACtC,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;YACpD,MAAM,CAAC,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4BAA4B,EAAE,KAAK,IAAI,EAAE;YAC1C,MAAM,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAE,CAAC,YAAY,CAAC;YAEtD,6CAA6C;YAC7C,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;YACzB,MAAM,KAAK,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAE,CAAC,YAAY,CAAC;YACrD,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oBAAoB,EAAE,KAAK,IAAI,EAAE;YAClC,MAAM,aAAa,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;YAClD,MAAM,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAE,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAE3D,MAAM,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC3C,MAAM,OAAO,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAE,CAAC;YAC1C,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=files.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/files.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,171 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import Fastify from 'fastify';
6
+ import { registerSchemas } from '../schemas.js';
7
+ import { fileRoutes } from '../routes/files.js';
8
+ import { initDb, closeDb, upsertAgent, insertSession, updateSessionStatus } from '../db/index.js';
9
+ // Minimal mock coordinator that returns a mock backend pointing at a workspace dir
10
+ function mockCoordinator(workspaceDir) {
11
+ const handle = workspaceDir
12
+ ? { sandboxId: 'sbx-1', workspaceDir }
13
+ : undefined;
14
+ const backend = {
15
+ getSandbox: () => handle,
16
+ };
17
+ return {
18
+ getBackendForRunner: () => backend,
19
+ };
20
+ }
21
+ describe('file routes', () => {
22
+ let dataDir;
23
+ let workspaceDir;
24
+ beforeEach(async () => {
25
+ dataDir = mkdtempSync(join(tmpdir(), 'ash-files-test-'));
26
+ workspaceDir = mkdtempSync(join(tmpdir(), 'ash-files-ws-'));
27
+ await initDb({ dataDir });
28
+ });
29
+ afterEach(async () => {
30
+ await closeDb();
31
+ rmSync(dataDir, { recursive: true, force: true });
32
+ rmSync(workspaceDir, { recursive: true, force: true });
33
+ });
34
+ function populateWorkspace() {
35
+ writeFileSync(join(workspaceDir, 'CLAUDE.md'), '# Agent');
36
+ mkdirSync(join(workspaceDir, 'src'), { recursive: true });
37
+ writeFileSync(join(workspaceDir, 'src', 'index.ts'), 'console.log("hello")');
38
+ writeFileSync(join(workspaceDir, 'src', 'util.ts'), 'export const x = 1;');
39
+ // Filtered dirs
40
+ mkdirSync(join(workspaceDir, 'node_modules', 'pkg'), { recursive: true });
41
+ writeFileSync(join(workspaceDir, 'node_modules', 'pkg', 'index.js'), '');
42
+ mkdirSync(join(workspaceDir, '.git'), { recursive: true });
43
+ writeFileSync(join(workspaceDir, '.git', 'HEAD'), 'ref');
44
+ }
45
+ async function buildApp(coordinator) {
46
+ const app = Fastify();
47
+ registerSchemas(app);
48
+ fileRoutes(app, coordinator, dataDir);
49
+ await app.ready();
50
+ return app;
51
+ }
52
+ async function createTestSession() {
53
+ await upsertAgent('test-agent', '/tmp/agent');
54
+ const session = await insertSession('11111111-1111-1111-1111-111111111111', 'test-agent', 'sbx-1');
55
+ await updateSessionStatus(session.id, 'active');
56
+ return session;
57
+ }
58
+ describe('GET /api/sessions/:id/files', () => {
59
+ it('lists files from live sandbox workspace', async () => {
60
+ populateWorkspace();
61
+ const session = await createTestSession();
62
+ const app = await buildApp(mockCoordinator(workspaceDir));
63
+ const res = await app.inject({
64
+ method: 'GET',
65
+ url: `/api/sessions/${session.id}/files`,
66
+ });
67
+ expect(res.statusCode).toBe(200);
68
+ const body = res.json();
69
+ expect(body.source).toBe('sandbox');
70
+ expect(body.files).toBeInstanceOf(Array);
71
+ const paths = body.files.map((f) => f.path).sort();
72
+ expect(paths).toContain('CLAUDE.md');
73
+ expect(paths).toContain('src/index.ts');
74
+ expect(paths).toContain('src/util.ts');
75
+ // Filtered dirs should not appear
76
+ expect(paths.find((p) => p.includes('node_modules'))).toBeUndefined();
77
+ expect(paths.find((p) => p.includes('.git'))).toBeUndefined();
78
+ });
79
+ it('returns file sizes and modifiedAt', async () => {
80
+ populateWorkspace();
81
+ const session = await createTestSession();
82
+ const app = await buildApp(mockCoordinator(workspaceDir));
83
+ const res = await app.inject({
84
+ method: 'GET',
85
+ url: `/api/sessions/${session.id}/files`,
86
+ });
87
+ const body = res.json();
88
+ const claude = body.files.find((f) => f.path === 'CLAUDE.md');
89
+ expect(claude).toBeDefined();
90
+ expect(claude.size).toBe(7); // '# Agent'
91
+ expect(claude.modifiedAt).toBeTruthy();
92
+ });
93
+ it('falls back to persisted snapshot when sandbox is gone', async () => {
94
+ populateWorkspace();
95
+ const session = await createTestSession();
96
+ // Persist state to snapshot location
97
+ const snapshotDir = join(dataDir, 'sessions', session.sandboxId, 'workspace');
98
+ mkdirSync(snapshotDir, { recursive: true });
99
+ writeFileSync(join(snapshotDir, 'snapshot-file.txt'), 'from snapshot');
100
+ // Coordinator returns no sandbox (sandbox gone)
101
+ const app = await buildApp(mockCoordinator(null));
102
+ const res = await app.inject({
103
+ method: 'GET',
104
+ url: `/api/sessions/${session.id}/files`,
105
+ });
106
+ expect(res.statusCode).toBe(200);
107
+ const body = res.json();
108
+ expect(body.source).toBe('snapshot');
109
+ expect(body.files.map((f) => f.path)).toContain('snapshot-file.txt');
110
+ });
111
+ it('returns 404 for unknown session', async () => {
112
+ const app = await buildApp(mockCoordinator(null));
113
+ const res = await app.inject({
114
+ method: 'GET',
115
+ url: '/api/sessions/99999999-9999-9999-9999-999999999999/files',
116
+ });
117
+ expect(res.statusCode).toBe(404);
118
+ });
119
+ it('returns 404 when no workspace available', async () => {
120
+ const session = await createTestSession();
121
+ const app = await buildApp(mockCoordinator(null));
122
+ const res = await app.inject({
123
+ method: 'GET',
124
+ url: `/api/sessions/${session.id}/files`,
125
+ });
126
+ expect(res.statusCode).toBe(404);
127
+ });
128
+ });
129
+ describe('GET /api/sessions/:id/files/*path', () => {
130
+ it('reads a single file', async () => {
131
+ populateWorkspace();
132
+ const session = await createTestSession();
133
+ const app = await buildApp(mockCoordinator(workspaceDir));
134
+ const res = await app.inject({
135
+ method: 'GET',
136
+ url: `/api/sessions/${session.id}/files/src/index.ts`,
137
+ });
138
+ expect(res.statusCode).toBe(200);
139
+ const body = res.json();
140
+ expect(body.path).toBe('src/index.ts');
141
+ expect(body.content).toBe('console.log("hello")');
142
+ expect(body.size).toBe(20);
143
+ expect(body.source).toBe('sandbox');
144
+ });
145
+ it('returns 404 for nonexistent file', async () => {
146
+ populateWorkspace();
147
+ const session = await createTestSession();
148
+ const app = await buildApp(mockCoordinator(workspaceDir));
149
+ const res = await app.inject({
150
+ method: 'GET',
151
+ url: `/api/sessions/${session.id}/files/nope.txt`,
152
+ });
153
+ expect(res.statusCode).toBe(404);
154
+ });
155
+ it('rejects path traversal with ..', async () => {
156
+ populateWorkspace();
157
+ const session = await createTestSession();
158
+ const app = await buildApp(mockCoordinator(workspaceDir));
159
+ // Fastify normalizes ../ in URLs before the handler runs, so the path
160
+ // resolves to something that doesn't exist (404). Either way, the
161
+ // traversal is blocked — the file can't be read.
162
+ const res = await app.inject({
163
+ method: 'GET',
164
+ url: `/api/sessions/${session.id}/files/../../../etc/passwd`,
165
+ });
166
+ expect([400, 404]).toContain(res.statusCode);
167
+ expect(res.json().content).toBeUndefined();
168
+ });
169
+ });
170
+ });
171
+ //# sourceMappingURL=files.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.test.js","sourceRoot":"","sources":["../../src/__tests__/files.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=openapi.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/openapi.test.ts"],"names":[],"mappings":""}