@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.
- package/LICENSE +21 -0
- package/dist/__tests__/auth.test.d.ts +2 -0
- package/dist/__tests__/auth.test.d.ts.map +1 -0
- package/dist/__tests__/auth.test.js +111 -0
- package/dist/__tests__/auth.test.js.map +1 -0
- package/dist/__tests__/backpressure.test.d.ts +2 -0
- package/dist/__tests__/backpressure.test.d.ts.map +1 -0
- package/dist/__tests__/backpressure.test.js +81 -0
- package/dist/__tests__/backpressure.test.js.map +1 -0
- package/dist/__tests__/db.test.d.ts +2 -0
- package/dist/__tests__/db.test.d.ts.map +1 -0
- package/dist/__tests__/db.test.js +111 -0
- package/dist/__tests__/db.test.js.map +1 -0
- package/dist/__tests__/files.test.d.ts +2 -0
- package/dist/__tests__/files.test.d.ts.map +1 -0
- package/dist/__tests__/files.test.js +171 -0
- package/dist/__tests__/files.test.js.map +1 -0
- package/dist/__tests__/openapi.test.d.ts +2 -0
- package/dist/__tests__/openapi.test.d.ts.map +1 -0
- package/dist/__tests__/openapi.test.js +88 -0
- package/dist/__tests__/openapi.test.js.map +1 -0
- package/dist/__tests__/pool.test.d.ts +2 -0
- package/dist/__tests__/pool.test.d.ts.map +1 -0
- package/dist/__tests__/pool.test.js +352 -0
- package/dist/__tests__/pool.test.js.map +1 -0
- package/dist/__tests__/resource-limits.test.d.ts +2 -0
- package/dist/__tests__/resource-limits.test.d.ts.map +1 -0
- package/dist/__tests__/resource-limits.test.js +119 -0
- package/dist/__tests__/resource-limits.test.js.map +1 -0
- package/dist/__tests__/sandbox-env.test.d.ts +2 -0
- package/dist/__tests__/sandbox-env.test.d.ts.map +1 -0
- package/dist/__tests__/sandbox-env.test.js +40 -0
- package/dist/__tests__/sandbox-env.test.js.map +1 -0
- package/dist/__tests__/snapshot-store.test.d.ts +2 -0
- package/dist/__tests__/snapshot-store.test.d.ts.map +1 -0
- package/dist/__tests__/snapshot-store.test.js +101 -0
- package/dist/__tests__/snapshot-store.test.js.map +1 -0
- package/dist/__tests__/state-persistence.test.d.ts +2 -0
- package/dist/__tests__/state-persistence.test.d.ts.map +1 -0
- package/dist/__tests__/state-persistence.test.js +116 -0
- package/dist/__tests__/state-persistence.test.js.map +1 -0
- package/dist/auth.d.ts +10 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +30 -0
- package/dist/auth.js.map +1 -0
- package/dist/db/index.d.ts +54 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +91 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/pg.d.ts +31 -0
- package/dist/db/pg.d.ts.map +1 -0
- package/dist/db/pg.js +214 -0
- package/dist/db/pg.js.map +1 -0
- package/dist/db/sqlite.d.ts +30 -0
- package/dist/db/sqlite.d.ts.map +1 -0
- package/dist/db/sqlite.js +195 -0
- package/dist/db/sqlite.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +122 -0
- package/dist/index.js.map +1 -0
- package/dist/routes/agents.d.ts +3 -0
- package/dist/routes/agents.d.ts.map +1 -0
- package/dist/routes/agents.js +103 -0
- package/dist/routes/agents.js.map +1 -0
- package/dist/routes/files.d.ts +4 -0
- package/dist/routes/files.d.ts.map +1 -0
- package/dist/routes/files.js +189 -0
- package/dist/routes/files.js.map +1 -0
- package/dist/routes/health.d.ts +5 -0
- package/dist/routes/health.d.ts.map +1 -0
- package/dist/routes/health.js +72 -0
- package/dist/routes/health.js.map +1 -0
- package/dist/routes/runners.d.ts +8 -0
- package/dist/routes/runners.d.ts.map +1 -0
- package/dist/routes/runners.js +33 -0
- package/dist/routes/runners.js.map +1 -0
- package/dist/routes/sessions.d.ts +10 -0
- package/dist/routes/sessions.d.ts.map +1 -0
- package/dist/routes/sessions.js +392 -0
- package/dist/routes/sessions.js.map +1 -0
- package/dist/runner/coordinator.d.ts +52 -0
- package/dist/runner/coordinator.d.ts.map +1 -0
- package/dist/runner/coordinator.js +157 -0
- package/dist/runner/coordinator.js.map +1 -0
- package/dist/runner/local-backend.d.ts +26 -0
- package/dist/runner/local-backend.d.ts.map +1 -0
- package/dist/runner/local-backend.js +79 -0
- package/dist/runner/local-backend.js.map +1 -0
- package/dist/runner/remote-backend.d.ts +32 -0
- package/dist/runner/remote-backend.d.ts.map +1 -0
- package/dist/runner/remote-backend.js +81 -0
- package/dist/runner/remote-backend.js.map +1 -0
- package/dist/runner/runner-client.d.ts +53 -0
- package/dist/runner/runner-client.d.ts.map +1 -0
- package/dist/runner/runner-client.js +157 -0
- package/dist/runner/runner-client.js.map +1 -0
- package/dist/runner/types.d.ts +37 -0
- package/dist/runner/types.d.ts.map +1 -0
- package/dist/runner/types.js +2 -0
- package/dist/runner/types.js.map +1 -0
- package/dist/schemas.d.ts +3 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +73 -0
- package/dist/schemas.js.map +1 -0
- package/package.json +44 -0
package/dist/db/pg.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import pg from 'pg';
|
|
2
|
+
export class PgDb {
|
|
3
|
+
pool;
|
|
4
|
+
constructor(databaseUrl) {
|
|
5
|
+
this.pool = new pg.Pool({ connectionString: databaseUrl });
|
|
6
|
+
}
|
|
7
|
+
async init() {
|
|
8
|
+
// Retry connection with exponential backoff (total ~31s: 1s, 2s, 4s, 8s, 16s)
|
|
9
|
+
const maxRetries = 5;
|
|
10
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
11
|
+
try {
|
|
12
|
+
await this.pool.query('SELECT 1');
|
|
13
|
+
break;
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
if (attempt === maxRetries) {
|
|
17
|
+
throw new Error(`Failed to connect to database after ${maxRetries + 1} attempts: ${err.message}`);
|
|
18
|
+
}
|
|
19
|
+
const delay = 1000 * Math.pow(2, attempt);
|
|
20
|
+
console.log(`[db] Connection attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
|
|
21
|
+
await new Promise(r => setTimeout(r, delay));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
await this.pool.query(`
|
|
25
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
26
|
+
name TEXT PRIMARY KEY,
|
|
27
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
28
|
+
path TEXT NOT NULL,
|
|
29
|
+
created_at TEXT NOT NULL DEFAULT (now()::TEXT),
|
|
30
|
+
updated_at TEXT NOT NULL DEFAULT (now()::TEXT)
|
|
31
|
+
)
|
|
32
|
+
`);
|
|
33
|
+
await this.pool.query(`
|
|
34
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
35
|
+
id TEXT PRIMARY KEY,
|
|
36
|
+
agent_name TEXT NOT NULL,
|
|
37
|
+
sandbox_id TEXT NOT NULL,
|
|
38
|
+
status TEXT NOT NULL DEFAULT 'starting',
|
|
39
|
+
runner_id TEXT,
|
|
40
|
+
created_at TEXT NOT NULL DEFAULT (now()::TEXT),
|
|
41
|
+
last_active_at TEXT NOT NULL DEFAULT (now()::TEXT),
|
|
42
|
+
FOREIGN KEY (agent_name) REFERENCES agents(name)
|
|
43
|
+
)
|
|
44
|
+
`);
|
|
45
|
+
await this.pool.query(`
|
|
46
|
+
CREATE TABLE IF NOT EXISTS sandboxes (
|
|
47
|
+
id TEXT PRIMARY KEY,
|
|
48
|
+
session_id TEXT,
|
|
49
|
+
agent_name TEXT NOT NULL,
|
|
50
|
+
state TEXT NOT NULL DEFAULT 'warming',
|
|
51
|
+
workspace_dir TEXT NOT NULL,
|
|
52
|
+
created_at TEXT NOT NULL DEFAULT (now()::TEXT),
|
|
53
|
+
last_used_at TEXT NOT NULL DEFAULT (now()::TEXT)
|
|
54
|
+
)
|
|
55
|
+
`);
|
|
56
|
+
// Indexes (CREATE INDEX IF NOT EXISTS is supported in Postgres)
|
|
57
|
+
await this.pool.query('CREATE INDEX IF NOT EXISTS idx_sandboxes_state ON sandboxes(state)');
|
|
58
|
+
await this.pool.query('CREATE INDEX IF NOT EXISTS idx_sandboxes_session ON sandboxes(session_id)');
|
|
59
|
+
await this.pool.query('CREATE INDEX IF NOT EXISTS idx_sandboxes_last_used ON sandboxes(last_used_at)');
|
|
60
|
+
}
|
|
61
|
+
// -- Agents -----------------------------------------------------------------
|
|
62
|
+
async upsertAgent(name, path) {
|
|
63
|
+
const existing = await this.pool.query('SELECT version FROM agents WHERE name = $1', [name]);
|
|
64
|
+
const version = existing.rows.length > 0 ? existing.rows[0].version + 1 : 1;
|
|
65
|
+
const now = new Date().toISOString();
|
|
66
|
+
await this.pool.query(`
|
|
67
|
+
INSERT INTO agents (name, version, path, created_at, updated_at)
|
|
68
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
69
|
+
ON CONFLICT(name) DO UPDATE SET version = $2, path = $3, updated_at = $5
|
|
70
|
+
`, [name, version, path, now, now]);
|
|
71
|
+
return { name, version, path, createdAt: now, updatedAt: now };
|
|
72
|
+
}
|
|
73
|
+
async getAgent(name) {
|
|
74
|
+
const result = await this.pool.query('SELECT * FROM agents WHERE name = $1', [name]);
|
|
75
|
+
const row = result.rows[0];
|
|
76
|
+
if (!row)
|
|
77
|
+
return null;
|
|
78
|
+
return { name: row.name, version: row.version, path: row.path, createdAt: row.created_at, updatedAt: row.updated_at };
|
|
79
|
+
}
|
|
80
|
+
async listAgents() {
|
|
81
|
+
const result = await this.pool.query('SELECT * FROM agents ORDER BY name');
|
|
82
|
+
return result.rows.map((r) => ({ name: r.name, version: r.version, path: r.path, createdAt: r.created_at, updatedAt: r.updated_at }));
|
|
83
|
+
}
|
|
84
|
+
async deleteAgent(name) {
|
|
85
|
+
await this.pool.query('DELETE FROM sessions WHERE agent_name = $1', [name]);
|
|
86
|
+
const result = await this.pool.query('DELETE FROM agents WHERE name = $1', [name]);
|
|
87
|
+
return (result.rowCount ?? 0) > 0;
|
|
88
|
+
}
|
|
89
|
+
// -- Sessions ---------------------------------------------------------------
|
|
90
|
+
async insertSession(id, agentName, sandboxId) {
|
|
91
|
+
const now = new Date().toISOString();
|
|
92
|
+
await this.pool.query(`
|
|
93
|
+
INSERT INTO sessions (id, agent_name, sandbox_id, status, created_at, last_active_at)
|
|
94
|
+
VALUES ($1, $2, $3, 'starting', $4, $5)
|
|
95
|
+
`, [id, agentName, sandboxId, now, now]);
|
|
96
|
+
return { id, agentName, sandboxId, status: 'starting', createdAt: now, lastActiveAt: now };
|
|
97
|
+
}
|
|
98
|
+
async updateSessionStatus(id, status) {
|
|
99
|
+
const now = new Date().toISOString();
|
|
100
|
+
await this.pool.query('UPDATE sessions SET status = $1, last_active_at = $2 WHERE id = $3', [status, now, id]);
|
|
101
|
+
}
|
|
102
|
+
async updateSessionSandbox(id, sandboxId) {
|
|
103
|
+
const now = new Date().toISOString();
|
|
104
|
+
await this.pool.query('UPDATE sessions SET sandbox_id = $1, last_active_at = $2 WHERE id = $3', [sandboxId, now, id]);
|
|
105
|
+
}
|
|
106
|
+
async updateSessionRunner(id, runnerId) {
|
|
107
|
+
const now = new Date().toISOString();
|
|
108
|
+
await this.pool.query('UPDATE sessions SET runner_id = $1, last_active_at = $2 WHERE id = $3', [runnerId, now, id]);
|
|
109
|
+
}
|
|
110
|
+
async getSession(id) {
|
|
111
|
+
const result = await this.pool.query('SELECT * FROM sessions WHERE id = $1', [id]);
|
|
112
|
+
const row = result.rows[0];
|
|
113
|
+
if (!row)
|
|
114
|
+
return null;
|
|
115
|
+
return { id: row.id, agentName: row.agent_name, sandboxId: row.sandbox_id, status: row.status, runnerId: row.runner_id ?? null, createdAt: row.created_at, lastActiveAt: row.last_active_at };
|
|
116
|
+
}
|
|
117
|
+
async listSessions(agent) {
|
|
118
|
+
const result = agent
|
|
119
|
+
? await this.pool.query('SELECT * FROM sessions WHERE agent_name = $1 ORDER BY created_at DESC', [agent])
|
|
120
|
+
: await this.pool.query('SELECT * FROM sessions ORDER BY created_at DESC');
|
|
121
|
+
return result.rows.map((r) => ({ id: r.id, agentName: r.agent_name, sandboxId: r.sandbox_id, status: r.status, runnerId: r.runner_id ?? null, createdAt: r.created_at, lastActiveAt: r.last_active_at }));
|
|
122
|
+
}
|
|
123
|
+
async listSessionsByRunner(runnerId) {
|
|
124
|
+
const result = await this.pool.query('SELECT * FROM sessions WHERE runner_id = $1 ORDER BY created_at DESC', [runnerId]);
|
|
125
|
+
return result.rows.map((r) => ({ id: r.id, agentName: r.agent_name, sandboxId: r.sandbox_id, status: r.status, runnerId: r.runner_id ?? null, createdAt: r.created_at, lastActiveAt: r.last_active_at }));
|
|
126
|
+
}
|
|
127
|
+
async touchSession(id) {
|
|
128
|
+
const now = new Date().toISOString();
|
|
129
|
+
await this.pool.query('UPDATE sessions SET last_active_at = $1 WHERE id = $2', [now, id]);
|
|
130
|
+
}
|
|
131
|
+
// -- Sandboxes --------------------------------------------------------------
|
|
132
|
+
async insertSandbox(id, agentName, workspaceDir, sessionId) {
|
|
133
|
+
const now = new Date().toISOString();
|
|
134
|
+
await this.pool.query(`
|
|
135
|
+
INSERT INTO sandboxes (id, agent_name, workspace_dir, session_id, state, created_at, last_used_at)
|
|
136
|
+
VALUES ($1, $2, $3, $4, 'warming', $5, $6)
|
|
137
|
+
`, [id, agentName, workspaceDir, sessionId ?? null, now, now]);
|
|
138
|
+
}
|
|
139
|
+
async updateSandboxState(id, state) {
|
|
140
|
+
await this.pool.query('UPDATE sandboxes SET state = $1 WHERE id = $2', [state, id]);
|
|
141
|
+
}
|
|
142
|
+
async updateSandboxSession(id, sessionId) {
|
|
143
|
+
await this.pool.query('UPDATE sandboxes SET session_id = $1 WHERE id = $2', [sessionId, id]);
|
|
144
|
+
}
|
|
145
|
+
async touchSandbox(id) {
|
|
146
|
+
const now = new Date().toISOString();
|
|
147
|
+
await this.pool.query('UPDATE sandboxes SET last_used_at = $1 WHERE id = $2', [now, id]);
|
|
148
|
+
}
|
|
149
|
+
async getSandbox(id) {
|
|
150
|
+
const result = await this.pool.query('SELECT * FROM sandboxes WHERE id = $1', [id]);
|
|
151
|
+
const row = result.rows[0];
|
|
152
|
+
if (!row)
|
|
153
|
+
return null;
|
|
154
|
+
return {
|
|
155
|
+
id: row.id,
|
|
156
|
+
sessionId: row.session_id,
|
|
157
|
+
agentName: row.agent_name,
|
|
158
|
+
state: row.state,
|
|
159
|
+
workspaceDir: row.workspace_dir,
|
|
160
|
+
createdAt: row.created_at,
|
|
161
|
+
lastUsedAt: row.last_used_at,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
async countSandboxes() {
|
|
165
|
+
const result = await this.pool.query('SELECT COUNT(*) as count FROM sandboxes');
|
|
166
|
+
return parseInt(result.rows[0].count, 10);
|
|
167
|
+
}
|
|
168
|
+
async getBestEvictionCandidate() {
|
|
169
|
+
const result = await this.pool.query(`
|
|
170
|
+
SELECT * FROM sandboxes
|
|
171
|
+
WHERE state IN ('cold', 'warm', 'waiting')
|
|
172
|
+
ORDER BY
|
|
173
|
+
CASE state WHEN 'cold' THEN 0 WHEN 'warm' THEN 1 WHEN 'waiting' THEN 2 END,
|
|
174
|
+
last_used_at ASC
|
|
175
|
+
LIMIT 1
|
|
176
|
+
`);
|
|
177
|
+
const row = result.rows[0];
|
|
178
|
+
if (!row)
|
|
179
|
+
return null;
|
|
180
|
+
return {
|
|
181
|
+
id: row.id,
|
|
182
|
+
sessionId: row.session_id,
|
|
183
|
+
agentName: row.agent_name,
|
|
184
|
+
state: row.state,
|
|
185
|
+
workspaceDir: row.workspace_dir,
|
|
186
|
+
createdAt: row.created_at,
|
|
187
|
+
lastUsedAt: row.last_used_at,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
async getIdleSandboxes(olderThan) {
|
|
191
|
+
const result = await this.pool.query("SELECT * FROM sandboxes WHERE state = 'waiting' AND last_used_at < $1 ORDER BY last_used_at ASC", [olderThan]);
|
|
192
|
+
return result.rows.map((row) => ({
|
|
193
|
+
id: row.id,
|
|
194
|
+
sessionId: row.session_id,
|
|
195
|
+
agentName: row.agent_name,
|
|
196
|
+
state: row.state,
|
|
197
|
+
workspaceDir: row.workspace_dir,
|
|
198
|
+
createdAt: row.created_at,
|
|
199
|
+
lastUsedAt: row.last_used_at,
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
async deleteSandbox(id) {
|
|
203
|
+
await this.pool.query('DELETE FROM sandboxes WHERE id = $1', [id]);
|
|
204
|
+
}
|
|
205
|
+
async markAllSandboxesCold() {
|
|
206
|
+
const result = await this.pool.query("UPDATE sandboxes SET state = 'cold' WHERE state != 'cold'");
|
|
207
|
+
return result.rowCount ?? 0;
|
|
208
|
+
}
|
|
209
|
+
// -- Lifecycle --------------------------------------------------------------
|
|
210
|
+
async close() {
|
|
211
|
+
await this.pool.end();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=pg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg.js","sourceRoot":"","sources":["../../src/db/pg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Agent, Session, SessionStatus, SandboxRecord, SandboxState } from '@ash-ai/shared';
|
|
2
|
+
import type { Db } from './index.js';
|
|
3
|
+
export declare class SqliteDb implements Db {
|
|
4
|
+
private db;
|
|
5
|
+
constructor(dataDir: string);
|
|
6
|
+
upsertAgent(name: string, path: string): Promise<Agent>;
|
|
7
|
+
getAgent(name: string): Promise<Agent | null>;
|
|
8
|
+
listAgents(): Promise<Agent[]>;
|
|
9
|
+
deleteAgent(name: string): Promise<boolean>;
|
|
10
|
+
insertSession(id: string, agentName: string, sandboxId: string): Promise<Session>;
|
|
11
|
+
updateSessionStatus(id: string, status: SessionStatus): Promise<void>;
|
|
12
|
+
updateSessionSandbox(id: string, sandboxId: string): Promise<void>;
|
|
13
|
+
updateSessionRunner(id: string, runnerId: string | null): Promise<void>;
|
|
14
|
+
getSession(id: string): Promise<Session | null>;
|
|
15
|
+
listSessions(agent?: string): Promise<Session[]>;
|
|
16
|
+
listSessionsByRunner(runnerId: string): Promise<Session[]>;
|
|
17
|
+
touchSession(id: string): Promise<void>;
|
|
18
|
+
insertSandbox(id: string, agentName: string, workspaceDir: string, sessionId?: string): Promise<void>;
|
|
19
|
+
updateSandboxState(id: string, state: SandboxState): Promise<void>;
|
|
20
|
+
updateSandboxSession(id: string, sessionId: string | null): Promise<void>;
|
|
21
|
+
touchSandbox(id: string): Promise<void>;
|
|
22
|
+
getSandbox(id: string): Promise<SandboxRecord | null>;
|
|
23
|
+
countSandboxes(): Promise<number>;
|
|
24
|
+
getBestEvictionCandidate(): Promise<SandboxRecord | null>;
|
|
25
|
+
getIdleSandboxes(olderThan: string): Promise<SandboxRecord[]>;
|
|
26
|
+
deleteSandbox(id: string): Promise<void>;
|
|
27
|
+
markAllSandboxesCold(): Promise<number>;
|
|
28
|
+
close(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=sqlite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/db/sqlite.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACjG,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAErC,qBAAa,QAAS,YAAW,EAAE;IACjC,OAAO,CAAC,EAAE,CAAoB;gBAElB,OAAO,EAAE,MAAM;IA4CrB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAcvD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAM7C,UAAU,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAK9B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ3C,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUjF,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrE,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlE,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAM/C,YAAY,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAOhD,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAK1D,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvC,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrG,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlE,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzE,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAcrD,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAKjC,wBAAwB,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAqBzD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAe7D,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC,oBAAoB,IAAI,OAAO,CAAC,MAAM,CAAC;IASvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { mkdirSync } from 'node:fs';
|
|
4
|
+
export class SqliteDb {
|
|
5
|
+
db;
|
|
6
|
+
constructor(dataDir) {
|
|
7
|
+
mkdirSync(dataDir, { recursive: true });
|
|
8
|
+
this.db = new Database(join(dataDir, 'ash.db'));
|
|
9
|
+
this.db.pragma('journal_mode = WAL');
|
|
10
|
+
this.db.pragma('foreign_keys = ON');
|
|
11
|
+
this.db.exec(`
|
|
12
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
13
|
+
name TEXT PRIMARY KEY,
|
|
14
|
+
version INTEGER NOT NULL DEFAULT 1,
|
|
15
|
+
path TEXT NOT NULL,
|
|
16
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
17
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
21
|
+
id TEXT PRIMARY KEY,
|
|
22
|
+
agent_name TEXT NOT NULL,
|
|
23
|
+
sandbox_id TEXT NOT NULL,
|
|
24
|
+
status TEXT NOT NULL DEFAULT 'starting',
|
|
25
|
+
runner_id TEXT,
|
|
26
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
27
|
+
last_active_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
28
|
+
FOREIGN KEY (agent_name) REFERENCES agents(name)
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
CREATE TABLE IF NOT EXISTS sandboxes (
|
|
32
|
+
id TEXT PRIMARY KEY,
|
|
33
|
+
session_id TEXT,
|
|
34
|
+
agent_name TEXT NOT NULL,
|
|
35
|
+
state TEXT NOT NULL DEFAULT 'warming',
|
|
36
|
+
workspace_dir TEXT NOT NULL,
|
|
37
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
38
|
+
last_used_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
CREATE INDEX IF NOT EXISTS idx_sandboxes_state ON sandboxes(state);
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_sandboxes_session ON sandboxes(session_id);
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_sandboxes_last_used ON sandboxes(last_used_at);
|
|
44
|
+
`);
|
|
45
|
+
}
|
|
46
|
+
// -- Agents -----------------------------------------------------------------
|
|
47
|
+
async upsertAgent(name, path) {
|
|
48
|
+
const existing = this.db.prepare('SELECT version FROM agents WHERE name = ?').get(name);
|
|
49
|
+
const version = existing ? existing.version + 1 : 1;
|
|
50
|
+
const now = new Date().toISOString();
|
|
51
|
+
this.db.prepare(`
|
|
52
|
+
INSERT INTO agents (name, version, path, created_at, updated_at)
|
|
53
|
+
VALUES (?, ?, ?, ?, ?)
|
|
54
|
+
ON CONFLICT(name) DO UPDATE SET version = ?, path = ?, updated_at = ?
|
|
55
|
+
`).run(name, version, path, now, now, version, path, now);
|
|
56
|
+
return { name, version, path, createdAt: now, updatedAt: now };
|
|
57
|
+
}
|
|
58
|
+
async getAgent(name) {
|
|
59
|
+
const row = this.db.prepare('SELECT * FROM agents WHERE name = ?').get(name);
|
|
60
|
+
if (!row)
|
|
61
|
+
return null;
|
|
62
|
+
return { name: row.name, version: row.version, path: row.path, createdAt: row.created_at, updatedAt: row.updated_at };
|
|
63
|
+
}
|
|
64
|
+
async listAgents() {
|
|
65
|
+
const rows = this.db.prepare('SELECT * FROM agents ORDER BY name').all();
|
|
66
|
+
return rows.map((r) => ({ name: r.name, version: r.version, path: r.path, createdAt: r.created_at, updatedAt: r.updated_at }));
|
|
67
|
+
}
|
|
68
|
+
async deleteAgent(name) {
|
|
69
|
+
this.db.prepare('DELETE FROM sessions WHERE agent_name = ?').run(name);
|
|
70
|
+
const result = this.db.prepare('DELETE FROM agents WHERE name = ?').run(name);
|
|
71
|
+
return result.changes > 0;
|
|
72
|
+
}
|
|
73
|
+
// -- Sessions ---------------------------------------------------------------
|
|
74
|
+
async insertSession(id, agentName, sandboxId) {
|
|
75
|
+
const now = new Date().toISOString();
|
|
76
|
+
this.db.prepare(`
|
|
77
|
+
INSERT INTO sessions (id, agent_name, sandbox_id, status, created_at, last_active_at)
|
|
78
|
+
VALUES (?, ?, ?, 'starting', ?, ?)
|
|
79
|
+
`).run(id, agentName, sandboxId, now, now);
|
|
80
|
+
return { id, agentName, sandboxId, status: 'starting', createdAt: now, lastActiveAt: now };
|
|
81
|
+
}
|
|
82
|
+
async updateSessionStatus(id, status) {
|
|
83
|
+
const now = new Date().toISOString();
|
|
84
|
+
this.db.prepare('UPDATE sessions SET status = ?, last_active_at = ? WHERE id = ?').run(status, now, id);
|
|
85
|
+
}
|
|
86
|
+
async updateSessionSandbox(id, sandboxId) {
|
|
87
|
+
const now = new Date().toISOString();
|
|
88
|
+
this.db.prepare('UPDATE sessions SET sandbox_id = ?, last_active_at = ? WHERE id = ?').run(sandboxId, now, id);
|
|
89
|
+
}
|
|
90
|
+
async updateSessionRunner(id, runnerId) {
|
|
91
|
+
const now = new Date().toISOString();
|
|
92
|
+
this.db.prepare('UPDATE sessions SET runner_id = ?, last_active_at = ? WHERE id = ?').run(runnerId, now, id);
|
|
93
|
+
}
|
|
94
|
+
async getSession(id) {
|
|
95
|
+
const row = this.db.prepare('SELECT * FROM sessions WHERE id = ?').get(id);
|
|
96
|
+
if (!row)
|
|
97
|
+
return null;
|
|
98
|
+
return { id: row.id, agentName: row.agent_name, sandboxId: row.sandbox_id, status: row.status, runnerId: row.runner_id ?? null, createdAt: row.created_at, lastActiveAt: row.last_active_at };
|
|
99
|
+
}
|
|
100
|
+
async listSessions(agent) {
|
|
101
|
+
const rows = agent
|
|
102
|
+
? this.db.prepare('SELECT * FROM sessions WHERE agent_name = ? ORDER BY created_at DESC').all(agent)
|
|
103
|
+
: this.db.prepare('SELECT * FROM sessions ORDER BY created_at DESC').all();
|
|
104
|
+
return rows.map((r) => ({ id: r.id, agentName: r.agent_name, sandboxId: r.sandbox_id, status: r.status, runnerId: r.runner_id ?? null, createdAt: r.created_at, lastActiveAt: r.last_active_at }));
|
|
105
|
+
}
|
|
106
|
+
async listSessionsByRunner(runnerId) {
|
|
107
|
+
const rows = this.db.prepare('SELECT * FROM sessions WHERE runner_id = ? ORDER BY created_at DESC').all(runnerId);
|
|
108
|
+
return rows.map((r) => ({ id: r.id, agentName: r.agent_name, sandboxId: r.sandbox_id, status: r.status, runnerId: r.runner_id ?? null, createdAt: r.created_at, lastActiveAt: r.last_active_at }));
|
|
109
|
+
}
|
|
110
|
+
async touchSession(id) {
|
|
111
|
+
const now = new Date().toISOString();
|
|
112
|
+
this.db.prepare('UPDATE sessions SET last_active_at = ? WHERE id = ?').run(now, id);
|
|
113
|
+
}
|
|
114
|
+
// -- Sandboxes --------------------------------------------------------------
|
|
115
|
+
async insertSandbox(id, agentName, workspaceDir, sessionId) {
|
|
116
|
+
const now = new Date().toISOString();
|
|
117
|
+
this.db.prepare(`
|
|
118
|
+
INSERT INTO sandboxes (id, agent_name, workspace_dir, session_id, state, created_at, last_used_at)
|
|
119
|
+
VALUES (?, ?, ?, ?, 'warming', ?, ?)
|
|
120
|
+
`).run(id, agentName, workspaceDir, sessionId ?? null, now, now);
|
|
121
|
+
}
|
|
122
|
+
async updateSandboxState(id, state) {
|
|
123
|
+
this.db.prepare('UPDATE sandboxes SET state = ? WHERE id = ?').run(state, id);
|
|
124
|
+
}
|
|
125
|
+
async updateSandboxSession(id, sessionId) {
|
|
126
|
+
this.db.prepare('UPDATE sandboxes SET session_id = ? WHERE id = ?').run(sessionId, id);
|
|
127
|
+
}
|
|
128
|
+
async touchSandbox(id) {
|
|
129
|
+
const now = new Date().toISOString();
|
|
130
|
+
this.db.prepare('UPDATE sandboxes SET last_used_at = ? WHERE id = ?').run(now, id);
|
|
131
|
+
}
|
|
132
|
+
async getSandbox(id) {
|
|
133
|
+
const row = this.db.prepare('SELECT * FROM sandboxes WHERE id = ?').get(id);
|
|
134
|
+
if (!row)
|
|
135
|
+
return null;
|
|
136
|
+
return {
|
|
137
|
+
id: row.id,
|
|
138
|
+
sessionId: row.session_id,
|
|
139
|
+
agentName: row.agent_name,
|
|
140
|
+
state: row.state,
|
|
141
|
+
workspaceDir: row.workspace_dir,
|
|
142
|
+
createdAt: row.created_at,
|
|
143
|
+
lastUsedAt: row.last_used_at,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
async countSandboxes() {
|
|
147
|
+
const row = this.db.prepare('SELECT COUNT(*) as count FROM sandboxes').get();
|
|
148
|
+
return row.count;
|
|
149
|
+
}
|
|
150
|
+
async getBestEvictionCandidate() {
|
|
151
|
+
const row = this.db.prepare(`
|
|
152
|
+
SELECT * FROM sandboxes
|
|
153
|
+
WHERE state IN ('cold', 'warm', 'waiting')
|
|
154
|
+
ORDER BY
|
|
155
|
+
CASE state WHEN 'cold' THEN 0 WHEN 'warm' THEN 1 WHEN 'waiting' THEN 2 END,
|
|
156
|
+
last_used_at ASC
|
|
157
|
+
LIMIT 1
|
|
158
|
+
`).get();
|
|
159
|
+
if (!row)
|
|
160
|
+
return null;
|
|
161
|
+
return {
|
|
162
|
+
id: row.id,
|
|
163
|
+
sessionId: row.session_id,
|
|
164
|
+
agentName: row.agent_name,
|
|
165
|
+
state: row.state,
|
|
166
|
+
workspaceDir: row.workspace_dir,
|
|
167
|
+
createdAt: row.created_at,
|
|
168
|
+
lastUsedAt: row.last_used_at,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async getIdleSandboxes(olderThan) {
|
|
172
|
+
const rows = this.db.prepare("SELECT * FROM sandboxes WHERE state = 'waiting' AND last_used_at < ? ORDER BY last_used_at ASC").all(olderThan);
|
|
173
|
+
return rows.map((row) => ({
|
|
174
|
+
id: row.id,
|
|
175
|
+
sessionId: row.session_id,
|
|
176
|
+
agentName: row.agent_name,
|
|
177
|
+
state: row.state,
|
|
178
|
+
workspaceDir: row.workspace_dir,
|
|
179
|
+
createdAt: row.created_at,
|
|
180
|
+
lastUsedAt: row.last_used_at,
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
async deleteSandbox(id) {
|
|
184
|
+
this.db.prepare('DELETE FROM sandboxes WHERE id = ?').run(id);
|
|
185
|
+
}
|
|
186
|
+
async markAllSandboxesCold() {
|
|
187
|
+
const result = this.db.prepare("UPDATE sandboxes SET state = 'cold' WHERE state != 'cold'").run();
|
|
188
|
+
return result.changes;
|
|
189
|
+
}
|
|
190
|
+
// -- Lifecycle --------------------------------------------------------------
|
|
191
|
+
async close() {
|
|
192
|
+
this.db.close();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/db/sqlite.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import Fastify from 'fastify';
|
|
2
|
+
import swagger from '@fastify/swagger';
|
|
3
|
+
import swaggerUi from '@fastify/swagger-ui';
|
|
4
|
+
import { join, resolve, dirname } from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { DEFAULT_PORT, DEFAULT_HOST, DEFAULT_DATA_DIR, DEFAULT_MAX_SANDBOXES, DEFAULT_IDLE_TIMEOUT_MS } from '@ash-ai/shared';
|
|
7
|
+
import { initDb, closeDb, updateSessionStatus } from './db/index.js';
|
|
8
|
+
import { SandboxManager, SandboxPool, persistSessionState, syncStateToCloud } from '@ash-ai/sandbox';
|
|
9
|
+
import { LocalRunnerBackend } from './runner/local-backend.js';
|
|
10
|
+
import { RunnerCoordinator } from './runner/coordinator.js';
|
|
11
|
+
import { registerSchemas } from './schemas.js';
|
|
12
|
+
import { registerAuth } from './auth.js';
|
|
13
|
+
import { agentRoutes } from './routes/agents.js';
|
|
14
|
+
import { sessionRoutes } from './routes/sessions.js';
|
|
15
|
+
import { healthRoutes } from './routes/health.js';
|
|
16
|
+
import { runnerRoutes } from './routes/runners.js';
|
|
17
|
+
import { fileRoutes } from './routes/files.js';
|
|
18
|
+
// Config from env
|
|
19
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const monorepoRoot = resolve(__dirname, '..', '..', '..');
|
|
21
|
+
const port = parseInt(process.env.ASH_PORT || String(DEFAULT_PORT), 10);
|
|
22
|
+
const host = process.env.ASH_HOST || DEFAULT_HOST;
|
|
23
|
+
const dataDir = resolve(process.env.ASH_DATA_DIR || DEFAULT_DATA_DIR);
|
|
24
|
+
const bridgeEntry = process.env.ASH_BRIDGE_ENTRY
|
|
25
|
+
? resolve(process.env.ASH_BRIDGE_ENTRY)
|
|
26
|
+
: join(monorepoRoot, 'packages', 'bridge', 'dist', 'index.js');
|
|
27
|
+
// Mode: 'standalone' (default) or 'coordinator'
|
|
28
|
+
const mode = (process.env.ASH_MODE || 'standalone');
|
|
29
|
+
// Initialize DB
|
|
30
|
+
const databaseUrl = process.env.ASH_DATABASE_URL;
|
|
31
|
+
const db = await initDb({ dataDir, databaseUrl });
|
|
32
|
+
// Build the backend and coordinator based on mode
|
|
33
|
+
let pool = null;
|
|
34
|
+
let coordinator;
|
|
35
|
+
if (mode === 'standalone') {
|
|
36
|
+
// Standalone: server creates local SandboxPool + LocalRunnerBackend
|
|
37
|
+
const sandboxManager = new SandboxManager({
|
|
38
|
+
sandboxesDir: join(dataDir, 'sandboxes'),
|
|
39
|
+
bridgeEntry,
|
|
40
|
+
});
|
|
41
|
+
const maxCapacity = parseInt(process.env.ASH_MAX_SANDBOXES || String(DEFAULT_MAX_SANDBOXES), 10);
|
|
42
|
+
const idleTimeoutMs = parseInt(process.env.ASH_IDLE_TIMEOUT_MS || String(DEFAULT_IDLE_TIMEOUT_MS), 10);
|
|
43
|
+
pool = new SandboxPool({
|
|
44
|
+
manager: sandboxManager,
|
|
45
|
+
db,
|
|
46
|
+
dataDir,
|
|
47
|
+
maxCapacity,
|
|
48
|
+
idleTimeoutMs,
|
|
49
|
+
onBeforeEvict: async (entry) => {
|
|
50
|
+
if (entry.sessionId) {
|
|
51
|
+
persistSessionState(dataDir, entry.sessionId, entry.sandbox.workspaceDir, entry.agentName);
|
|
52
|
+
syncStateToCloud(dataDir, entry.sessionId).catch((err) => console.error(`[server] Cloud sync failed for ${entry.sessionId}:`, err));
|
|
53
|
+
await updateSessionStatus(entry.sessionId, 'paused');
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
await pool.init();
|
|
58
|
+
pool.startIdleSweep();
|
|
59
|
+
const localBackend = new LocalRunnerBackend(pool, dataDir);
|
|
60
|
+
coordinator = new RunnerCoordinator({ localBackend });
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// Coordinator mode: pure control plane, no local sandbox pool
|
|
64
|
+
// Runners must register and provide sandbox capacity
|
|
65
|
+
coordinator = new RunnerCoordinator({});
|
|
66
|
+
}
|
|
67
|
+
const app = Fastify({ logger: true });
|
|
68
|
+
// OpenAPI / Swagger
|
|
69
|
+
await app.register(swagger, {
|
|
70
|
+
openapi: {
|
|
71
|
+
info: {
|
|
72
|
+
title: 'Ash API',
|
|
73
|
+
description: 'REST API for deploying and orchestrating hosted AI agents',
|
|
74
|
+
version: '0.1.0',
|
|
75
|
+
},
|
|
76
|
+
servers: [{ url: `http://localhost:${port}` }],
|
|
77
|
+
tags: [
|
|
78
|
+
{ name: 'health', description: 'Server health' },
|
|
79
|
+
{ name: 'agents', description: 'Agent deployment and management' },
|
|
80
|
+
{ name: 'sessions', description: 'Session lifecycle and messaging' },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
await app.register(swaggerUi, { routePrefix: '/docs' });
|
|
85
|
+
registerSchemas(app);
|
|
86
|
+
// Auth (enabled when ASH_API_KEY is set, disabled otherwise)
|
|
87
|
+
registerAuth(app, process.env.ASH_API_KEY);
|
|
88
|
+
// Routes
|
|
89
|
+
agentRoutes(app, dataDir);
|
|
90
|
+
sessionRoutes(app, coordinator, dataDir);
|
|
91
|
+
fileRoutes(app, coordinator, dataDir);
|
|
92
|
+
healthRoutes(app, coordinator, pool);
|
|
93
|
+
runnerRoutes(app, coordinator);
|
|
94
|
+
coordinator.startLivenessSweep();
|
|
95
|
+
// Graceful shutdown
|
|
96
|
+
async function shutdown() {
|
|
97
|
+
app.log.info('Shutting down...');
|
|
98
|
+
coordinator.stopLivenessSweep();
|
|
99
|
+
if (pool) {
|
|
100
|
+
pool.stopIdleSweep();
|
|
101
|
+
await pool.destroyAll();
|
|
102
|
+
}
|
|
103
|
+
await closeDb();
|
|
104
|
+
await app.close();
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
process.on('SIGTERM', shutdown);
|
|
108
|
+
process.on('SIGINT', shutdown);
|
|
109
|
+
// Start
|
|
110
|
+
try {
|
|
111
|
+
await app.listen({ port, host });
|
|
112
|
+
app.log.info(`Ash server listening on ${host}:${port} (mode: ${mode})`);
|
|
113
|
+
app.log.info(`Data directory: ${dataDir}`);
|
|
114
|
+
if (mode === 'standalone') {
|
|
115
|
+
app.log.info(`Bridge entry: ${bridgeEntry}`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
app.log.error(err);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/routes/agents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAW/C,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAmGvE"}
|