@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
@@ -0,0 +1,26 @@
1
+ import type { BridgeCommand, BridgeEvent, PoolStats } from '@ash-ai/shared';
2
+ import { SandboxPool } from '@ash-ai/sandbox';
3
+ import type { RunnerBackend, CreateSandboxRequest, SandboxHandle } from './types.js';
4
+ /**
5
+ * Local (in-process) runner backend. Wraps SandboxPool for single-machine mode.
6
+ * This is the default — no network hop, no process boundary beyond the sandbox itself.
7
+ */
8
+ export declare class LocalRunnerBackend implements RunnerBackend {
9
+ private pool;
10
+ private dataDir;
11
+ constructor(pool: SandboxPool, dataDir: string);
12
+ createSandbox(opts: CreateSandboxRequest): Promise<SandboxHandle>;
13
+ destroySandbox(sandboxId: string): Promise<void>;
14
+ destroyAll(): Promise<void>;
15
+ sendCommand(sandboxId: string, cmd: BridgeCommand): AsyncGenerator<BridgeEvent>;
16
+ getSandbox(sandboxId: string): SandboxHandle | undefined;
17
+ isSandboxAlive(sandboxId: string): boolean;
18
+ markRunning(sandboxId: string): void;
19
+ markWaiting(sandboxId: string): void;
20
+ recordWarmHit(): void;
21
+ recordColdHit(): void;
22
+ persistState(sandboxId: string, sessionId: string, agentName: string): boolean;
23
+ getStats(): Promise<PoolStats>;
24
+ get activeCount(): number;
25
+ }
26
+ //# sourceMappingURL=local-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-backend.d.ts","sourceRoot":"","sources":["../../src/runner/local-backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAyC,MAAM,iBAAiB,CAAC;AACrF,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAErF;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,aAAa;IAEpD,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,OAAO;gBADP,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,MAAM;IAGnB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC;IAajE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAI1B,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,cAAc,CAAC,WAAW,CAAC;IAQtF,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAMxD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAM1C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIpC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAIpC,aAAa,IAAI,IAAI;IAIrB,aAAa,IAAI,IAAI;IAIrB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAYxE,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC;IAIpC,IAAI,WAAW,IAAI,MAAM,CAExB;CACF"}
@@ -0,0 +1,79 @@
1
+ import { persistSessionState, syncStateToCloud } from '@ash-ai/sandbox';
2
+ /**
3
+ * Local (in-process) runner backend. Wraps SandboxPool for single-machine mode.
4
+ * This is the default — no network hop, no process boundary beyond the sandbox itself.
5
+ */
6
+ export class LocalRunnerBackend {
7
+ pool;
8
+ dataDir;
9
+ constructor(pool, dataDir) {
10
+ this.pool = pool;
11
+ this.dataDir = dataDir;
12
+ }
13
+ async createSandbox(opts) {
14
+ const sandbox = await this.pool.create({
15
+ agentDir: opts.agentDir,
16
+ sessionId: opts.sessionId,
17
+ id: opts.sandboxId,
18
+ agentName: opts.agentName,
19
+ skipAgentCopy: opts.skipAgentCopy,
20
+ limits: opts.limits,
21
+ onOomKill: opts.onOomKill,
22
+ });
23
+ return { sandboxId: sandbox.id, workspaceDir: sandbox.workspaceDir };
24
+ }
25
+ async destroySandbox(sandboxId) {
26
+ await this.pool.destroy(sandboxId);
27
+ }
28
+ async destroyAll() {
29
+ await this.pool.destroyAll();
30
+ }
31
+ async *sendCommand(sandboxId, cmd) {
32
+ const sandbox = this.pool.get(sandboxId);
33
+ if (!sandbox) {
34
+ throw new Error(`Sandbox ${sandboxId} not found`);
35
+ }
36
+ yield* sandbox.client.sendCommand(cmd);
37
+ }
38
+ getSandbox(sandboxId) {
39
+ const sandbox = this.pool.get(sandboxId);
40
+ if (!sandbox)
41
+ return undefined;
42
+ return { sandboxId: sandbox.id, workspaceDir: sandbox.workspaceDir };
43
+ }
44
+ isSandboxAlive(sandboxId) {
45
+ const sandbox = this.pool.get(sandboxId);
46
+ if (!sandbox)
47
+ return false;
48
+ return sandbox.process.exitCode === null;
49
+ }
50
+ markRunning(sandboxId) {
51
+ this.pool.markRunning(sandboxId);
52
+ }
53
+ markWaiting(sandboxId) {
54
+ this.pool.markWaiting(sandboxId);
55
+ }
56
+ recordWarmHit() {
57
+ this.pool.recordWarmHit();
58
+ }
59
+ recordColdHit() {
60
+ this.pool.recordColdHit();
61
+ }
62
+ persistState(sandboxId, sessionId, agentName) {
63
+ const sandbox = this.pool.get(sandboxId);
64
+ if (!sandbox)
65
+ return false;
66
+ const ok = persistSessionState(this.dataDir, sessionId, sandbox.workspaceDir, agentName);
67
+ if (ok) {
68
+ syncStateToCloud(this.dataDir, sessionId).catch((err) => console.error(`[local-backend] Cloud sync failed for ${sessionId}:`, err));
69
+ }
70
+ return ok;
71
+ }
72
+ async getStats() {
73
+ return this.pool.statsAsync();
74
+ }
75
+ get activeCount() {
76
+ return this.pool.activeCount;
77
+ }
78
+ }
79
+ //# sourceMappingURL=local-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-backend.js","sourceRoot":"","sources":["../../src/runner/local-backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { BridgeCommand, BridgeEvent, PoolStats } from '@ash-ai/shared';
2
+ import { RunnerClient } from './runner-client.js';
3
+ import type { RunnerBackend, CreateSandboxRequest, SandboxHandle } from './types.js';
4
+ /**
5
+ * Remote runner backend. Delegates all sandbox operations to a runner process
6
+ * over HTTP. Used in multi-runner (coordinator) mode.
7
+ */
8
+ export declare class RemoteRunnerBackend implements RunnerBackend {
9
+ private client;
10
+ private sandboxes;
11
+ constructor(opts: {
12
+ host: string;
13
+ port: number;
14
+ });
15
+ createSandbox(opts: CreateSandboxRequest): Promise<SandboxHandle>;
16
+ destroySandbox(sandboxId: string): Promise<void>;
17
+ destroyAll(): Promise<void>;
18
+ sendCommand(sandboxId: string, cmd: BridgeCommand): AsyncGenerator<BridgeEvent>;
19
+ getSandbox(sandboxId: string): SandboxHandle | undefined;
20
+ isSandboxAlive(sandboxId: string): boolean;
21
+ markRunning(sandboxId: string): void;
22
+ markWaiting(sandboxId: string): void;
23
+ recordWarmHit(): void;
24
+ recordColdHit(): void;
25
+ persistState(sandboxId: string, sessionId: string, agentName: string): boolean;
26
+ getStats(): Promise<PoolStats>;
27
+ get activeCount(): number;
28
+ /** Expose the underlying RunnerClient for health checks. */
29
+ getClient(): RunnerClient;
30
+ close(): void;
31
+ }
32
+ //# sourceMappingURL=remote-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-backend.d.ts","sourceRoot":"","sources":["../../src/runner/remote-backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAErF;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,aAAa;IACvD,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAoC;gBAEzC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAI1C,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC;IAkBjE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK1B,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,cAAc,CAAC,WAAW,CAAC;IAItF,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIxD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAM1C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKpC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKpC,aAAa,IAAI,IAAI;IAIrB,aAAa,IAAI,IAAI;IAIrB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAMxE,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC;IAKpC,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,4DAA4D;IAC5D,SAAS,IAAI,YAAY;IAIzB,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,81 @@
1
+ import { RunnerClient } from './runner-client.js';
2
+ /**
3
+ * Remote runner backend. Delegates all sandbox operations to a runner process
4
+ * over HTTP. Used in multi-runner (coordinator) mode.
5
+ */
6
+ export class RemoteRunnerBackend {
7
+ client;
8
+ sandboxes = new Map(); // local cache
9
+ constructor(opts) {
10
+ this.client = new RunnerClient(opts);
11
+ }
12
+ async createSandbox(opts) {
13
+ const result = await this.client.createSandbox({
14
+ sessionId: opts.sessionId,
15
+ agentDir: opts.agentDir,
16
+ agentName: opts.agentName,
17
+ sandboxId: opts.sandboxId,
18
+ skipAgentCopy: opts.skipAgentCopy,
19
+ limits: opts.limits,
20
+ });
21
+ const handle = {
22
+ sandboxId: result.sandboxId,
23
+ workspaceDir: result.workspaceDir,
24
+ };
25
+ this.sandboxes.set(result.sandboxId, handle);
26
+ return handle;
27
+ }
28
+ async destroySandbox(sandboxId) {
29
+ await this.client.destroySandbox(sandboxId);
30
+ this.sandboxes.delete(sandboxId);
31
+ }
32
+ async destroyAll() {
33
+ const ids = [...this.sandboxes.keys()];
34
+ await Promise.all(ids.map((id) => this.destroySandbox(id)));
35
+ }
36
+ async *sendCommand(sandboxId, cmd) {
37
+ yield* this.client.sendCommand(sandboxId, cmd);
38
+ }
39
+ getSandbox(sandboxId) {
40
+ return this.sandboxes.get(sandboxId);
41
+ }
42
+ isSandboxAlive(sandboxId) {
43
+ // We can't synchronously check a remote process. If we have it cached, assume alive.
44
+ // The coordinator does periodic health checks to detect dead runners.
45
+ return this.sandboxes.has(sandboxId);
46
+ }
47
+ markRunning(sandboxId) {
48
+ // Fire-and-forget to runner
49
+ this.client.markState(sandboxId, 'running').catch(() => { });
50
+ }
51
+ markWaiting(sandboxId) {
52
+ // Fire-and-forget to runner
53
+ this.client.markState(sandboxId, 'waiting').catch(() => { });
54
+ }
55
+ recordWarmHit() {
56
+ // Remote runners track their own metrics — no-op here
57
+ }
58
+ recordColdHit() {
59
+ // Remote runners track their own metrics — no-op here
60
+ }
61
+ persistState(sandboxId, sessionId, agentName) {
62
+ // Fire-and-forget to runner. Returns true optimistically.
63
+ this.client.persistState(sandboxId, sessionId, agentName).catch(() => { });
64
+ return true;
65
+ }
66
+ async getStats() {
67
+ const health = await this.client.health();
68
+ return health.pool;
69
+ }
70
+ get activeCount() {
71
+ return this.sandboxes.size;
72
+ }
73
+ /** Expose the underlying RunnerClient for health checks. */
74
+ getClient() {
75
+ return this.client;
76
+ }
77
+ close() {
78
+ this.client.close();
79
+ }
80
+ }
81
+ //# sourceMappingURL=remote-backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-backend.js","sourceRoot":"","sources":["../../src/runner/remote-backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { BridgeCommand, BridgeEvent, PoolStats } from '@ash-ai/shared';
2
+ export interface RunnerHealthResponse {
3
+ runnerId: string;
4
+ status: string;
5
+ capacity: {
6
+ max: number;
7
+ active: number;
8
+ available: number;
9
+ };
10
+ pool: PoolStats;
11
+ uptime: number;
12
+ }
13
+ /**
14
+ * HTTP client to a single runner process.
15
+ * Uses standard HTTP (Fastify on the runner side). For SSE streaming,
16
+ * parses the event stream from the response body.
17
+ */
18
+ export declare class RunnerClient {
19
+ private baseUrl;
20
+ private _closed;
21
+ constructor(opts: {
22
+ host: string;
23
+ port: number;
24
+ });
25
+ createSandbox(opts: {
26
+ sessionId: string;
27
+ agentDir: string;
28
+ agentName: string;
29
+ sandboxId?: string;
30
+ skipAgentCopy?: boolean;
31
+ limits?: Record<string, number>;
32
+ }): Promise<{
33
+ sandboxId: string;
34
+ workspaceDir: string;
35
+ }>;
36
+ destroySandbox(sandboxId: string): Promise<void>;
37
+ /**
38
+ * Send a command to a sandbox and return an async generator of bridge events.
39
+ * Parses SSE from the HTTP response body.
40
+ */
41
+ sendCommand(sandboxId: string, cmd: BridgeCommand): AsyncGenerator<BridgeEvent>;
42
+ getSandbox(sandboxId: string): Promise<{
43
+ sandboxId: string;
44
+ workspaceDir: string;
45
+ alive: boolean;
46
+ } | null>;
47
+ markState(sandboxId: string, state: 'running' | 'waiting'): Promise<void>;
48
+ persistState(sandboxId: string, sessionId: string, agentName: string): Promise<boolean>;
49
+ health(): Promise<RunnerHealthResponse>;
50
+ close(): void;
51
+ get closed(): boolean;
52
+ }
53
+ //# sourceMappingURL=runner-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-client.d.ts","sourceRoot":"","sources":["../../src/runner/runner-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE5E,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE;QACR,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,IAAI,EAAE,SAAS,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;gBAEZ,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAI1C,aAAa,CAAC,IAAI,EAAE;QACxB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACjC,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IAelD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWtD;;;OAGG;IACI,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,cAAc,CAAC,WAAW,CAAC;IAqDhF,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IAS1G,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzE,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvF,MAAM,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAQ7C,KAAK,IAAI,IAAI;IAIb,IAAI,MAAM,IAAI,OAAO,CAEpB;CACF"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * HTTP client to a single runner process.
3
+ * Uses standard HTTP (Fastify on the runner side). For SSE streaming,
4
+ * parses the event stream from the response body.
5
+ */
6
+ export class RunnerClient {
7
+ baseUrl;
8
+ _closed = false;
9
+ constructor(opts) {
10
+ this.baseUrl = `http://${opts.host}:${opts.port}`;
11
+ }
12
+ async createSandbox(opts) {
13
+ const resp = await fetch(`${this.baseUrl}/runner/sandboxes`, {
14
+ method: 'POST',
15
+ headers: { 'Content-Type': 'application/json' },
16
+ body: JSON.stringify(opts),
17
+ });
18
+ if (!resp.ok) {
19
+ const body = await resp.text();
20
+ throw new Error(`Runner createSandbox failed (${resp.status}): ${body}`);
21
+ }
22
+ return resp.json();
23
+ }
24
+ async destroySandbox(sandboxId) {
25
+ const resp = await fetch(`${this.baseUrl}/runner/sandboxes/${sandboxId}`, {
26
+ method: 'DELETE',
27
+ });
28
+ if (!resp.ok && resp.status !== 404) {
29
+ const body = await resp.text();
30
+ throw new Error(`Runner destroySandbox failed (${resp.status}): ${body}`);
31
+ }
32
+ }
33
+ /**
34
+ * Send a command to a sandbox and return an async generator of bridge events.
35
+ * Parses SSE from the HTTP response body.
36
+ */
37
+ async *sendCommand(sandboxId, cmd) {
38
+ const resp = await fetch(`${this.baseUrl}/runner/sandboxes/${sandboxId}/cmd`, {
39
+ method: 'POST',
40
+ headers: { 'Content-Type': 'application/json' },
41
+ body: JSON.stringify(cmd),
42
+ });
43
+ if (!resp.ok) {
44
+ const body = await resp.text();
45
+ throw new Error(`Runner sendCommand failed (${resp.status}): ${body}`);
46
+ }
47
+ if (!resp.body) {
48
+ throw new Error('Runner sendCommand: no response body');
49
+ }
50
+ // Parse SSE from response body stream
51
+ const reader = resp.body.getReader();
52
+ const decoder = new TextDecoder();
53
+ let buffer = '';
54
+ try {
55
+ while (true) {
56
+ const { done, value } = await reader.read();
57
+ if (done)
58
+ break;
59
+ buffer += decoder.decode(value, { stream: true });
60
+ // Process complete SSE events
61
+ let doubleNewline;
62
+ while ((doubleNewline = buffer.indexOf('\n\n')) !== -1) {
63
+ const eventBlock = buffer.slice(0, doubleNewline);
64
+ buffer = buffer.slice(doubleNewline + 2);
65
+ const event = parseSSEEvent(eventBlock);
66
+ if (event) {
67
+ yield event;
68
+ }
69
+ }
70
+ }
71
+ // Process any remaining buffer
72
+ if (buffer.trim()) {
73
+ const event = parseSSEEvent(buffer);
74
+ if (event) {
75
+ yield event;
76
+ }
77
+ }
78
+ }
79
+ finally {
80
+ reader.releaseLock();
81
+ }
82
+ }
83
+ async getSandbox(sandboxId) {
84
+ const resp = await fetch(`${this.baseUrl}/runner/sandboxes/${sandboxId}`);
85
+ if (resp.status === 404)
86
+ return null;
87
+ if (!resp.ok) {
88
+ throw new Error(`Runner getSandbox failed (${resp.status})`);
89
+ }
90
+ return resp.json();
91
+ }
92
+ async markState(sandboxId, state) {
93
+ await fetch(`${this.baseUrl}/runner/sandboxes/${sandboxId}/mark`, {
94
+ method: 'POST',
95
+ headers: { 'Content-Type': 'application/json' },
96
+ body: JSON.stringify({ state }),
97
+ });
98
+ }
99
+ async persistState(sandboxId, sessionId, agentName) {
100
+ const resp = await fetch(`${this.baseUrl}/runner/sandboxes/${sandboxId}/persist`, {
101
+ method: 'POST',
102
+ headers: { 'Content-Type': 'application/json' },
103
+ body: JSON.stringify({ sessionId, agentName }),
104
+ });
105
+ if (!resp.ok)
106
+ return false;
107
+ const result = await resp.json();
108
+ return result.success;
109
+ }
110
+ async health() {
111
+ const resp = await fetch(`${this.baseUrl}/runner/health`);
112
+ if (!resp.ok) {
113
+ throw new Error(`Runner health check failed (${resp.status})`);
114
+ }
115
+ return resp.json();
116
+ }
117
+ close() {
118
+ this._closed = true;
119
+ }
120
+ get closed() {
121
+ return this._closed;
122
+ }
123
+ }
124
+ /**
125
+ * Parse a single SSE event block into a BridgeEvent.
126
+ */
127
+ function parseSSEEvent(block) {
128
+ let eventType = '';
129
+ let data = '';
130
+ for (const line of block.split('\n')) {
131
+ if (line.startsWith('event: ')) {
132
+ eventType = line.slice(7);
133
+ }
134
+ else if (line.startsWith('data: ')) {
135
+ data = line.slice(6);
136
+ }
137
+ }
138
+ if (!eventType || !data)
139
+ return null;
140
+ try {
141
+ const parsed = JSON.parse(data);
142
+ if (eventType === 'message') {
143
+ return { ev: 'message', data: parsed };
144
+ }
145
+ else if (eventType === 'error') {
146
+ return { ev: 'error', error: parsed.error || 'Unknown error' };
147
+ }
148
+ else if (eventType === 'done') {
149
+ return { ev: 'done', sessionId: parsed.sessionId || '' };
150
+ }
151
+ }
152
+ catch {
153
+ // Malformed JSON — skip
154
+ }
155
+ return null;
156
+ }
157
+ //# sourceMappingURL=runner-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-client.js","sourceRoot":"","sources":["../../src/runner/runner-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { BridgeCommand, BridgeEvent, PoolStats, SandboxLimits } from '@ash-ai/shared';
2
+ export interface CreateSandboxRequest {
3
+ sessionId: string;
4
+ agentDir: string;
5
+ agentName: string;
6
+ sandboxId?: string;
7
+ skipAgentCopy?: boolean;
8
+ limits?: Partial<SandboxLimits>;
9
+ onOomKill?: (sandboxId: string) => void;
10
+ }
11
+ export interface SandboxHandle {
12
+ sandboxId: string;
13
+ workspaceDir: string;
14
+ }
15
+ /**
16
+ * Abstraction over sandbox management. Routes and the coordinator
17
+ * program against this interface — LocalRunnerBackend wraps SandboxPool
18
+ * for single-machine mode, RemoteRunnerBackend talks to a runner over HTTP/2.
19
+ */
20
+ export interface RunnerBackend {
21
+ createSandbox(opts: CreateSandboxRequest): Promise<SandboxHandle>;
22
+ destroySandbox(sandboxId: string): Promise<void>;
23
+ destroyAll(): Promise<void>;
24
+ sendCommand(sandboxId: string, cmd: BridgeCommand): AsyncGenerator<BridgeEvent>;
25
+ /** Returns sandbox info if alive, undefined if not found or dead. */
26
+ getSandbox(sandboxId: string): SandboxHandle | undefined;
27
+ /** Check if the sandbox process is still alive. */
28
+ isSandboxAlive(sandboxId: string): boolean;
29
+ markRunning(sandboxId: string): void;
30
+ markWaiting(sandboxId: string): void;
31
+ recordWarmHit(): void;
32
+ recordColdHit(): void;
33
+ persistState(sandboxId: string, sessionId: string, agentName: string): boolean;
34
+ getStats(): Promise<PoolStats>;
35
+ readonly activeCount: number;
36
+ }
37
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runner/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE3F,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAClE,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;IAEhF,qEAAqE;IACrE,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAAC;IAEzD,mDAAmD;IACnD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAE3C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAErC,aAAa,IAAI,IAAI,CAAC;IACtB,aAAa,IAAI,IAAI,CAAC;IAEtB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IAE/E,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/runner/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ export declare function registerSchemas(app: FastifyInstance): void;
3
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAyE/C,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CAM1D"}
@@ -0,0 +1,73 @@
1
+ // -- Reusable JSON Schema components ------------------------------------------
2
+ // Each gets a $id so routes can reference via { $ref: 'SchemaName#' }.
3
+ const AgentSchema = {
4
+ $id: 'Agent',
5
+ type: 'object',
6
+ properties: {
7
+ name: { type: 'string' },
8
+ version: { type: 'integer' },
9
+ path: { type: 'string' },
10
+ createdAt: { type: 'string', format: 'date-time' },
11
+ updatedAt: { type: 'string', format: 'date-time' },
12
+ },
13
+ required: ['name', 'version', 'path', 'createdAt', 'updatedAt'],
14
+ };
15
+ const SessionSchema = {
16
+ $id: 'Session',
17
+ type: 'object',
18
+ properties: {
19
+ id: { type: 'string', format: 'uuid' },
20
+ agentName: { type: 'string' },
21
+ sandboxId: { type: 'string' },
22
+ status: { type: 'string', enum: ['starting', 'active', 'paused', 'ended', 'error'] },
23
+ runnerId: { type: ['string', 'null'] },
24
+ createdAt: { type: 'string', format: 'date-time' },
25
+ lastActiveAt: { type: 'string', format: 'date-time' },
26
+ },
27
+ required: ['id', 'agentName', 'sandboxId', 'status', 'createdAt', 'lastActiveAt'],
28
+ };
29
+ const ApiErrorSchema = {
30
+ $id: 'ApiError',
31
+ type: 'object',
32
+ properties: {
33
+ error: { type: 'string' },
34
+ statusCode: { type: 'integer' },
35
+ },
36
+ required: ['error', 'statusCode'],
37
+ };
38
+ const PoolStatsSchema = {
39
+ $id: 'PoolStats',
40
+ type: 'object',
41
+ properties: {
42
+ total: { type: 'integer' },
43
+ cold: { type: 'integer' },
44
+ warming: { type: 'integer' },
45
+ warm: { type: 'integer' },
46
+ waiting: { type: 'integer' },
47
+ running: { type: 'integer' },
48
+ maxCapacity: { type: 'integer' },
49
+ resumeWarmHits: { type: 'integer' },
50
+ resumeColdHits: { type: 'integer' },
51
+ },
52
+ required: ['total', 'cold', 'warming', 'warm', 'waiting', 'running', 'maxCapacity', 'resumeWarmHits', 'resumeColdHits'],
53
+ };
54
+ const HealthResponseSchema = {
55
+ $id: 'HealthResponse',
56
+ type: 'object',
57
+ properties: {
58
+ status: { type: 'string', enum: ['ok'] },
59
+ activeSessions: { type: 'integer' },
60
+ activeSandboxes: { type: 'integer' },
61
+ uptime: { type: 'integer', description: 'Seconds since process start' },
62
+ pool: { $ref: 'PoolStats#' },
63
+ },
64
+ required: ['status', 'activeSessions', 'activeSandboxes', 'uptime', 'pool'],
65
+ };
66
+ export function registerSchemas(app) {
67
+ app.addSchema(AgentSchema);
68
+ app.addSchema(SessionSchema);
69
+ app.addSchema(ApiErrorSchema);
70
+ app.addSchema(PoolStatsSchema);
71
+ app.addSchema(HealthResponseSchema);
72
+ }
73
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAEA,gFAAgF;AAChF,uEAAuE;AAEvE,MAAM,WAAW,GAAG;IAClB,GAAG,EAAE,OAAO;IACZ,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACxB,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE;QAClD,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE;KACnD;IACD,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,CAAC;CACvD,CAAC;AAEX,MAAM,aAAa,GAAG;IACpB,GAAG,EAAE,SAAS;IACd,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE;QACtC,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC7B,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC7B,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QACpF,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE;QACtC,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE;QAClD,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE;KACtD;IACD,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,CAAC;CACzE,CAAC;AAEX,MAAM,cAAc,GAAG;IACrB,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QACzB,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;KAChC;IACD,QAAQ,EAAE,CAAC,OAAO,EAAE,YAAY,CAAC;CACzB,CAAC;AAEX,MAAM,eAAe,GAAG;IACtB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAC1B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACzB,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACzB,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAC5B,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAC5B,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QAChC,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACnC,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;KACpC;IACD,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,gBAAgB,EAAE,gBAAgB,CAAC;CAC/G,CAAC;AAEX,MAAM,oBAAoB,GAAG;IAC3B,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE;QACxC,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACnC,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACpC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,6BAA6B,EAAE;QACvE,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;KAC7B;IACD,QAAQ,EAAE,CAAC,QAAQ,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,CAAC;CACnE,CAAC;AAEX,MAAM,UAAU,eAAe,CAAC,GAAoB;IAClD,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAC3B,GAAG,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IAC7B,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC9B,GAAG,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IAC/B,GAAG,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;AACtC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@ash-ai/server",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/ash-ai/ash.git",
16
+ "directory": "packages/server"
17
+ },
18
+ "license": "MIT",
19
+ "description": "Ash agent orchestration server (Fastify REST + SSE + sandbox management)",
20
+ "dependencies": {
21
+ "@aws-sdk/client-s3": "^3.700.0",
22
+ "@fastify/multipart": "^9.0.0",
23
+ "@fastify/swagger": "^9.7.0",
24
+ "@fastify/swagger-ui": "^5.2.5",
25
+ "better-sqlite3": "^11.0.0",
26
+ "fastify": "^5.2.0",
27
+ "pg": "^8.18.0",
28
+ "@ash-ai/sandbox": "0.0.1",
29
+ "@ash-ai/shared": "0.0.1"
30
+ },
31
+ "devDependencies": {
32
+ "@types/better-sqlite3": "^7.6.0",
33
+ "@types/pg": "^8.16.0"
34
+ },
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "clean": "rm -rf dist *.tsbuildinfo",
38
+ "typecheck": "tsc --noEmit",
39
+ "start": "node dist/index.js",
40
+ "dev": "tsx src/index.ts",
41
+ "test": "vitest run",
42
+ "openapi": "tsx scripts/export-openapi.ts"
43
+ }
44
+ }