@vm0/runner 3.11.2 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1026 -607
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -44,7 +44,7 @@ var runnerPaths = {
|
|
|
44
44
|
/** Runner status file */
|
|
45
45
|
statusFile: (baseDir) => path.join(baseDir, "status.json"),
|
|
46
46
|
/** Snapshot generation work directory */
|
|
47
|
-
snapshotWorkDir: (baseDir) => path.join(baseDir, "workspaces", "
|
|
47
|
+
snapshotWorkDir: (baseDir) => path.join(baseDir, "workspaces", "snapshot"),
|
|
48
48
|
/** Check if a directory name is a VM workspace */
|
|
49
49
|
isVmWorkspace: (dirname) => dirname.startsWith(VM_WORKSPACE_PREFIX),
|
|
50
50
|
/** Extract vmId from workspace directory name */
|
|
@@ -62,6 +62,14 @@ var vmPaths = {
|
|
|
62
62
|
/** Overlay filesystem for VM writes */
|
|
63
63
|
overlay: (workDir) => path.join(workDir, "overlay.ext4")
|
|
64
64
|
};
|
|
65
|
+
var snapshotOutputPaths = {
|
|
66
|
+
/** VM state snapshot */
|
|
67
|
+
snapshot: (outputDir) => path.join(outputDir, "snapshot.bin"),
|
|
68
|
+
/** VM memory snapshot */
|
|
69
|
+
memory: (outputDir) => path.join(outputDir, "memory.bin"),
|
|
70
|
+
/** Golden overlay with guest state */
|
|
71
|
+
overlay: (outputDir) => path.join(outputDir, "overlay.ext4")
|
|
72
|
+
};
|
|
65
73
|
var tempPaths = {
|
|
66
74
|
/** Default proxy CA directory */
|
|
67
75
|
proxyDir: `${VM0_TMP_PREFIX}-proxy`,
|
|
@@ -102,7 +110,12 @@ var runnerConfigSchema = z.object({
|
|
|
102
110
|
firecracker: z.object({
|
|
103
111
|
binary: z.string().min(1, "Firecracker binary path is required"),
|
|
104
112
|
kernel: z.string().min(1, "Kernel path is required"),
|
|
105
|
-
rootfs: z.string().min(1, "Rootfs path is required")
|
|
113
|
+
rootfs: z.string().min(1, "Rootfs path is required"),
|
|
114
|
+
snapshot: z.object({
|
|
115
|
+
snapshot: z.string().min(1, "Snapshot state file path is required"),
|
|
116
|
+
memory: z.string().min(1, "Snapshot memory file path is required"),
|
|
117
|
+
overlay: z.string().min(1, "Snapshot overlay file path is required")
|
|
118
|
+
}).optional()
|
|
106
119
|
}),
|
|
107
120
|
proxy: z.object({
|
|
108
121
|
// TODO: Allow 0 to auto-find available port
|
|
@@ -131,7 +144,12 @@ var debugConfigSchema = z.object({
|
|
|
131
144
|
firecracker: z.object({
|
|
132
145
|
binary: z.string().min(1, "Firecracker binary path is required"),
|
|
133
146
|
kernel: z.string().min(1, "Kernel path is required"),
|
|
134
|
-
rootfs: z.string().min(1, "Rootfs path is required")
|
|
147
|
+
rootfs: z.string().min(1, "Rootfs path is required"),
|
|
148
|
+
snapshot: z.object({
|
|
149
|
+
snapshot: z.string().min(1, "Snapshot state file path is required"),
|
|
150
|
+
memory: z.string().min(1, "Snapshot memory file path is required"),
|
|
151
|
+
overlay: z.string().min(1, "Snapshot overlay file path is required")
|
|
152
|
+
}).optional()
|
|
135
153
|
}),
|
|
136
154
|
proxy: z.object({
|
|
137
155
|
port: z.number().int().min(1024).max(65535).default(PROXY_DEFAULTS.port),
|
|
@@ -172,6 +190,13 @@ function validateFirecrackerPaths(config) {
|
|
|
172
190
|
{ path: config.kernel, name: "Kernel" },
|
|
173
191
|
{ path: config.rootfs, name: "Rootfs" }
|
|
174
192
|
];
|
|
193
|
+
if (config.snapshot) {
|
|
194
|
+
checks.push(
|
|
195
|
+
{ path: config.snapshot.snapshot, name: "Snapshot state file" },
|
|
196
|
+
{ path: config.snapshot.memory, name: "Snapshot memory file" },
|
|
197
|
+
{ path: config.snapshot.overlay, name: "Snapshot overlay file" }
|
|
198
|
+
);
|
|
199
|
+
}
|
|
175
200
|
for (const check of checks) {
|
|
176
201
|
if (!fs.existsSync(check.path)) {
|
|
177
202
|
throw new Error(`${check.name} not found: ${check.path}`);
|
|
@@ -337,10 +362,13 @@ async function subscribeToJobs(server, group, onJob, onConnectionChange) {
|
|
|
337
362
|
|
|
338
363
|
// src/lib/executor.ts
|
|
339
364
|
import fs9 from "fs";
|
|
365
|
+
import path6 from "path";
|
|
340
366
|
|
|
341
367
|
// src/lib/firecracker/vm.ts
|
|
342
368
|
import { spawn } from "child_process";
|
|
343
369
|
import fs4 from "fs";
|
|
370
|
+
import os from "os";
|
|
371
|
+
import path4 from "path";
|
|
344
372
|
import readline from "readline";
|
|
345
373
|
|
|
346
374
|
// src/lib/firecracker/netns-pool.ts
|
|
@@ -379,8 +407,8 @@ var DEFAULT_OPTIONS = {
|
|
|
379
407
|
maxTimeout: 1e3
|
|
380
408
|
}
|
|
381
409
|
};
|
|
382
|
-
async function withFileLock(
|
|
383
|
-
const release = await lockfile.lock(
|
|
410
|
+
async function withFileLock(path9, fn, options) {
|
|
411
|
+
const release = await lockfile.lock(path9, { ...DEFAULT_OPTIONS, ...options });
|
|
384
412
|
try {
|
|
385
413
|
return await fn();
|
|
386
414
|
} finally {
|
|
@@ -436,6 +464,10 @@ async function createNetnsWithTap(nsName, tap) {
|
|
|
436
464
|
await execCommand(`ip netns exec ${nsName} ip link set ${tap.tapName} up`);
|
|
437
465
|
await execCommand(`ip netns exec ${nsName} ip link set lo up`);
|
|
438
466
|
}
|
|
467
|
+
async function deleteNetns(nsName) {
|
|
468
|
+
await execCommand(`ip netns del ${nsName}`).catch(() => {
|
|
469
|
+
});
|
|
470
|
+
}
|
|
439
471
|
|
|
440
472
|
// src/lib/firecracker/netns-pool.ts
|
|
441
473
|
var logger = createLogger("NetnsPool");
|
|
@@ -1077,10 +1109,10 @@ import * as http from "http";
|
|
|
1077
1109
|
import * as fs3 from "fs";
|
|
1078
1110
|
var logger3 = createLogger("FirecrackerClient");
|
|
1079
1111
|
var FirecrackerApiError = class extends Error {
|
|
1080
|
-
constructor(statusCode,
|
|
1081
|
-
super(`Firecracker API error ${statusCode} on ${
|
|
1112
|
+
constructor(statusCode, path9, faultMessage) {
|
|
1113
|
+
super(`Firecracker API error ${statusCode} on ${path9}: ${faultMessage}`);
|
|
1082
1114
|
this.statusCode = statusCode;
|
|
1083
|
-
this.path =
|
|
1115
|
+
this.path = path9;
|
|
1084
1116
|
this.faultMessage = faultMessage;
|
|
1085
1117
|
this.name = "FirecrackerApiError";
|
|
1086
1118
|
}
|
|
@@ -1193,27 +1225,27 @@ var FirecrackerClient = class {
|
|
|
1193
1225
|
/**
|
|
1194
1226
|
* GET request
|
|
1195
1227
|
*/
|
|
1196
|
-
async get(
|
|
1197
|
-
return this.request("GET",
|
|
1228
|
+
async get(path9) {
|
|
1229
|
+
return this.request("GET", path9);
|
|
1198
1230
|
}
|
|
1199
1231
|
/**
|
|
1200
1232
|
* PATCH request
|
|
1201
1233
|
*/
|
|
1202
|
-
async patch(
|
|
1203
|
-
return this.request("PATCH",
|
|
1234
|
+
async patch(path9, body) {
|
|
1235
|
+
return this.request("PATCH", path9, body);
|
|
1204
1236
|
}
|
|
1205
1237
|
/**
|
|
1206
1238
|
* PUT request
|
|
1207
1239
|
*/
|
|
1208
|
-
async put(
|
|
1209
|
-
return this.request("PUT",
|
|
1240
|
+
async put(path9, body) {
|
|
1241
|
+
return this.request("PUT", path9, body);
|
|
1210
1242
|
}
|
|
1211
1243
|
/**
|
|
1212
1244
|
* Make an HTTP request to Firecracker API
|
|
1213
1245
|
*
|
|
1214
1246
|
* @param timeoutMs Request timeout in milliseconds (default: 30000ms)
|
|
1215
1247
|
*/
|
|
1216
|
-
request(method,
|
|
1248
|
+
request(method, path9, body, timeoutMs = 3e4) {
|
|
1217
1249
|
return new Promise((resolve, reject) => {
|
|
1218
1250
|
const bodyStr = body !== void 0 ? JSON.stringify(body) : void 0;
|
|
1219
1251
|
const headers = {
|
|
@@ -1227,7 +1259,7 @@ var FirecrackerClient = class {
|
|
|
1227
1259
|
}
|
|
1228
1260
|
const options = {
|
|
1229
1261
|
socketPath: this.socketPath,
|
|
1230
|
-
path:
|
|
1262
|
+
path: path9,
|
|
1231
1263
|
method,
|
|
1232
1264
|
headers,
|
|
1233
1265
|
timeout: timeoutMs,
|
|
@@ -1235,7 +1267,7 @@ var FirecrackerClient = class {
|
|
|
1235
1267
|
// Firecracker's single-threaded API can have issues with pipelined requests
|
|
1236
1268
|
agent: false
|
|
1237
1269
|
};
|
|
1238
|
-
logger3.log(`${method} ${
|
|
1270
|
+
logger3.log(`${method} ${path9}${bodyStr ? " " + bodyStr : ""}`);
|
|
1239
1271
|
const req = http.request(options, (res) => {
|
|
1240
1272
|
let data = "";
|
|
1241
1273
|
res.on("data", (chunk) => {
|
|
@@ -1252,14 +1284,14 @@ var FirecrackerClient = class {
|
|
|
1252
1284
|
faultMessage = errorBody.fault_message || data;
|
|
1253
1285
|
} catch {
|
|
1254
1286
|
}
|
|
1255
|
-
reject(new FirecrackerApiError(statusCode,
|
|
1287
|
+
reject(new FirecrackerApiError(statusCode, path9, faultMessage));
|
|
1256
1288
|
}
|
|
1257
1289
|
});
|
|
1258
1290
|
});
|
|
1259
1291
|
req.on("timeout", () => {
|
|
1260
1292
|
req.destroy();
|
|
1261
1293
|
reject(
|
|
1262
|
-
new Error(`Request timeout after ${timeoutMs}ms: ${method} ${
|
|
1294
|
+
new Error(`Request timeout after ${timeoutMs}ms: ${method} ${path9}`)
|
|
1263
1295
|
);
|
|
1264
1296
|
});
|
|
1265
1297
|
req.on("error", (err) => {
|
|
@@ -1352,7 +1384,7 @@ var FirecrackerVM = class {
|
|
|
1352
1384
|
this.workDir = config.workDir;
|
|
1353
1385
|
this.vsockPath = vmPaths.vsock(this.workDir);
|
|
1354
1386
|
this.configPath = vmPaths.config(this.workDir);
|
|
1355
|
-
this.apiSocketPath =
|
|
1387
|
+
this.apiSocketPath = vmPaths.apiSock(this.workDir);
|
|
1356
1388
|
}
|
|
1357
1389
|
/**
|
|
1358
1390
|
* Get current VM state
|
|
@@ -1451,6 +1483,7 @@ var FirecrackerVM = class {
|
|
|
1451
1483
|
const config = this.buildConfig();
|
|
1452
1484
|
fs4.writeFileSync(this.configPath, JSON.stringify(config, null, 2));
|
|
1453
1485
|
logger4.log(`[VM ${this.config.vmId}] Starting Firecracker (fresh boot)...`);
|
|
1486
|
+
const currentUser = os.userInfo().username;
|
|
1454
1487
|
this.process = spawn(
|
|
1455
1488
|
"sudo",
|
|
1456
1489
|
[
|
|
@@ -1458,6 +1491,9 @@ var FirecrackerVM = class {
|
|
|
1458
1491
|
"netns",
|
|
1459
1492
|
"exec",
|
|
1460
1493
|
this.netns.name,
|
|
1494
|
+
"sudo",
|
|
1495
|
+
"-u",
|
|
1496
|
+
currentUser,
|
|
1461
1497
|
this.config.firecrackerBinary,
|
|
1462
1498
|
"--config-file",
|
|
1463
1499
|
this.configPath,
|
|
@@ -1475,25 +1511,58 @@ var FirecrackerVM = class {
|
|
|
1475
1511
|
* Start VM from snapshot
|
|
1476
1512
|
* Uses --api-sock to load snapshot via API
|
|
1477
1513
|
*
|
|
1478
|
-
*
|
|
1479
|
-
*
|
|
1514
|
+
* Snapshot contains original absolute paths for drives. We use mount namespace
|
|
1515
|
+
* isolation to bind mount our actual overlay file to the path expected by the snapshot.
|
|
1516
|
+
* This allows concurrent VMs to each have their own overlay while restoring from
|
|
1517
|
+
* the same snapshot.
|
|
1480
1518
|
*/
|
|
1481
1519
|
async startFromSnapshot(snapshot) {
|
|
1482
1520
|
logger4.log(
|
|
1483
1521
|
`[VM ${this.config.vmId}] Starting Firecracker (snapshot restore)...`
|
|
1484
1522
|
);
|
|
1485
|
-
logger4.log(`[VM ${this.config.vmId}] Snapshot: ${snapshot.
|
|
1486
|
-
logger4.log(`[VM ${this.config.vmId}] Memory: ${snapshot.
|
|
1523
|
+
logger4.log(`[VM ${this.config.vmId}] Snapshot: ${snapshot.snapshot}`);
|
|
1524
|
+
logger4.log(`[VM ${this.config.vmId}] Memory: ${snapshot.memory}`);
|
|
1525
|
+
const actualVsockDir = vmPaths.vsockDir(this.workDir);
|
|
1526
|
+
logger4.log(
|
|
1527
|
+
`[VM ${this.config.vmId}] Snapshot vsock: ${snapshot.snapshotVsockDir}`
|
|
1528
|
+
);
|
|
1529
|
+
logger4.log(
|
|
1530
|
+
`[VM ${this.config.vmId}] Snapshot overlay: ${snapshot.snapshotOverlay}`
|
|
1531
|
+
);
|
|
1532
|
+
logger4.log(`[VM ${this.config.vmId}] Actual vsock: ${actualVsockDir}`);
|
|
1533
|
+
logger4.log(
|
|
1534
|
+
`[VM ${this.config.vmId}] Actual overlay: ${this.vmOverlayPath}`
|
|
1535
|
+
);
|
|
1536
|
+
fs4.mkdirSync(snapshot.snapshotVsockDir, { recursive: true });
|
|
1537
|
+
fs4.mkdirSync(path4.dirname(snapshot.snapshotOverlay), {
|
|
1538
|
+
recursive: true
|
|
1539
|
+
});
|
|
1540
|
+
if (!fs4.existsSync(snapshot.snapshotOverlay)) {
|
|
1541
|
+
fs4.writeFileSync(snapshot.snapshotOverlay, "");
|
|
1542
|
+
}
|
|
1543
|
+
const currentUser = os.userInfo().username;
|
|
1544
|
+
const bindMountVsock = `mount --bind "${actualVsockDir}" "${snapshot.snapshotVsockDir}"`;
|
|
1545
|
+
const bindMountOverlay = `mount --bind "${this.vmOverlayPath}" "${snapshot.snapshotOverlay}"`;
|
|
1546
|
+
const firecrackerCmd = [
|
|
1547
|
+
"ip",
|
|
1548
|
+
"netns",
|
|
1549
|
+
"exec",
|
|
1550
|
+
this.netns.name,
|
|
1551
|
+
"sudo",
|
|
1552
|
+
"-u",
|
|
1553
|
+
currentUser,
|
|
1554
|
+
this.config.firecrackerBinary,
|
|
1555
|
+
"--api-sock",
|
|
1556
|
+
this.apiSocketPath
|
|
1557
|
+
].join(" ");
|
|
1487
1558
|
this.process = spawn(
|
|
1488
1559
|
"sudo",
|
|
1489
1560
|
[
|
|
1490
|
-
"
|
|
1491
|
-
"
|
|
1492
|
-
"
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
"--api-sock",
|
|
1496
|
-
this.apiSocketPath
|
|
1561
|
+
"unshare",
|
|
1562
|
+
"--mount",
|
|
1563
|
+
"bash",
|
|
1564
|
+
"-c",
|
|
1565
|
+
`${bindMountVsock} && ${bindMountOverlay} && ${firecrackerCmd}`
|
|
1497
1566
|
],
|
|
1498
1567
|
{
|
|
1499
1568
|
cwd: this.workDir,
|
|
@@ -1504,26 +1573,11 @@ var FirecrackerVM = class {
|
|
|
1504
1573
|
this.setupProcessHandlers();
|
|
1505
1574
|
const client = new FirecrackerClient(this.apiSocketPath);
|
|
1506
1575
|
await this.waitForApiReady(client);
|
|
1507
|
-
logger4.log(`[VM ${this.config.vmId}] Configuring drives...`);
|
|
1508
|
-
await Promise.all([
|
|
1509
|
-
client.configureDrive({
|
|
1510
|
-
drive_id: "rootfs",
|
|
1511
|
-
path_on_host: this.config.rootfsPath,
|
|
1512
|
-
is_root_device: true,
|
|
1513
|
-
is_read_only: true
|
|
1514
|
-
}),
|
|
1515
|
-
client.configureDrive({
|
|
1516
|
-
drive_id: "overlay",
|
|
1517
|
-
path_on_host: this.vmOverlayPath,
|
|
1518
|
-
is_root_device: false,
|
|
1519
|
-
is_read_only: false
|
|
1520
|
-
})
|
|
1521
|
-
]);
|
|
1522
1576
|
logger4.log(`[VM ${this.config.vmId}] Loading snapshot...`);
|
|
1523
1577
|
await client.loadSnapshot({
|
|
1524
|
-
snapshot_path: snapshot.
|
|
1578
|
+
snapshot_path: snapshot.snapshot,
|
|
1525
1579
|
mem_backend: {
|
|
1526
|
-
backend_path: snapshot.
|
|
1580
|
+
backend_path: snapshot.memory,
|
|
1527
1581
|
backend_type: "File"
|
|
1528
1582
|
},
|
|
1529
1583
|
resume_vm: true
|
|
@@ -1756,8 +1810,8 @@ function encodeExecPayload(command, timeoutMs) {
|
|
|
1756
1810
|
cmdBuf.copy(payload, 8);
|
|
1757
1811
|
return payload;
|
|
1758
1812
|
}
|
|
1759
|
-
function encodeWriteFilePayload(
|
|
1760
|
-
const pathBuf = Buffer.from(
|
|
1813
|
+
function encodeWriteFilePayload(path9, content, sudo) {
|
|
1814
|
+
const pathBuf = Buffer.from(path9, "utf-8");
|
|
1761
1815
|
if (pathBuf.length > 65535) {
|
|
1762
1816
|
throw new Error(`Path too long: ${pathBuf.length} bytes (max 65535)`);
|
|
1763
1817
|
}
|
|
@@ -2285,6 +2339,20 @@ var VsockClient = class {
|
|
|
2285
2339
|
}
|
|
2286
2340
|
this.cachedExits.clear();
|
|
2287
2341
|
}
|
|
2342
|
+
/**
|
|
2343
|
+
* Send raw bytes directly to the socket (for testing only)
|
|
2344
|
+
*
|
|
2345
|
+
* This allows tests to send malformed messages to verify the agent's
|
|
2346
|
+
* protocol error handling (e.g., oversized messages).
|
|
2347
|
+
*
|
|
2348
|
+
* @internal This method is only for testing purposes
|
|
2349
|
+
*/
|
|
2350
|
+
sendRawForTesting(data) {
|
|
2351
|
+
if (!this.connected || !this.socket) {
|
|
2352
|
+
throw new Error("Not connected - call waitForGuestConnection() first");
|
|
2353
|
+
}
|
|
2354
|
+
this.socket.write(data);
|
|
2355
|
+
}
|
|
2288
2356
|
};
|
|
2289
2357
|
|
|
2290
2358
|
// ../../packages/core/src/contracts/base.ts
|
|
@@ -2638,8 +2706,8 @@ function getErrorMap() {
|
|
|
2638
2706
|
return overrideErrorMap;
|
|
2639
2707
|
}
|
|
2640
2708
|
var makeIssue = (params) => {
|
|
2641
|
-
const { data, path:
|
|
2642
|
-
const fullPath = [...
|
|
2709
|
+
const { data, path: path9, errorMaps, issueData } = params;
|
|
2710
|
+
const fullPath = [...path9, ...issueData.path || []];
|
|
2643
2711
|
const fullIssue = {
|
|
2644
2712
|
...issueData,
|
|
2645
2713
|
path: fullPath
|
|
@@ -2738,11 +2806,11 @@ var errorUtil;
|
|
|
2738
2806
|
errorUtil2.toString = (message) => typeof message === "string" ? message : message === null || message === void 0 ? void 0 : message.message;
|
|
2739
2807
|
})(errorUtil || (errorUtil = {}));
|
|
2740
2808
|
var ParseInputLazyPath = class {
|
|
2741
|
-
constructor(parent, value,
|
|
2809
|
+
constructor(parent, value, path9, key) {
|
|
2742
2810
|
this._cachedPath = [];
|
|
2743
2811
|
this.parent = parent;
|
|
2744
2812
|
this.data = value;
|
|
2745
|
-
this._path =
|
|
2813
|
+
this._path = path9;
|
|
2746
2814
|
this._key = key;
|
|
2747
2815
|
}
|
|
2748
2816
|
get path() {
|
|
@@ -7705,58 +7773,159 @@ var credentialsByNameContract = c10.router({
|
|
|
7705
7773
|
}
|
|
7706
7774
|
});
|
|
7707
7775
|
|
|
7708
|
-
// ../../packages/core/src/contracts/
|
|
7776
|
+
// ../../packages/core/src/contracts/secrets.ts
|
|
7709
7777
|
import { z as z18 } from "zod";
|
|
7710
7778
|
var c11 = initContract();
|
|
7711
|
-
var
|
|
7779
|
+
var secretNameSchema = z18.string().min(1, "Secret name is required").max(255, "Secret name must be at most 255 characters").regex(
|
|
7780
|
+
/^[A-Z][A-Z0-9_]*$/,
|
|
7781
|
+
"Secret name must contain only uppercase letters, numbers, and underscores, and must start with a letter (e.g., MY_API_KEY)"
|
|
7782
|
+
);
|
|
7783
|
+
var secretTypeSchema = z18.enum(["user", "model-provider"]);
|
|
7784
|
+
var secretResponseSchema = z18.object({
|
|
7785
|
+
id: z18.string().uuid(),
|
|
7786
|
+
name: z18.string(),
|
|
7787
|
+
description: z18.string().nullable(),
|
|
7788
|
+
type: secretTypeSchema,
|
|
7789
|
+
createdAt: z18.string(),
|
|
7790
|
+
updatedAt: z18.string()
|
|
7791
|
+
});
|
|
7792
|
+
var secretListResponseSchema = z18.object({
|
|
7793
|
+
secrets: z18.array(secretResponseSchema)
|
|
7794
|
+
});
|
|
7795
|
+
var setSecretRequestSchema = z18.object({
|
|
7796
|
+
name: secretNameSchema,
|
|
7797
|
+
value: z18.string().min(1, "Secret value is required"),
|
|
7798
|
+
description: z18.string().max(1e3).optional()
|
|
7799
|
+
});
|
|
7800
|
+
var secretsMainContract = c11.router({
|
|
7801
|
+
/**
|
|
7802
|
+
* GET /api/secrets
|
|
7803
|
+
* List all secrets for the current user's scope (metadata only)
|
|
7804
|
+
*/
|
|
7805
|
+
list: {
|
|
7806
|
+
method: "GET",
|
|
7807
|
+
path: "/api/secrets",
|
|
7808
|
+
headers: authHeadersSchema,
|
|
7809
|
+
responses: {
|
|
7810
|
+
200: secretListResponseSchema,
|
|
7811
|
+
401: apiErrorSchema,
|
|
7812
|
+
500: apiErrorSchema
|
|
7813
|
+
},
|
|
7814
|
+
summary: "List all secrets (metadata only)"
|
|
7815
|
+
},
|
|
7816
|
+
/**
|
|
7817
|
+
* PUT /api/secrets
|
|
7818
|
+
* Create or update a secret
|
|
7819
|
+
*/
|
|
7820
|
+
set: {
|
|
7821
|
+
method: "PUT",
|
|
7822
|
+
path: "/api/secrets",
|
|
7823
|
+
headers: authHeadersSchema,
|
|
7824
|
+
body: setSecretRequestSchema,
|
|
7825
|
+
responses: {
|
|
7826
|
+
200: secretResponseSchema,
|
|
7827
|
+
201: secretResponseSchema,
|
|
7828
|
+
400: apiErrorSchema,
|
|
7829
|
+
401: apiErrorSchema,
|
|
7830
|
+
500: apiErrorSchema
|
|
7831
|
+
},
|
|
7832
|
+
summary: "Create or update a secret"
|
|
7833
|
+
}
|
|
7834
|
+
});
|
|
7835
|
+
var secretsByNameContract = c11.router({
|
|
7836
|
+
/**
|
|
7837
|
+
* GET /api/secrets/:name
|
|
7838
|
+
* Get a secret by name (metadata only)
|
|
7839
|
+
*/
|
|
7840
|
+
get: {
|
|
7841
|
+
method: "GET",
|
|
7842
|
+
path: "/api/secrets/:name",
|
|
7843
|
+
headers: authHeadersSchema,
|
|
7844
|
+
pathParams: z18.object({
|
|
7845
|
+
name: secretNameSchema
|
|
7846
|
+
}),
|
|
7847
|
+
responses: {
|
|
7848
|
+
200: secretResponseSchema,
|
|
7849
|
+
401: apiErrorSchema,
|
|
7850
|
+
404: apiErrorSchema,
|
|
7851
|
+
500: apiErrorSchema
|
|
7852
|
+
},
|
|
7853
|
+
summary: "Get secret metadata by name"
|
|
7854
|
+
},
|
|
7855
|
+
/**
|
|
7856
|
+
* DELETE /api/secrets/:name
|
|
7857
|
+
* Delete a secret by name
|
|
7858
|
+
*/
|
|
7859
|
+
delete: {
|
|
7860
|
+
method: "DELETE",
|
|
7861
|
+
path: "/api/secrets/:name",
|
|
7862
|
+
headers: authHeadersSchema,
|
|
7863
|
+
pathParams: z18.object({
|
|
7864
|
+
name: secretNameSchema
|
|
7865
|
+
}),
|
|
7866
|
+
responses: {
|
|
7867
|
+
204: c11.noBody(),
|
|
7868
|
+
401: apiErrorSchema,
|
|
7869
|
+
404: apiErrorSchema,
|
|
7870
|
+
500: apiErrorSchema
|
|
7871
|
+
},
|
|
7872
|
+
summary: "Delete a secret"
|
|
7873
|
+
}
|
|
7874
|
+
});
|
|
7875
|
+
|
|
7876
|
+
// ../../packages/core/src/contracts/model-providers.ts
|
|
7877
|
+
import { z as z19 } from "zod";
|
|
7878
|
+
var c12 = initContract();
|
|
7879
|
+
var modelProviderTypeSchema = z19.enum([
|
|
7712
7880
|
"claude-code-oauth-token",
|
|
7713
7881
|
"anthropic-api-key",
|
|
7714
7882
|
"openrouter-api-key",
|
|
7715
7883
|
"moonshot-api-key",
|
|
7716
7884
|
"minimax-api-key",
|
|
7717
7885
|
"deepseek-api-key",
|
|
7886
|
+
"zai-api-key",
|
|
7718
7887
|
"aws-bedrock"
|
|
7719
7888
|
]);
|
|
7720
|
-
var modelProviderFrameworkSchema =
|
|
7721
|
-
var modelProviderResponseSchema =
|
|
7722
|
-
id:
|
|
7889
|
+
var modelProviderFrameworkSchema = z19.enum(["claude-code", "codex"]);
|
|
7890
|
+
var modelProviderResponseSchema = z19.object({
|
|
7891
|
+
id: z19.string().uuid(),
|
|
7723
7892
|
type: modelProviderTypeSchema,
|
|
7724
7893
|
framework: modelProviderFrameworkSchema,
|
|
7725
|
-
credentialName:
|
|
7894
|
+
credentialName: z19.string().nullable(),
|
|
7726
7895
|
// Legacy single-credential (deprecated for multi-auth)
|
|
7727
|
-
authMethod:
|
|
7896
|
+
authMethod: z19.string().nullable(),
|
|
7728
7897
|
// For multi-auth providers
|
|
7729
|
-
credentialNames:
|
|
7898
|
+
credentialNames: z19.array(z19.string()).nullable(),
|
|
7730
7899
|
// For multi-auth providers
|
|
7731
|
-
isDefault:
|
|
7732
|
-
selectedModel:
|
|
7733
|
-
createdAt:
|
|
7734
|
-
updatedAt:
|
|
7900
|
+
isDefault: z19.boolean(),
|
|
7901
|
+
selectedModel: z19.string().nullable(),
|
|
7902
|
+
createdAt: z19.string(),
|
|
7903
|
+
updatedAt: z19.string()
|
|
7735
7904
|
});
|
|
7736
|
-
var modelProviderListResponseSchema =
|
|
7737
|
-
modelProviders:
|
|
7905
|
+
var modelProviderListResponseSchema = z19.object({
|
|
7906
|
+
modelProviders: z19.array(modelProviderResponseSchema)
|
|
7738
7907
|
});
|
|
7739
|
-
var upsertModelProviderRequestSchema =
|
|
7908
|
+
var upsertModelProviderRequestSchema = z19.object({
|
|
7740
7909
|
type: modelProviderTypeSchema,
|
|
7741
|
-
credential:
|
|
7910
|
+
credential: z19.string().min(1).optional(),
|
|
7742
7911
|
// Legacy single credential
|
|
7743
|
-
authMethod:
|
|
7912
|
+
authMethod: z19.string().optional(),
|
|
7744
7913
|
// For multi-auth providers
|
|
7745
|
-
credentials:
|
|
7914
|
+
credentials: z19.record(z19.string(), z19.string()).optional(),
|
|
7746
7915
|
// For multi-auth providers
|
|
7747
|
-
convert:
|
|
7748
|
-
selectedModel:
|
|
7916
|
+
convert: z19.boolean().optional(),
|
|
7917
|
+
selectedModel: z19.string().optional()
|
|
7749
7918
|
});
|
|
7750
|
-
var upsertModelProviderResponseSchema =
|
|
7919
|
+
var upsertModelProviderResponseSchema = z19.object({
|
|
7751
7920
|
provider: modelProviderResponseSchema,
|
|
7752
|
-
created:
|
|
7921
|
+
created: z19.boolean()
|
|
7753
7922
|
});
|
|
7754
|
-
var checkCredentialResponseSchema =
|
|
7755
|
-
exists:
|
|
7756
|
-
credentialName:
|
|
7757
|
-
currentType:
|
|
7923
|
+
var checkCredentialResponseSchema = z19.object({
|
|
7924
|
+
exists: z19.boolean(),
|
|
7925
|
+
credentialName: z19.string(),
|
|
7926
|
+
currentType: z19.enum(["user", "model-provider"]).optional()
|
|
7758
7927
|
});
|
|
7759
|
-
var modelProvidersMainContract =
|
|
7928
|
+
var modelProvidersMainContract = c12.router({
|
|
7760
7929
|
list: {
|
|
7761
7930
|
method: "GET",
|
|
7762
7931
|
path: "/api/model-providers",
|
|
@@ -7784,12 +7953,12 @@ var modelProvidersMainContract = c11.router({
|
|
|
7784
7953
|
summary: "Create or update a model provider"
|
|
7785
7954
|
}
|
|
7786
7955
|
});
|
|
7787
|
-
var modelProvidersCheckContract =
|
|
7956
|
+
var modelProvidersCheckContract = c12.router({
|
|
7788
7957
|
check: {
|
|
7789
7958
|
method: "GET",
|
|
7790
7959
|
path: "/api/model-providers/check/:type",
|
|
7791
7960
|
headers: authHeadersSchema,
|
|
7792
|
-
pathParams:
|
|
7961
|
+
pathParams: z19.object({
|
|
7793
7962
|
type: modelProviderTypeSchema
|
|
7794
7963
|
}),
|
|
7795
7964
|
responses: {
|
|
@@ -7800,16 +7969,16 @@ var modelProvidersCheckContract = c11.router({
|
|
|
7800
7969
|
summary: "Check if credential exists for a model provider type"
|
|
7801
7970
|
}
|
|
7802
7971
|
});
|
|
7803
|
-
var modelProvidersByTypeContract =
|
|
7972
|
+
var modelProvidersByTypeContract = c12.router({
|
|
7804
7973
|
delete: {
|
|
7805
7974
|
method: "DELETE",
|
|
7806
7975
|
path: "/api/model-providers/:type",
|
|
7807
7976
|
headers: authHeadersSchema,
|
|
7808
|
-
pathParams:
|
|
7977
|
+
pathParams: z19.object({
|
|
7809
7978
|
type: modelProviderTypeSchema
|
|
7810
7979
|
}),
|
|
7811
7980
|
responses: {
|
|
7812
|
-
204:
|
|
7981
|
+
204: c12.noBody(),
|
|
7813
7982
|
401: apiErrorSchema,
|
|
7814
7983
|
404: apiErrorSchema,
|
|
7815
7984
|
500: apiErrorSchema
|
|
@@ -7817,15 +7986,15 @@ var modelProvidersByTypeContract = c11.router({
|
|
|
7817
7986
|
summary: "Delete a model provider"
|
|
7818
7987
|
}
|
|
7819
7988
|
});
|
|
7820
|
-
var modelProvidersConvertContract =
|
|
7989
|
+
var modelProvidersConvertContract = c12.router({
|
|
7821
7990
|
convert: {
|
|
7822
7991
|
method: "POST",
|
|
7823
7992
|
path: "/api/model-providers/:type/convert",
|
|
7824
7993
|
headers: authHeadersSchema,
|
|
7825
|
-
pathParams:
|
|
7994
|
+
pathParams: z19.object({
|
|
7826
7995
|
type: modelProviderTypeSchema
|
|
7827
7996
|
}),
|
|
7828
|
-
body:
|
|
7997
|
+
body: z19.undefined(),
|
|
7829
7998
|
responses: {
|
|
7830
7999
|
200: modelProviderResponseSchema,
|
|
7831
8000
|
400: apiErrorSchema,
|
|
@@ -7836,15 +8005,15 @@ var modelProvidersConvertContract = c11.router({
|
|
|
7836
8005
|
summary: "Convert existing user credential to model provider"
|
|
7837
8006
|
}
|
|
7838
8007
|
});
|
|
7839
|
-
var modelProvidersSetDefaultContract =
|
|
8008
|
+
var modelProvidersSetDefaultContract = c12.router({
|
|
7840
8009
|
setDefault: {
|
|
7841
8010
|
method: "POST",
|
|
7842
8011
|
path: "/api/model-providers/:type/set-default",
|
|
7843
8012
|
headers: authHeadersSchema,
|
|
7844
|
-
pathParams:
|
|
8013
|
+
pathParams: z19.object({
|
|
7845
8014
|
type: modelProviderTypeSchema
|
|
7846
8015
|
}),
|
|
7847
|
-
body:
|
|
8016
|
+
body: z19.undefined(),
|
|
7848
8017
|
responses: {
|
|
7849
8018
|
200: modelProviderResponseSchema,
|
|
7850
8019
|
401: apiErrorSchema,
|
|
@@ -7854,15 +8023,15 @@ var modelProvidersSetDefaultContract = c11.router({
|
|
|
7854
8023
|
summary: "Set a model provider as default for its framework"
|
|
7855
8024
|
}
|
|
7856
8025
|
});
|
|
7857
|
-
var updateModelRequestSchema =
|
|
7858
|
-
selectedModel:
|
|
8026
|
+
var updateModelRequestSchema = z19.object({
|
|
8027
|
+
selectedModel: z19.string().optional()
|
|
7859
8028
|
});
|
|
7860
|
-
var modelProvidersUpdateModelContract =
|
|
8029
|
+
var modelProvidersUpdateModelContract = c12.router({
|
|
7861
8030
|
updateModel: {
|
|
7862
8031
|
method: "PATCH",
|
|
7863
8032
|
path: "/api/model-providers/:type/model",
|
|
7864
8033
|
headers: authHeadersSchema,
|
|
7865
|
-
pathParams:
|
|
8034
|
+
pathParams: z19.object({
|
|
7866
8035
|
type: modelProviderTypeSchema
|
|
7867
8036
|
}),
|
|
7868
8037
|
body: updateModelRequestSchema,
|
|
@@ -7877,42 +8046,42 @@ var modelProvidersUpdateModelContract = c11.router({
|
|
|
7877
8046
|
});
|
|
7878
8047
|
|
|
7879
8048
|
// ../../packages/core/src/contracts/sessions.ts
|
|
7880
|
-
import { z as
|
|
7881
|
-
var
|
|
7882
|
-
var sessionResponseSchema =
|
|
7883
|
-
id:
|
|
7884
|
-
agentComposeId:
|
|
7885
|
-
agentComposeVersionId:
|
|
7886
|
-
conversationId:
|
|
7887
|
-
artifactName:
|
|
7888
|
-
vars:
|
|
7889
|
-
secretNames:
|
|
7890
|
-
volumeVersions:
|
|
7891
|
-
createdAt:
|
|
7892
|
-
updatedAt:
|
|
8049
|
+
import { z as z20 } from "zod";
|
|
8050
|
+
var c13 = initContract();
|
|
8051
|
+
var sessionResponseSchema = z20.object({
|
|
8052
|
+
id: z20.string(),
|
|
8053
|
+
agentComposeId: z20.string(),
|
|
8054
|
+
agentComposeVersionId: z20.string().nullable(),
|
|
8055
|
+
conversationId: z20.string().nullable(),
|
|
8056
|
+
artifactName: z20.string().nullable(),
|
|
8057
|
+
vars: z20.record(z20.string(), z20.string()).nullable(),
|
|
8058
|
+
secretNames: z20.array(z20.string()).nullable(),
|
|
8059
|
+
volumeVersions: z20.record(z20.string(), z20.string()).nullable(),
|
|
8060
|
+
createdAt: z20.string(),
|
|
8061
|
+
updatedAt: z20.string()
|
|
7893
8062
|
});
|
|
7894
|
-
var agentComposeSnapshotSchema =
|
|
7895
|
-
agentComposeVersionId:
|
|
7896
|
-
vars:
|
|
7897
|
-
secretNames:
|
|
8063
|
+
var agentComposeSnapshotSchema = z20.object({
|
|
8064
|
+
agentComposeVersionId: z20.string(),
|
|
8065
|
+
vars: z20.record(z20.string(), z20.string()).optional(),
|
|
8066
|
+
secretNames: z20.array(z20.string()).optional()
|
|
7898
8067
|
});
|
|
7899
|
-
var artifactSnapshotSchema2 =
|
|
7900
|
-
artifactName:
|
|
7901
|
-
artifactVersion:
|
|
8068
|
+
var artifactSnapshotSchema2 = z20.object({
|
|
8069
|
+
artifactName: z20.string(),
|
|
8070
|
+
artifactVersion: z20.string()
|
|
7902
8071
|
});
|
|
7903
|
-
var volumeVersionsSnapshotSchema2 =
|
|
7904
|
-
versions:
|
|
8072
|
+
var volumeVersionsSnapshotSchema2 = z20.object({
|
|
8073
|
+
versions: z20.record(z20.string(), z20.string())
|
|
7905
8074
|
});
|
|
7906
|
-
var checkpointResponseSchema =
|
|
7907
|
-
id:
|
|
7908
|
-
runId:
|
|
7909
|
-
conversationId:
|
|
8075
|
+
var checkpointResponseSchema = z20.object({
|
|
8076
|
+
id: z20.string(),
|
|
8077
|
+
runId: z20.string(),
|
|
8078
|
+
conversationId: z20.string(),
|
|
7910
8079
|
agentComposeSnapshot: agentComposeSnapshotSchema,
|
|
7911
8080
|
artifactSnapshot: artifactSnapshotSchema2.nullable(),
|
|
7912
8081
|
volumeVersionsSnapshot: volumeVersionsSnapshotSchema2.nullable(),
|
|
7913
|
-
createdAt:
|
|
8082
|
+
createdAt: z20.string()
|
|
7914
8083
|
});
|
|
7915
|
-
var sessionsByIdContract =
|
|
8084
|
+
var sessionsByIdContract = c13.router({
|
|
7916
8085
|
/**
|
|
7917
8086
|
* GET /api/agent/sessions/:id
|
|
7918
8087
|
* Get session by ID
|
|
@@ -7921,8 +8090,8 @@ var sessionsByIdContract = c12.router({
|
|
|
7921
8090
|
method: "GET",
|
|
7922
8091
|
path: "/api/agent/sessions/:id",
|
|
7923
8092
|
headers: authHeadersSchema,
|
|
7924
|
-
pathParams:
|
|
7925
|
-
id:
|
|
8093
|
+
pathParams: z20.object({
|
|
8094
|
+
id: z20.string().min(1, "Session ID is required")
|
|
7926
8095
|
}),
|
|
7927
8096
|
responses: {
|
|
7928
8097
|
200: sessionResponseSchema,
|
|
@@ -7933,7 +8102,7 @@ var sessionsByIdContract = c12.router({
|
|
|
7933
8102
|
summary: "Get session by ID"
|
|
7934
8103
|
}
|
|
7935
8104
|
});
|
|
7936
|
-
var checkpointsByIdContract =
|
|
8105
|
+
var checkpointsByIdContract = c13.router({
|
|
7937
8106
|
/**
|
|
7938
8107
|
* GET /api/agent/checkpoints/:id
|
|
7939
8108
|
* Get checkpoint by ID
|
|
@@ -7942,8 +8111,8 @@ var checkpointsByIdContract = c12.router({
|
|
|
7942
8111
|
method: "GET",
|
|
7943
8112
|
path: "/api/agent/checkpoints/:id",
|
|
7944
8113
|
headers: authHeadersSchema,
|
|
7945
|
-
pathParams:
|
|
7946
|
-
id:
|
|
8114
|
+
pathParams: z20.object({
|
|
8115
|
+
id: z20.string().min(1, "Checkpoint ID is required")
|
|
7947
8116
|
}),
|
|
7948
8117
|
responses: {
|
|
7949
8118
|
200: checkpointResponseSchema,
|
|
@@ -7956,93 +8125,93 @@ var checkpointsByIdContract = c12.router({
|
|
|
7956
8125
|
});
|
|
7957
8126
|
|
|
7958
8127
|
// ../../packages/core/src/contracts/schedules.ts
|
|
7959
|
-
import { z as
|
|
7960
|
-
var
|
|
7961
|
-
var scheduleTriggerSchema =
|
|
7962
|
-
cron:
|
|
7963
|
-
at:
|
|
7964
|
-
timezone:
|
|
8128
|
+
import { z as z21 } from "zod";
|
|
8129
|
+
var c14 = initContract();
|
|
8130
|
+
var scheduleTriggerSchema = z21.object({
|
|
8131
|
+
cron: z21.string().optional(),
|
|
8132
|
+
at: z21.string().optional(),
|
|
8133
|
+
timezone: z21.string().default("UTC")
|
|
7965
8134
|
}).refine((data) => data.cron && !data.at || !data.cron && data.at, {
|
|
7966
8135
|
message: "Exactly one of 'cron' or 'at' must be specified"
|
|
7967
8136
|
});
|
|
7968
|
-
var scheduleRunConfigSchema =
|
|
7969
|
-
agent:
|
|
7970
|
-
prompt:
|
|
7971
|
-
vars:
|
|
7972
|
-
secrets:
|
|
7973
|
-
artifactName:
|
|
7974
|
-
artifactVersion:
|
|
7975
|
-
volumeVersions:
|
|
8137
|
+
var scheduleRunConfigSchema = z21.object({
|
|
8138
|
+
agent: z21.string().min(1, "Agent reference required"),
|
|
8139
|
+
prompt: z21.string().min(1, "Prompt required"),
|
|
8140
|
+
vars: z21.record(z21.string(), z21.string()).optional(),
|
|
8141
|
+
secrets: z21.record(z21.string(), z21.string()).optional(),
|
|
8142
|
+
artifactName: z21.string().optional(),
|
|
8143
|
+
artifactVersion: z21.string().optional(),
|
|
8144
|
+
volumeVersions: z21.record(z21.string(), z21.string()).optional()
|
|
7976
8145
|
});
|
|
7977
|
-
var scheduleDefinitionSchema =
|
|
8146
|
+
var scheduleDefinitionSchema = z21.object({
|
|
7978
8147
|
on: scheduleTriggerSchema,
|
|
7979
8148
|
run: scheduleRunConfigSchema
|
|
7980
8149
|
});
|
|
7981
|
-
var scheduleYamlSchema =
|
|
7982
|
-
version:
|
|
7983
|
-
schedules:
|
|
7984
|
-
});
|
|
7985
|
-
var deployScheduleRequestSchema =
|
|
7986
|
-
name:
|
|
7987
|
-
cronExpression:
|
|
7988
|
-
atTime:
|
|
7989
|
-
timezone:
|
|
7990
|
-
prompt:
|
|
7991
|
-
vars:
|
|
7992
|
-
secrets:
|
|
7993
|
-
artifactName:
|
|
7994
|
-
artifactVersion:
|
|
7995
|
-
volumeVersions:
|
|
8150
|
+
var scheduleYamlSchema = z21.object({
|
|
8151
|
+
version: z21.literal("1.0"),
|
|
8152
|
+
schedules: z21.record(z21.string(), scheduleDefinitionSchema)
|
|
8153
|
+
});
|
|
8154
|
+
var deployScheduleRequestSchema = z21.object({
|
|
8155
|
+
name: z21.string().min(1).max(64, "Schedule name max 64 chars"),
|
|
8156
|
+
cronExpression: z21.string().optional(),
|
|
8157
|
+
atTime: z21.string().optional(),
|
|
8158
|
+
timezone: z21.string().default("UTC"),
|
|
8159
|
+
prompt: z21.string().min(1, "Prompt required"),
|
|
8160
|
+
vars: z21.record(z21.string(), z21.string()).optional(),
|
|
8161
|
+
secrets: z21.record(z21.string(), z21.string()).optional(),
|
|
8162
|
+
artifactName: z21.string().optional(),
|
|
8163
|
+
artifactVersion: z21.string().optional(),
|
|
8164
|
+
volumeVersions: z21.record(z21.string(), z21.string()).optional(),
|
|
7996
8165
|
// Resolved agent compose ID (CLI resolves scope/name:version → composeId)
|
|
7997
|
-
composeId:
|
|
8166
|
+
composeId: z21.string().uuid("Invalid compose ID")
|
|
7998
8167
|
}).refine(
|
|
7999
8168
|
(data) => data.cronExpression && !data.atTime || !data.cronExpression && data.atTime,
|
|
8000
8169
|
{
|
|
8001
8170
|
message: "Exactly one of 'cronExpression' or 'atTime' must be specified"
|
|
8002
8171
|
}
|
|
8003
8172
|
);
|
|
8004
|
-
var scheduleResponseSchema =
|
|
8005
|
-
id:
|
|
8006
|
-
composeId:
|
|
8007
|
-
composeName:
|
|
8008
|
-
scopeSlug:
|
|
8009
|
-
name:
|
|
8010
|
-
cronExpression:
|
|
8011
|
-
atTime:
|
|
8012
|
-
timezone:
|
|
8013
|
-
prompt:
|
|
8014
|
-
vars:
|
|
8173
|
+
var scheduleResponseSchema = z21.object({
|
|
8174
|
+
id: z21.string().uuid(),
|
|
8175
|
+
composeId: z21.string().uuid(),
|
|
8176
|
+
composeName: z21.string(),
|
|
8177
|
+
scopeSlug: z21.string(),
|
|
8178
|
+
name: z21.string(),
|
|
8179
|
+
cronExpression: z21.string().nullable(),
|
|
8180
|
+
atTime: z21.string().nullable(),
|
|
8181
|
+
timezone: z21.string(),
|
|
8182
|
+
prompt: z21.string(),
|
|
8183
|
+
vars: z21.record(z21.string(), z21.string()).nullable(),
|
|
8015
8184
|
// Secret names only (values are never returned)
|
|
8016
|
-
secretNames:
|
|
8017
|
-
artifactName:
|
|
8018
|
-
artifactVersion:
|
|
8019
|
-
volumeVersions:
|
|
8020
|
-
enabled:
|
|
8021
|
-
nextRunAt:
|
|
8022
|
-
lastRunAt:
|
|
8023
|
-
retryStartedAt:
|
|
8024
|
-
createdAt:
|
|
8025
|
-
updatedAt:
|
|
8026
|
-
});
|
|
8027
|
-
var runSummarySchema =
|
|
8028
|
-
id:
|
|
8029
|
-
status:
|
|
8030
|
-
createdAt:
|
|
8031
|
-
completedAt:
|
|
8032
|
-
error:
|
|
8033
|
-
});
|
|
8034
|
-
var scheduleRunsResponseSchema =
|
|
8035
|
-
runs:
|
|
8036
|
-
});
|
|
8037
|
-
var scheduleListResponseSchema =
|
|
8038
|
-
schedules:
|
|
8039
|
-
});
|
|
8040
|
-
var deployScheduleResponseSchema =
|
|
8185
|
+
secretNames: z21.array(z21.string()).nullable(),
|
|
8186
|
+
artifactName: z21.string().nullable(),
|
|
8187
|
+
artifactVersion: z21.string().nullable(),
|
|
8188
|
+
volumeVersions: z21.record(z21.string(), z21.string()).nullable(),
|
|
8189
|
+
enabled: z21.boolean(),
|
|
8190
|
+
nextRunAt: z21.string().nullable(),
|
|
8191
|
+
lastRunAt: z21.string().nullable(),
|
|
8192
|
+
retryStartedAt: z21.string().nullable(),
|
|
8193
|
+
createdAt: z21.string(),
|
|
8194
|
+
updatedAt: z21.string()
|
|
8195
|
+
});
|
|
8196
|
+
var runSummarySchema = z21.object({
|
|
8197
|
+
id: z21.string().uuid(),
|
|
8198
|
+
status: z21.enum(["pending", "running", "completed", "failed", "timeout"]),
|
|
8199
|
+
createdAt: z21.string(),
|
|
8200
|
+
completedAt: z21.string().nullable(),
|
|
8201
|
+
error: z21.string().nullable()
|
|
8202
|
+
});
|
|
8203
|
+
var scheduleRunsResponseSchema = z21.object({
|
|
8204
|
+
runs: z21.array(runSummarySchema)
|
|
8205
|
+
});
|
|
8206
|
+
var scheduleListResponseSchema = z21.object({
|
|
8207
|
+
schedules: z21.array(scheduleResponseSchema)
|
|
8208
|
+
});
|
|
8209
|
+
var deployScheduleResponseSchema = z21.object({
|
|
8041
8210
|
schedule: scheduleResponseSchema,
|
|
8042
|
-
created:
|
|
8211
|
+
created: z21.boolean()
|
|
8043
8212
|
// true if created, false if updated
|
|
8044
8213
|
});
|
|
8045
|
-
var schedulesMainContract =
|
|
8214
|
+
var schedulesMainContract = c14.router({
|
|
8046
8215
|
/**
|
|
8047
8216
|
* POST /api/agent/schedules
|
|
8048
8217
|
* Deploy (create or update) a schedule
|
|
@@ -8080,7 +8249,7 @@ var schedulesMainContract = c13.router({
|
|
|
8080
8249
|
summary: "List all schedules"
|
|
8081
8250
|
}
|
|
8082
8251
|
});
|
|
8083
|
-
var schedulesByNameContract =
|
|
8252
|
+
var schedulesByNameContract = c14.router({
|
|
8084
8253
|
/**
|
|
8085
8254
|
* GET /api/agent/schedules/:name
|
|
8086
8255
|
* Get schedule by name
|
|
@@ -8089,11 +8258,11 @@ var schedulesByNameContract = c13.router({
|
|
|
8089
8258
|
method: "GET",
|
|
8090
8259
|
path: "/api/agent/schedules/:name",
|
|
8091
8260
|
headers: authHeadersSchema,
|
|
8092
|
-
pathParams:
|
|
8093
|
-
name:
|
|
8261
|
+
pathParams: z21.object({
|
|
8262
|
+
name: z21.string().min(1, "Schedule name required")
|
|
8094
8263
|
}),
|
|
8095
|
-
query:
|
|
8096
|
-
composeId:
|
|
8264
|
+
query: z21.object({
|
|
8265
|
+
composeId: z21.string().uuid("Compose ID required")
|
|
8097
8266
|
}),
|
|
8098
8267
|
responses: {
|
|
8099
8268
|
200: scheduleResponseSchema,
|
|
@@ -8110,21 +8279,21 @@ var schedulesByNameContract = c13.router({
|
|
|
8110
8279
|
method: "DELETE",
|
|
8111
8280
|
path: "/api/agent/schedules/:name",
|
|
8112
8281
|
headers: authHeadersSchema,
|
|
8113
|
-
pathParams:
|
|
8114
|
-
name:
|
|
8282
|
+
pathParams: z21.object({
|
|
8283
|
+
name: z21.string().min(1, "Schedule name required")
|
|
8115
8284
|
}),
|
|
8116
|
-
query:
|
|
8117
|
-
composeId:
|
|
8285
|
+
query: z21.object({
|
|
8286
|
+
composeId: z21.string().uuid("Compose ID required")
|
|
8118
8287
|
}),
|
|
8119
8288
|
responses: {
|
|
8120
|
-
204:
|
|
8289
|
+
204: c14.noBody(),
|
|
8121
8290
|
401: apiErrorSchema,
|
|
8122
8291
|
404: apiErrorSchema
|
|
8123
8292
|
},
|
|
8124
8293
|
summary: "Delete schedule"
|
|
8125
8294
|
}
|
|
8126
8295
|
});
|
|
8127
|
-
var schedulesEnableContract =
|
|
8296
|
+
var schedulesEnableContract = c14.router({
|
|
8128
8297
|
/**
|
|
8129
8298
|
* POST /api/agent/schedules/:name/enable
|
|
8130
8299
|
* Enable a disabled schedule
|
|
@@ -8133,11 +8302,11 @@ var schedulesEnableContract = c13.router({
|
|
|
8133
8302
|
method: "POST",
|
|
8134
8303
|
path: "/api/agent/schedules/:name/enable",
|
|
8135
8304
|
headers: authHeadersSchema,
|
|
8136
|
-
pathParams:
|
|
8137
|
-
name:
|
|
8305
|
+
pathParams: z21.object({
|
|
8306
|
+
name: z21.string().min(1, "Schedule name required")
|
|
8138
8307
|
}),
|
|
8139
|
-
body:
|
|
8140
|
-
composeId:
|
|
8308
|
+
body: z21.object({
|
|
8309
|
+
composeId: z21.string().uuid("Compose ID required")
|
|
8141
8310
|
}),
|
|
8142
8311
|
responses: {
|
|
8143
8312
|
200: scheduleResponseSchema,
|
|
@@ -8154,11 +8323,11 @@ var schedulesEnableContract = c13.router({
|
|
|
8154
8323
|
method: "POST",
|
|
8155
8324
|
path: "/api/agent/schedules/:name/disable",
|
|
8156
8325
|
headers: authHeadersSchema,
|
|
8157
|
-
pathParams:
|
|
8158
|
-
name:
|
|
8326
|
+
pathParams: z21.object({
|
|
8327
|
+
name: z21.string().min(1, "Schedule name required")
|
|
8159
8328
|
}),
|
|
8160
|
-
body:
|
|
8161
|
-
composeId:
|
|
8329
|
+
body: z21.object({
|
|
8330
|
+
composeId: z21.string().uuid("Compose ID required")
|
|
8162
8331
|
}),
|
|
8163
8332
|
responses: {
|
|
8164
8333
|
200: scheduleResponseSchema,
|
|
@@ -8168,7 +8337,7 @@ var schedulesEnableContract = c13.router({
|
|
|
8168
8337
|
summary: "Disable schedule"
|
|
8169
8338
|
}
|
|
8170
8339
|
});
|
|
8171
|
-
var scheduleRunsContract =
|
|
8340
|
+
var scheduleRunsContract = c14.router({
|
|
8172
8341
|
/**
|
|
8173
8342
|
* GET /api/agent/schedules/:name/runs
|
|
8174
8343
|
* List recent runs for a schedule
|
|
@@ -8177,12 +8346,12 @@ var scheduleRunsContract = c13.router({
|
|
|
8177
8346
|
method: "GET",
|
|
8178
8347
|
path: "/api/agent/schedules/:name/runs",
|
|
8179
8348
|
headers: authHeadersSchema,
|
|
8180
|
-
pathParams:
|
|
8181
|
-
name:
|
|
8349
|
+
pathParams: z21.object({
|
|
8350
|
+
name: z21.string().min(1, "Schedule name required")
|
|
8182
8351
|
}),
|
|
8183
|
-
query:
|
|
8184
|
-
composeId:
|
|
8185
|
-
limit:
|
|
8352
|
+
query: z21.object({
|
|
8353
|
+
composeId: z21.string().uuid("Compose ID required"),
|
|
8354
|
+
limit: z21.coerce.number().min(0).max(100).default(5)
|
|
8186
8355
|
}),
|
|
8187
8356
|
responses: {
|
|
8188
8357
|
200: scheduleRunsResponseSchema,
|
|
@@ -8194,18 +8363,18 @@ var scheduleRunsContract = c13.router({
|
|
|
8194
8363
|
});
|
|
8195
8364
|
|
|
8196
8365
|
// ../../packages/core/src/contracts/realtime.ts
|
|
8197
|
-
import { z as
|
|
8198
|
-
var
|
|
8199
|
-
var ablyTokenRequestSchema =
|
|
8200
|
-
keyName:
|
|
8201
|
-
ttl:
|
|
8202
|
-
timestamp:
|
|
8203
|
-
capability:
|
|
8204
|
-
clientId:
|
|
8205
|
-
nonce:
|
|
8206
|
-
mac:
|
|
8366
|
+
import { z as z22 } from "zod";
|
|
8367
|
+
var c15 = initContract();
|
|
8368
|
+
var ablyTokenRequestSchema = z22.object({
|
|
8369
|
+
keyName: z22.string(),
|
|
8370
|
+
ttl: z22.number().optional(),
|
|
8371
|
+
timestamp: z22.number(),
|
|
8372
|
+
capability: z22.string(),
|
|
8373
|
+
clientId: z22.string().optional(),
|
|
8374
|
+
nonce: z22.string(),
|
|
8375
|
+
mac: z22.string()
|
|
8207
8376
|
});
|
|
8208
|
-
var realtimeTokenContract =
|
|
8377
|
+
var realtimeTokenContract = c15.router({
|
|
8209
8378
|
/**
|
|
8210
8379
|
* POST /api/realtime/token
|
|
8211
8380
|
* Get an Ably token to subscribe to a run's events channel
|
|
@@ -8214,8 +8383,8 @@ var realtimeTokenContract = c14.router({
|
|
|
8214
8383
|
method: "POST",
|
|
8215
8384
|
path: "/api/realtime/token",
|
|
8216
8385
|
headers: authHeadersSchema,
|
|
8217
|
-
body:
|
|
8218
|
-
runId:
|
|
8386
|
+
body: z22.object({
|
|
8387
|
+
runId: z22.string().uuid("runId must be a valid UUID")
|
|
8219
8388
|
}),
|
|
8220
8389
|
responses: {
|
|
8221
8390
|
200: ablyTokenRequestSchema,
|
|
@@ -8227,7 +8396,7 @@ var realtimeTokenContract = c14.router({
|
|
|
8227
8396
|
summary: "Get Ably token for run event subscription"
|
|
8228
8397
|
}
|
|
8229
8398
|
});
|
|
8230
|
-
var runnerRealtimeTokenContract =
|
|
8399
|
+
var runnerRealtimeTokenContract = c15.router({
|
|
8231
8400
|
/**
|
|
8232
8401
|
* POST /api/runners/realtime/token
|
|
8233
8402
|
* Get an Ably token to subscribe to a runner group's job notification channel
|
|
@@ -8236,7 +8405,7 @@ var runnerRealtimeTokenContract = c14.router({
|
|
|
8236
8405
|
method: "POST",
|
|
8237
8406
|
path: "/api/runners/realtime/token",
|
|
8238
8407
|
headers: authHeadersSchema,
|
|
8239
|
-
body:
|
|
8408
|
+
body: z22.object({
|
|
8240
8409
|
group: runnerGroupSchema
|
|
8241
8410
|
}),
|
|
8242
8411
|
responses: {
|
|
@@ -8250,11 +8419,11 @@ var runnerRealtimeTokenContract = c14.router({
|
|
|
8250
8419
|
});
|
|
8251
8420
|
|
|
8252
8421
|
// ../../packages/core/src/contracts/platform.ts
|
|
8253
|
-
import { z as
|
|
8422
|
+
import { z as z24 } from "zod";
|
|
8254
8423
|
|
|
8255
8424
|
// ../../packages/core/src/contracts/public/common.ts
|
|
8256
|
-
import { z as
|
|
8257
|
-
var publicApiErrorTypeSchema =
|
|
8425
|
+
import { z as z23 } from "zod";
|
|
8426
|
+
var publicApiErrorTypeSchema = z23.enum([
|
|
8258
8427
|
"api_error",
|
|
8259
8428
|
// Internal server error (5xx)
|
|
8260
8429
|
"invalid_request_error",
|
|
@@ -8268,40 +8437,40 @@ var publicApiErrorTypeSchema = z22.enum([
|
|
|
8268
8437
|
"rate_limit_error"
|
|
8269
8438
|
// Rate limit exceeded (429)
|
|
8270
8439
|
]);
|
|
8271
|
-
var publicApiErrorSchema =
|
|
8272
|
-
error:
|
|
8440
|
+
var publicApiErrorSchema = z23.object({
|
|
8441
|
+
error: z23.object({
|
|
8273
8442
|
type: publicApiErrorTypeSchema,
|
|
8274
|
-
code:
|
|
8275
|
-
message:
|
|
8276
|
-
param:
|
|
8277
|
-
docUrl:
|
|
8443
|
+
code: z23.string(),
|
|
8444
|
+
message: z23.string(),
|
|
8445
|
+
param: z23.string().optional(),
|
|
8446
|
+
docUrl: z23.string().url().optional()
|
|
8278
8447
|
})
|
|
8279
8448
|
});
|
|
8280
|
-
var paginationSchema =
|
|
8281
|
-
hasMore:
|
|
8282
|
-
nextCursor:
|
|
8449
|
+
var paginationSchema = z23.object({
|
|
8450
|
+
hasMore: z23.boolean(),
|
|
8451
|
+
nextCursor: z23.string().nullable()
|
|
8283
8452
|
});
|
|
8284
8453
|
function createPaginatedResponseSchema(dataSchema) {
|
|
8285
|
-
return
|
|
8286
|
-
data:
|
|
8454
|
+
return z23.object({
|
|
8455
|
+
data: z23.array(dataSchema),
|
|
8287
8456
|
pagination: paginationSchema
|
|
8288
8457
|
});
|
|
8289
8458
|
}
|
|
8290
|
-
var listQuerySchema =
|
|
8291
|
-
cursor:
|
|
8292
|
-
limit:
|
|
8459
|
+
var listQuerySchema = z23.object({
|
|
8460
|
+
cursor: z23.string().optional(),
|
|
8461
|
+
limit: z23.coerce.number().min(1).max(100).default(20)
|
|
8293
8462
|
});
|
|
8294
|
-
var requestIdSchema =
|
|
8295
|
-
var timestampSchema =
|
|
8463
|
+
var requestIdSchema = z23.string().uuid();
|
|
8464
|
+
var timestampSchema = z23.string().datetime();
|
|
8296
8465
|
|
|
8297
8466
|
// ../../packages/core/src/contracts/platform.ts
|
|
8298
|
-
var
|
|
8299
|
-
var platformPaginationSchema =
|
|
8300
|
-
hasMore:
|
|
8301
|
-
nextCursor:
|
|
8302
|
-
totalPages:
|
|
8467
|
+
var c16 = initContract();
|
|
8468
|
+
var platformPaginationSchema = z24.object({
|
|
8469
|
+
hasMore: z24.boolean(),
|
|
8470
|
+
nextCursor: z24.string().nullable(),
|
|
8471
|
+
totalPages: z24.number()
|
|
8303
8472
|
});
|
|
8304
|
-
var platformLogStatusSchema =
|
|
8473
|
+
var platformLogStatusSchema = z24.enum([
|
|
8305
8474
|
"pending",
|
|
8306
8475
|
"running",
|
|
8307
8476
|
"completed",
|
|
@@ -8309,41 +8478,41 @@ var platformLogStatusSchema = z23.enum([
|
|
|
8309
8478
|
"timeout",
|
|
8310
8479
|
"cancelled"
|
|
8311
8480
|
]);
|
|
8312
|
-
var platformLogEntrySchema =
|
|
8313
|
-
id:
|
|
8314
|
-
sessionId:
|
|
8315
|
-
agentName:
|
|
8316
|
-
framework:
|
|
8481
|
+
var platformLogEntrySchema = z24.object({
|
|
8482
|
+
id: z24.string().uuid(),
|
|
8483
|
+
sessionId: z24.string().nullable(),
|
|
8484
|
+
agentName: z24.string(),
|
|
8485
|
+
framework: z24.string().nullable(),
|
|
8317
8486
|
status: platformLogStatusSchema,
|
|
8318
|
-
createdAt:
|
|
8487
|
+
createdAt: z24.string()
|
|
8319
8488
|
});
|
|
8320
|
-
var platformLogsListResponseSchema =
|
|
8321
|
-
data:
|
|
8489
|
+
var platformLogsListResponseSchema = z24.object({
|
|
8490
|
+
data: z24.array(platformLogEntrySchema),
|
|
8322
8491
|
pagination: platformPaginationSchema
|
|
8323
8492
|
});
|
|
8324
|
-
var artifactSchema =
|
|
8325
|
-
name:
|
|
8326
|
-
version:
|
|
8493
|
+
var artifactSchema = z24.object({
|
|
8494
|
+
name: z24.string().nullable(),
|
|
8495
|
+
version: z24.string().nullable()
|
|
8327
8496
|
});
|
|
8328
|
-
var platformLogDetailSchema =
|
|
8329
|
-
id:
|
|
8330
|
-
sessionId:
|
|
8331
|
-
agentName:
|
|
8332
|
-
framework:
|
|
8497
|
+
var platformLogDetailSchema = z24.object({
|
|
8498
|
+
id: z24.string().uuid(),
|
|
8499
|
+
sessionId: z24.string().nullable(),
|
|
8500
|
+
agentName: z24.string(),
|
|
8501
|
+
framework: z24.string().nullable(),
|
|
8333
8502
|
status: platformLogStatusSchema,
|
|
8334
|
-
prompt:
|
|
8335
|
-
error:
|
|
8336
|
-
createdAt:
|
|
8337
|
-
startedAt:
|
|
8338
|
-
completedAt:
|
|
8503
|
+
prompt: z24.string(),
|
|
8504
|
+
error: z24.string().nullable(),
|
|
8505
|
+
createdAt: z24.string(),
|
|
8506
|
+
startedAt: z24.string().nullable(),
|
|
8507
|
+
completedAt: z24.string().nullable(),
|
|
8339
8508
|
artifact: artifactSchema
|
|
8340
8509
|
});
|
|
8341
|
-
var platformLogsListContract =
|
|
8510
|
+
var platformLogsListContract = c16.router({
|
|
8342
8511
|
list: {
|
|
8343
8512
|
method: "GET",
|
|
8344
8513
|
path: "/api/platform/logs",
|
|
8345
8514
|
query: listQuerySchema.extend({
|
|
8346
|
-
search:
|
|
8515
|
+
search: z24.string().optional()
|
|
8347
8516
|
}),
|
|
8348
8517
|
responses: {
|
|
8349
8518
|
200: platformLogsListResponseSchema,
|
|
@@ -8352,12 +8521,12 @@ var platformLogsListContract = c15.router({
|
|
|
8352
8521
|
summary: "List agent run logs with pagination"
|
|
8353
8522
|
}
|
|
8354
8523
|
});
|
|
8355
|
-
var platformLogsByIdContract =
|
|
8524
|
+
var platformLogsByIdContract = c16.router({
|
|
8356
8525
|
getById: {
|
|
8357
8526
|
method: "GET",
|
|
8358
8527
|
path: "/api/platform/logs/:id",
|
|
8359
|
-
pathParams:
|
|
8360
|
-
id:
|
|
8528
|
+
pathParams: z24.object({
|
|
8529
|
+
id: z24.string().uuid("Invalid log ID")
|
|
8361
8530
|
}),
|
|
8362
8531
|
responses: {
|
|
8363
8532
|
200: platformLogDetailSchema,
|
|
@@ -8367,17 +8536,17 @@ var platformLogsByIdContract = c15.router({
|
|
|
8367
8536
|
summary: "Get agent run log details by ID"
|
|
8368
8537
|
}
|
|
8369
8538
|
});
|
|
8370
|
-
var artifactDownloadResponseSchema =
|
|
8371
|
-
url:
|
|
8372
|
-
expiresAt:
|
|
8539
|
+
var artifactDownloadResponseSchema = z24.object({
|
|
8540
|
+
url: z24.string().url(),
|
|
8541
|
+
expiresAt: z24.string()
|
|
8373
8542
|
});
|
|
8374
|
-
var platformArtifactDownloadContract =
|
|
8543
|
+
var platformArtifactDownloadContract = c16.router({
|
|
8375
8544
|
getDownloadUrl: {
|
|
8376
8545
|
method: "GET",
|
|
8377
8546
|
path: "/api/platform/artifacts/download",
|
|
8378
|
-
query:
|
|
8379
|
-
name:
|
|
8380
|
-
version:
|
|
8547
|
+
query: z24.object({
|
|
8548
|
+
name: z24.string().min(1, "Artifact name is required"),
|
|
8549
|
+
version: z24.string().optional()
|
|
8381
8550
|
}),
|
|
8382
8551
|
responses: {
|
|
8383
8552
|
200: artifactDownloadResponseSchema,
|
|
@@ -8389,29 +8558,29 @@ var platformArtifactDownloadContract = c15.router({
|
|
|
8389
8558
|
});
|
|
8390
8559
|
|
|
8391
8560
|
// ../../packages/core/src/contracts/llm.ts
|
|
8392
|
-
import { z as
|
|
8393
|
-
var
|
|
8394
|
-
var messageRoleSchema =
|
|
8395
|
-
var chatMessageSchema =
|
|
8561
|
+
import { z as z25 } from "zod";
|
|
8562
|
+
var c17 = initContract();
|
|
8563
|
+
var messageRoleSchema = z25.enum(["user", "assistant", "system"]);
|
|
8564
|
+
var chatMessageSchema = z25.object({
|
|
8396
8565
|
role: messageRoleSchema,
|
|
8397
|
-
content:
|
|
8566
|
+
content: z25.string()
|
|
8398
8567
|
});
|
|
8399
|
-
var tokenUsageSchema =
|
|
8400
|
-
promptTokens:
|
|
8401
|
-
completionTokens:
|
|
8402
|
-
totalTokens:
|
|
8568
|
+
var tokenUsageSchema = z25.object({
|
|
8569
|
+
promptTokens: z25.number(),
|
|
8570
|
+
completionTokens: z25.number(),
|
|
8571
|
+
totalTokens: z25.number()
|
|
8403
8572
|
});
|
|
8404
|
-
var llmChatRequestSchema =
|
|
8405
|
-
model:
|
|
8406
|
-
messages:
|
|
8407
|
-
stream:
|
|
8573
|
+
var llmChatRequestSchema = z25.object({
|
|
8574
|
+
model: z25.string().min(1).optional(),
|
|
8575
|
+
messages: z25.array(chatMessageSchema).min(1, "At least one message is required"),
|
|
8576
|
+
stream: z25.boolean().optional().default(false)
|
|
8408
8577
|
});
|
|
8409
|
-
var llmChatResponseSchema =
|
|
8410
|
-
content:
|
|
8411
|
-
model:
|
|
8578
|
+
var llmChatResponseSchema = z25.object({
|
|
8579
|
+
content: z25.string(),
|
|
8580
|
+
model: z25.string(),
|
|
8412
8581
|
usage: tokenUsageSchema
|
|
8413
8582
|
});
|
|
8414
|
-
var llmChatContract =
|
|
8583
|
+
var llmChatContract = c17.router({
|
|
8415
8584
|
chat: {
|
|
8416
8585
|
method: "POST",
|
|
8417
8586
|
path: "/api/llm/chat",
|
|
@@ -8427,28 +8596,28 @@ var llmChatContract = c16.router({
|
|
|
8427
8596
|
});
|
|
8428
8597
|
|
|
8429
8598
|
// ../../packages/core/src/contracts/public/agents.ts
|
|
8430
|
-
import { z as
|
|
8431
|
-
var
|
|
8432
|
-
var publicAgentSchema =
|
|
8433
|
-
id:
|
|
8434
|
-
name:
|
|
8435
|
-
currentVersionId:
|
|
8599
|
+
import { z as z26 } from "zod";
|
|
8600
|
+
var c18 = initContract();
|
|
8601
|
+
var publicAgentSchema = z26.object({
|
|
8602
|
+
id: z26.string(),
|
|
8603
|
+
name: z26.string(),
|
|
8604
|
+
currentVersionId: z26.string().nullable(),
|
|
8436
8605
|
createdAt: timestampSchema,
|
|
8437
8606
|
updatedAt: timestampSchema
|
|
8438
8607
|
});
|
|
8439
|
-
var agentVersionSchema =
|
|
8440
|
-
id:
|
|
8441
|
-
agentId:
|
|
8442
|
-
versionNumber:
|
|
8608
|
+
var agentVersionSchema = z26.object({
|
|
8609
|
+
id: z26.string(),
|
|
8610
|
+
agentId: z26.string(),
|
|
8611
|
+
versionNumber: z26.number(),
|
|
8443
8612
|
createdAt: timestampSchema
|
|
8444
8613
|
});
|
|
8445
8614
|
var publicAgentDetailSchema = publicAgentSchema;
|
|
8446
8615
|
var paginatedAgentsSchema = createPaginatedResponseSchema(publicAgentSchema);
|
|
8447
8616
|
var paginatedAgentVersionsSchema = createPaginatedResponseSchema(agentVersionSchema);
|
|
8448
8617
|
var agentListQuerySchema = listQuerySchema.extend({
|
|
8449
|
-
name:
|
|
8618
|
+
name: z26.string().optional()
|
|
8450
8619
|
});
|
|
8451
|
-
var publicAgentsListContract =
|
|
8620
|
+
var publicAgentsListContract = c18.router({
|
|
8452
8621
|
list: {
|
|
8453
8622
|
method: "GET",
|
|
8454
8623
|
path: "/v1/agents",
|
|
@@ -8463,13 +8632,13 @@ var publicAgentsListContract = c17.router({
|
|
|
8463
8632
|
description: "List all agents in the current scope with pagination. Use the `name` query parameter to filter by agent name."
|
|
8464
8633
|
}
|
|
8465
8634
|
});
|
|
8466
|
-
var publicAgentByIdContract =
|
|
8635
|
+
var publicAgentByIdContract = c18.router({
|
|
8467
8636
|
get: {
|
|
8468
8637
|
method: "GET",
|
|
8469
8638
|
path: "/v1/agents/:id",
|
|
8470
8639
|
headers: authHeadersSchema,
|
|
8471
|
-
pathParams:
|
|
8472
|
-
id:
|
|
8640
|
+
pathParams: z26.object({
|
|
8641
|
+
id: z26.string().min(1, "Agent ID is required")
|
|
8473
8642
|
}),
|
|
8474
8643
|
responses: {
|
|
8475
8644
|
200: publicAgentDetailSchema,
|
|
@@ -8481,13 +8650,13 @@ var publicAgentByIdContract = c17.router({
|
|
|
8481
8650
|
description: "Get agent details by ID"
|
|
8482
8651
|
}
|
|
8483
8652
|
});
|
|
8484
|
-
var publicAgentVersionsContract =
|
|
8653
|
+
var publicAgentVersionsContract = c18.router({
|
|
8485
8654
|
list: {
|
|
8486
8655
|
method: "GET",
|
|
8487
8656
|
path: "/v1/agents/:id/versions",
|
|
8488
8657
|
headers: authHeadersSchema,
|
|
8489
|
-
pathParams:
|
|
8490
|
-
id:
|
|
8658
|
+
pathParams: z26.object({
|
|
8659
|
+
id: z26.string().min(1, "Agent ID is required")
|
|
8491
8660
|
}),
|
|
8492
8661
|
query: listQuerySchema,
|
|
8493
8662
|
responses: {
|
|
@@ -8502,9 +8671,9 @@ var publicAgentVersionsContract = c17.router({
|
|
|
8502
8671
|
});
|
|
8503
8672
|
|
|
8504
8673
|
// ../../packages/core/src/contracts/public/runs.ts
|
|
8505
|
-
import { z as
|
|
8506
|
-
var
|
|
8507
|
-
var publicRunStatusSchema =
|
|
8674
|
+
import { z as z27 } from "zod";
|
|
8675
|
+
var c19 = initContract();
|
|
8676
|
+
var publicRunStatusSchema = z27.enum([
|
|
8508
8677
|
"pending",
|
|
8509
8678
|
"running",
|
|
8510
8679
|
"completed",
|
|
@@ -8512,54 +8681,54 @@ var publicRunStatusSchema = z26.enum([
|
|
|
8512
8681
|
"timeout",
|
|
8513
8682
|
"cancelled"
|
|
8514
8683
|
]);
|
|
8515
|
-
var publicRunSchema =
|
|
8516
|
-
id:
|
|
8517
|
-
agentId:
|
|
8518
|
-
agentName:
|
|
8684
|
+
var publicRunSchema = z27.object({
|
|
8685
|
+
id: z27.string(),
|
|
8686
|
+
agentId: z27.string(),
|
|
8687
|
+
agentName: z27.string(),
|
|
8519
8688
|
status: publicRunStatusSchema,
|
|
8520
|
-
prompt:
|
|
8689
|
+
prompt: z27.string(),
|
|
8521
8690
|
createdAt: timestampSchema,
|
|
8522
8691
|
startedAt: timestampSchema.nullable(),
|
|
8523
8692
|
completedAt: timestampSchema.nullable()
|
|
8524
8693
|
});
|
|
8525
8694
|
var publicRunDetailSchema = publicRunSchema.extend({
|
|
8526
|
-
error:
|
|
8527
|
-
executionTimeMs:
|
|
8528
|
-
checkpointId:
|
|
8529
|
-
sessionId:
|
|
8530
|
-
artifactName:
|
|
8531
|
-
artifactVersion:
|
|
8532
|
-
volumes:
|
|
8695
|
+
error: z27.string().nullable(),
|
|
8696
|
+
executionTimeMs: z27.number().nullable(),
|
|
8697
|
+
checkpointId: z27.string().nullable(),
|
|
8698
|
+
sessionId: z27.string().nullable(),
|
|
8699
|
+
artifactName: z27.string().nullable(),
|
|
8700
|
+
artifactVersion: z27.string().nullable(),
|
|
8701
|
+
volumes: z27.record(z27.string(), z27.string()).optional()
|
|
8533
8702
|
});
|
|
8534
8703
|
var paginatedRunsSchema = createPaginatedResponseSchema(publicRunSchema);
|
|
8535
|
-
var createRunRequestSchema =
|
|
8704
|
+
var createRunRequestSchema = z27.object({
|
|
8536
8705
|
// Agent identification (one of: agent, agentId, sessionId, checkpointId)
|
|
8537
|
-
agent:
|
|
8706
|
+
agent: z27.string().optional(),
|
|
8538
8707
|
// Agent name
|
|
8539
|
-
agentId:
|
|
8708
|
+
agentId: z27.string().optional(),
|
|
8540
8709
|
// Agent ID
|
|
8541
|
-
agentVersion:
|
|
8710
|
+
agentVersion: z27.string().optional(),
|
|
8542
8711
|
// Version specifier (e.g., "latest", "v1", specific ID)
|
|
8543
8712
|
// Continue session
|
|
8544
|
-
sessionId:
|
|
8713
|
+
sessionId: z27.string().optional(),
|
|
8545
8714
|
// Resume from checkpoint
|
|
8546
|
-
checkpointId:
|
|
8715
|
+
checkpointId: z27.string().optional(),
|
|
8547
8716
|
// Required
|
|
8548
|
-
prompt:
|
|
8717
|
+
prompt: z27.string().min(1, "Prompt is required"),
|
|
8549
8718
|
// Optional configuration
|
|
8550
|
-
variables:
|
|
8551
|
-
secrets:
|
|
8552
|
-
artifactName:
|
|
8719
|
+
variables: z27.record(z27.string(), z27.string()).optional(),
|
|
8720
|
+
secrets: z27.record(z27.string(), z27.string()).optional(),
|
|
8721
|
+
artifactName: z27.string().optional(),
|
|
8553
8722
|
// Artifact name to mount
|
|
8554
|
-
artifactVersion:
|
|
8723
|
+
artifactVersion: z27.string().optional(),
|
|
8555
8724
|
// Artifact version (defaults to latest)
|
|
8556
|
-
volumes:
|
|
8725
|
+
volumes: z27.record(z27.string(), z27.string()).optional()
|
|
8557
8726
|
// volume_name -> version
|
|
8558
8727
|
});
|
|
8559
8728
|
var runListQuerySchema = listQuerySchema.extend({
|
|
8560
8729
|
status: publicRunStatusSchema.optional()
|
|
8561
8730
|
});
|
|
8562
|
-
var publicRunsListContract =
|
|
8731
|
+
var publicRunsListContract = c19.router({
|
|
8563
8732
|
list: {
|
|
8564
8733
|
method: "GET",
|
|
8565
8734
|
path: "/v1/runs",
|
|
@@ -8591,13 +8760,13 @@ var publicRunsListContract = c18.router({
|
|
|
8591
8760
|
description: "Create and execute a new agent run. Returns 202 Accepted as runs execute asynchronously."
|
|
8592
8761
|
}
|
|
8593
8762
|
});
|
|
8594
|
-
var publicRunByIdContract =
|
|
8763
|
+
var publicRunByIdContract = c19.router({
|
|
8595
8764
|
get: {
|
|
8596
8765
|
method: "GET",
|
|
8597
8766
|
path: "/v1/runs/:id",
|
|
8598
8767
|
headers: authHeadersSchema,
|
|
8599
|
-
pathParams:
|
|
8600
|
-
id:
|
|
8768
|
+
pathParams: z27.object({
|
|
8769
|
+
id: z27.string().min(1, "Run ID is required")
|
|
8601
8770
|
}),
|
|
8602
8771
|
responses: {
|
|
8603
8772
|
200: publicRunDetailSchema,
|
|
@@ -8609,15 +8778,15 @@ var publicRunByIdContract = c18.router({
|
|
|
8609
8778
|
description: "Get run details by ID"
|
|
8610
8779
|
}
|
|
8611
8780
|
});
|
|
8612
|
-
var publicRunCancelContract =
|
|
8781
|
+
var publicRunCancelContract = c19.router({
|
|
8613
8782
|
cancel: {
|
|
8614
8783
|
method: "POST",
|
|
8615
8784
|
path: "/v1/runs/:id/cancel",
|
|
8616
8785
|
headers: authHeadersSchema,
|
|
8617
|
-
pathParams:
|
|
8618
|
-
id:
|
|
8786
|
+
pathParams: z27.object({
|
|
8787
|
+
id: z27.string().min(1, "Run ID is required")
|
|
8619
8788
|
}),
|
|
8620
|
-
body:
|
|
8789
|
+
body: z27.undefined(),
|
|
8621
8790
|
responses: {
|
|
8622
8791
|
200: publicRunDetailSchema,
|
|
8623
8792
|
400: publicApiErrorSchema,
|
|
@@ -8630,27 +8799,27 @@ var publicRunCancelContract = c18.router({
|
|
|
8630
8799
|
description: "Cancel a pending or running execution"
|
|
8631
8800
|
}
|
|
8632
8801
|
});
|
|
8633
|
-
var logEntrySchema =
|
|
8802
|
+
var logEntrySchema = z27.object({
|
|
8634
8803
|
timestamp: timestampSchema,
|
|
8635
|
-
type:
|
|
8636
|
-
level:
|
|
8637
|
-
message:
|
|
8638
|
-
metadata:
|
|
8804
|
+
type: z27.enum(["agent", "system", "network"]),
|
|
8805
|
+
level: z27.enum(["debug", "info", "warn", "error"]),
|
|
8806
|
+
message: z27.string(),
|
|
8807
|
+
metadata: z27.record(z27.string(), z27.unknown()).optional()
|
|
8639
8808
|
});
|
|
8640
8809
|
var paginatedLogsSchema = createPaginatedResponseSchema(logEntrySchema);
|
|
8641
8810
|
var logsQuerySchema = listQuerySchema.extend({
|
|
8642
|
-
type:
|
|
8811
|
+
type: z27.enum(["agent", "system", "network", "all"]).default("all"),
|
|
8643
8812
|
since: timestampSchema.optional(),
|
|
8644
8813
|
until: timestampSchema.optional(),
|
|
8645
|
-
order:
|
|
8814
|
+
order: z27.enum(["asc", "desc"]).default("asc")
|
|
8646
8815
|
});
|
|
8647
|
-
var publicRunLogsContract =
|
|
8816
|
+
var publicRunLogsContract = c19.router({
|
|
8648
8817
|
getLogs: {
|
|
8649
8818
|
method: "GET",
|
|
8650
8819
|
path: "/v1/runs/:id/logs",
|
|
8651
8820
|
headers: authHeadersSchema,
|
|
8652
|
-
pathParams:
|
|
8653
|
-
id:
|
|
8821
|
+
pathParams: z27.object({
|
|
8822
|
+
id: z27.string().min(1, "Run ID is required")
|
|
8654
8823
|
}),
|
|
8655
8824
|
query: logsQuerySchema,
|
|
8656
8825
|
responses: {
|
|
@@ -8663,30 +8832,30 @@ var publicRunLogsContract = c18.router({
|
|
|
8663
8832
|
description: "Get unified logs for a run. Combines agent, system, and network logs."
|
|
8664
8833
|
}
|
|
8665
8834
|
});
|
|
8666
|
-
var metricPointSchema =
|
|
8835
|
+
var metricPointSchema = z27.object({
|
|
8667
8836
|
timestamp: timestampSchema,
|
|
8668
|
-
cpuPercent:
|
|
8669
|
-
memoryUsedMb:
|
|
8670
|
-
memoryTotalMb:
|
|
8671
|
-
diskUsedMb:
|
|
8672
|
-
diskTotalMb:
|
|
8673
|
-
});
|
|
8674
|
-
var metricsSummarySchema =
|
|
8675
|
-
avgCpuPercent:
|
|
8676
|
-
maxMemoryUsedMb:
|
|
8677
|
-
totalDurationMs:
|
|
8678
|
-
});
|
|
8679
|
-
var metricsResponseSchema2 =
|
|
8680
|
-
data:
|
|
8837
|
+
cpuPercent: z27.number(),
|
|
8838
|
+
memoryUsedMb: z27.number(),
|
|
8839
|
+
memoryTotalMb: z27.number(),
|
|
8840
|
+
diskUsedMb: z27.number(),
|
|
8841
|
+
diskTotalMb: z27.number()
|
|
8842
|
+
});
|
|
8843
|
+
var metricsSummarySchema = z27.object({
|
|
8844
|
+
avgCpuPercent: z27.number(),
|
|
8845
|
+
maxMemoryUsedMb: z27.number(),
|
|
8846
|
+
totalDurationMs: z27.number().nullable()
|
|
8847
|
+
});
|
|
8848
|
+
var metricsResponseSchema2 = z27.object({
|
|
8849
|
+
data: z27.array(metricPointSchema),
|
|
8681
8850
|
summary: metricsSummarySchema
|
|
8682
8851
|
});
|
|
8683
|
-
var publicRunMetricsContract =
|
|
8852
|
+
var publicRunMetricsContract = c19.router({
|
|
8684
8853
|
getMetrics: {
|
|
8685
8854
|
method: "GET",
|
|
8686
8855
|
path: "/v1/runs/:id/metrics",
|
|
8687
8856
|
headers: authHeadersSchema,
|
|
8688
|
-
pathParams:
|
|
8689
|
-
id:
|
|
8857
|
+
pathParams: z27.object({
|
|
8858
|
+
id: z27.string().min(1, "Run ID is required")
|
|
8690
8859
|
}),
|
|
8691
8860
|
responses: {
|
|
8692
8861
|
200: metricsResponseSchema2,
|
|
@@ -8698,7 +8867,7 @@ var publicRunMetricsContract = c18.router({
|
|
|
8698
8867
|
description: "Get CPU, memory, and disk metrics for a run"
|
|
8699
8868
|
}
|
|
8700
8869
|
});
|
|
8701
|
-
var sseEventTypeSchema =
|
|
8870
|
+
var sseEventTypeSchema = z27.enum([
|
|
8702
8871
|
"status",
|
|
8703
8872
|
// Run status change
|
|
8704
8873
|
"output",
|
|
@@ -8710,26 +8879,26 @@ var sseEventTypeSchema = z26.enum([
|
|
|
8710
8879
|
"heartbeat"
|
|
8711
8880
|
// Keep-alive
|
|
8712
8881
|
]);
|
|
8713
|
-
var sseEventSchema =
|
|
8882
|
+
var sseEventSchema = z27.object({
|
|
8714
8883
|
event: sseEventTypeSchema,
|
|
8715
|
-
data:
|
|
8716
|
-
id:
|
|
8884
|
+
data: z27.unknown(),
|
|
8885
|
+
id: z27.string().optional()
|
|
8717
8886
|
// For Last-Event-ID reconnection
|
|
8718
8887
|
});
|
|
8719
|
-
var publicRunEventsContract =
|
|
8888
|
+
var publicRunEventsContract = c19.router({
|
|
8720
8889
|
streamEvents: {
|
|
8721
8890
|
method: "GET",
|
|
8722
8891
|
path: "/v1/runs/:id/events",
|
|
8723
8892
|
headers: authHeadersSchema,
|
|
8724
|
-
pathParams:
|
|
8725
|
-
id:
|
|
8893
|
+
pathParams: z27.object({
|
|
8894
|
+
id: z27.string().min(1, "Run ID is required")
|
|
8726
8895
|
}),
|
|
8727
|
-
query:
|
|
8728
|
-
lastEventId:
|
|
8896
|
+
query: z27.object({
|
|
8897
|
+
lastEventId: z27.string().optional()
|
|
8729
8898
|
// For reconnection
|
|
8730
8899
|
}),
|
|
8731
8900
|
responses: {
|
|
8732
|
-
200:
|
|
8901
|
+
200: z27.any(),
|
|
8733
8902
|
// SSE stream - actual content is text/event-stream
|
|
8734
8903
|
401: publicApiErrorSchema,
|
|
8735
8904
|
404: publicApiErrorSchema,
|
|
@@ -8741,28 +8910,28 @@ var publicRunEventsContract = c18.router({
|
|
|
8741
8910
|
});
|
|
8742
8911
|
|
|
8743
8912
|
// ../../packages/core/src/contracts/public/artifacts.ts
|
|
8744
|
-
import { z as
|
|
8745
|
-
var
|
|
8746
|
-
var publicArtifactSchema =
|
|
8747
|
-
id:
|
|
8748
|
-
name:
|
|
8749
|
-
currentVersionId:
|
|
8750
|
-
size:
|
|
8913
|
+
import { z as z28 } from "zod";
|
|
8914
|
+
var c20 = initContract();
|
|
8915
|
+
var publicArtifactSchema = z28.object({
|
|
8916
|
+
id: z28.string(),
|
|
8917
|
+
name: z28.string(),
|
|
8918
|
+
currentVersionId: z28.string().nullable(),
|
|
8919
|
+
size: z28.number(),
|
|
8751
8920
|
// Total size in bytes
|
|
8752
|
-
fileCount:
|
|
8921
|
+
fileCount: z28.number(),
|
|
8753
8922
|
createdAt: timestampSchema,
|
|
8754
8923
|
updatedAt: timestampSchema
|
|
8755
8924
|
});
|
|
8756
|
-
var artifactVersionSchema =
|
|
8757
|
-
id:
|
|
8925
|
+
var artifactVersionSchema = z28.object({
|
|
8926
|
+
id: z28.string(),
|
|
8758
8927
|
// SHA-256 content hash
|
|
8759
|
-
artifactId:
|
|
8760
|
-
size:
|
|
8928
|
+
artifactId: z28.string(),
|
|
8929
|
+
size: z28.number(),
|
|
8761
8930
|
// Size in bytes
|
|
8762
|
-
fileCount:
|
|
8763
|
-
message:
|
|
8931
|
+
fileCount: z28.number(),
|
|
8932
|
+
message: z28.string().nullable(),
|
|
8764
8933
|
// Optional commit message
|
|
8765
|
-
createdBy:
|
|
8934
|
+
createdBy: z28.string(),
|
|
8766
8935
|
createdAt: timestampSchema
|
|
8767
8936
|
});
|
|
8768
8937
|
var publicArtifactDetailSchema = publicArtifactSchema.extend({
|
|
@@ -8772,7 +8941,7 @@ var paginatedArtifactsSchema = createPaginatedResponseSchema(publicArtifactSchem
|
|
|
8772
8941
|
var paginatedArtifactVersionsSchema = createPaginatedResponseSchema(
|
|
8773
8942
|
artifactVersionSchema
|
|
8774
8943
|
);
|
|
8775
|
-
var publicArtifactsListContract =
|
|
8944
|
+
var publicArtifactsListContract = c20.router({
|
|
8776
8945
|
list: {
|
|
8777
8946
|
method: "GET",
|
|
8778
8947
|
path: "/v1/artifacts",
|
|
@@ -8787,13 +8956,13 @@ var publicArtifactsListContract = c19.router({
|
|
|
8787
8956
|
description: "List all artifacts in the current scope with pagination"
|
|
8788
8957
|
}
|
|
8789
8958
|
});
|
|
8790
|
-
var publicArtifactByIdContract =
|
|
8959
|
+
var publicArtifactByIdContract = c20.router({
|
|
8791
8960
|
get: {
|
|
8792
8961
|
method: "GET",
|
|
8793
8962
|
path: "/v1/artifacts/:id",
|
|
8794
8963
|
headers: authHeadersSchema,
|
|
8795
|
-
pathParams:
|
|
8796
|
-
id:
|
|
8964
|
+
pathParams: z28.object({
|
|
8965
|
+
id: z28.string().min(1, "Artifact ID is required")
|
|
8797
8966
|
}),
|
|
8798
8967
|
responses: {
|
|
8799
8968
|
200: publicArtifactDetailSchema,
|
|
@@ -8805,13 +8974,13 @@ var publicArtifactByIdContract = c19.router({
|
|
|
8805
8974
|
description: "Get artifact details by ID"
|
|
8806
8975
|
}
|
|
8807
8976
|
});
|
|
8808
|
-
var publicArtifactVersionsContract =
|
|
8977
|
+
var publicArtifactVersionsContract = c20.router({
|
|
8809
8978
|
list: {
|
|
8810
8979
|
method: "GET",
|
|
8811
8980
|
path: "/v1/artifacts/:id/versions",
|
|
8812
8981
|
headers: authHeadersSchema,
|
|
8813
|
-
pathParams:
|
|
8814
|
-
id:
|
|
8982
|
+
pathParams: z28.object({
|
|
8983
|
+
id: z28.string().min(1, "Artifact ID is required")
|
|
8815
8984
|
}),
|
|
8816
8985
|
query: listQuerySchema,
|
|
8817
8986
|
responses: {
|
|
@@ -8824,20 +8993,20 @@ var publicArtifactVersionsContract = c19.router({
|
|
|
8824
8993
|
description: "List all versions of an artifact with pagination"
|
|
8825
8994
|
}
|
|
8826
8995
|
});
|
|
8827
|
-
var publicArtifactDownloadContract =
|
|
8996
|
+
var publicArtifactDownloadContract = c20.router({
|
|
8828
8997
|
download: {
|
|
8829
8998
|
method: "GET",
|
|
8830
8999
|
path: "/v1/artifacts/:id/download",
|
|
8831
9000
|
headers: authHeadersSchema,
|
|
8832
|
-
pathParams:
|
|
8833
|
-
id:
|
|
9001
|
+
pathParams: z28.object({
|
|
9002
|
+
id: z28.string().min(1, "Artifact ID is required")
|
|
8834
9003
|
}),
|
|
8835
|
-
query:
|
|
8836
|
-
versionId:
|
|
9004
|
+
query: z28.object({
|
|
9005
|
+
versionId: z28.string().optional()
|
|
8837
9006
|
// Defaults to current version
|
|
8838
9007
|
}),
|
|
8839
9008
|
responses: {
|
|
8840
|
-
302:
|
|
9009
|
+
302: z28.undefined(),
|
|
8841
9010
|
// Redirect to presigned URL
|
|
8842
9011
|
401: publicApiErrorSchema,
|
|
8843
9012
|
404: publicApiErrorSchema,
|
|
@@ -8849,28 +9018,28 @@ var publicArtifactDownloadContract = c19.router({
|
|
|
8849
9018
|
});
|
|
8850
9019
|
|
|
8851
9020
|
// ../../packages/core/src/contracts/public/volumes.ts
|
|
8852
|
-
import { z as
|
|
8853
|
-
var
|
|
8854
|
-
var publicVolumeSchema =
|
|
8855
|
-
id:
|
|
8856
|
-
name:
|
|
8857
|
-
currentVersionId:
|
|
8858
|
-
size:
|
|
9021
|
+
import { z as z29 } from "zod";
|
|
9022
|
+
var c21 = initContract();
|
|
9023
|
+
var publicVolumeSchema = z29.object({
|
|
9024
|
+
id: z29.string(),
|
|
9025
|
+
name: z29.string(),
|
|
9026
|
+
currentVersionId: z29.string().nullable(),
|
|
9027
|
+
size: z29.number(),
|
|
8859
9028
|
// Total size in bytes
|
|
8860
|
-
fileCount:
|
|
9029
|
+
fileCount: z29.number(),
|
|
8861
9030
|
createdAt: timestampSchema,
|
|
8862
9031
|
updatedAt: timestampSchema
|
|
8863
9032
|
});
|
|
8864
|
-
var volumeVersionSchema =
|
|
8865
|
-
id:
|
|
9033
|
+
var volumeVersionSchema = z29.object({
|
|
9034
|
+
id: z29.string(),
|
|
8866
9035
|
// SHA-256 content hash
|
|
8867
|
-
volumeId:
|
|
8868
|
-
size:
|
|
9036
|
+
volumeId: z29.string(),
|
|
9037
|
+
size: z29.number(),
|
|
8869
9038
|
// Size in bytes
|
|
8870
|
-
fileCount:
|
|
8871
|
-
message:
|
|
9039
|
+
fileCount: z29.number(),
|
|
9040
|
+
message: z29.string().nullable(),
|
|
8872
9041
|
// Optional commit message
|
|
8873
|
-
createdBy:
|
|
9042
|
+
createdBy: z29.string(),
|
|
8874
9043
|
createdAt: timestampSchema
|
|
8875
9044
|
});
|
|
8876
9045
|
var publicVolumeDetailSchema = publicVolumeSchema.extend({
|
|
@@ -8878,7 +9047,7 @@ var publicVolumeDetailSchema = publicVolumeSchema.extend({
|
|
|
8878
9047
|
});
|
|
8879
9048
|
var paginatedVolumesSchema = createPaginatedResponseSchema(publicVolumeSchema);
|
|
8880
9049
|
var paginatedVolumeVersionsSchema = createPaginatedResponseSchema(volumeVersionSchema);
|
|
8881
|
-
var publicVolumesListContract =
|
|
9050
|
+
var publicVolumesListContract = c21.router({
|
|
8882
9051
|
list: {
|
|
8883
9052
|
method: "GET",
|
|
8884
9053
|
path: "/v1/volumes",
|
|
@@ -8893,13 +9062,13 @@ var publicVolumesListContract = c20.router({
|
|
|
8893
9062
|
description: "List all volumes in the current scope with pagination"
|
|
8894
9063
|
}
|
|
8895
9064
|
});
|
|
8896
|
-
var publicVolumeByIdContract =
|
|
9065
|
+
var publicVolumeByIdContract = c21.router({
|
|
8897
9066
|
get: {
|
|
8898
9067
|
method: "GET",
|
|
8899
9068
|
path: "/v1/volumes/:id",
|
|
8900
9069
|
headers: authHeadersSchema,
|
|
8901
|
-
pathParams:
|
|
8902
|
-
id:
|
|
9070
|
+
pathParams: z29.object({
|
|
9071
|
+
id: z29.string().min(1, "Volume ID is required")
|
|
8903
9072
|
}),
|
|
8904
9073
|
responses: {
|
|
8905
9074
|
200: publicVolumeDetailSchema,
|
|
@@ -8911,13 +9080,13 @@ var publicVolumeByIdContract = c20.router({
|
|
|
8911
9080
|
description: "Get volume details by ID"
|
|
8912
9081
|
}
|
|
8913
9082
|
});
|
|
8914
|
-
var publicVolumeVersionsContract =
|
|
9083
|
+
var publicVolumeVersionsContract = c21.router({
|
|
8915
9084
|
list: {
|
|
8916
9085
|
method: "GET",
|
|
8917
9086
|
path: "/v1/volumes/:id/versions",
|
|
8918
9087
|
headers: authHeadersSchema,
|
|
8919
|
-
pathParams:
|
|
8920
|
-
id:
|
|
9088
|
+
pathParams: z29.object({
|
|
9089
|
+
id: z29.string().min(1, "Volume ID is required")
|
|
8921
9090
|
}),
|
|
8922
9091
|
query: listQuerySchema,
|
|
8923
9092
|
responses: {
|
|
@@ -8930,20 +9099,20 @@ var publicVolumeVersionsContract = c20.router({
|
|
|
8930
9099
|
description: "List all versions of a volume with pagination"
|
|
8931
9100
|
}
|
|
8932
9101
|
});
|
|
8933
|
-
var publicVolumeDownloadContract =
|
|
9102
|
+
var publicVolumeDownloadContract = c21.router({
|
|
8934
9103
|
download: {
|
|
8935
9104
|
method: "GET",
|
|
8936
9105
|
path: "/v1/volumes/:id/download",
|
|
8937
9106
|
headers: authHeadersSchema,
|
|
8938
|
-
pathParams:
|
|
8939
|
-
id:
|
|
9107
|
+
pathParams: z29.object({
|
|
9108
|
+
id: z29.string().min(1, "Volume ID is required")
|
|
8940
9109
|
}),
|
|
8941
|
-
query:
|
|
8942
|
-
versionId:
|
|
9110
|
+
query: z29.object({
|
|
9111
|
+
versionId: z29.string().optional()
|
|
8943
9112
|
// Defaults to current version
|
|
8944
9113
|
}),
|
|
8945
9114
|
responses: {
|
|
8946
|
-
302:
|
|
9115
|
+
302: z29.undefined(),
|
|
8947
9116
|
// Redirect to presigned URL
|
|
8948
9117
|
401: publicApiErrorSchema,
|
|
8949
9118
|
404: publicApiErrorSchema,
|
|
@@ -9105,7 +9274,7 @@ function initVMRegistry(registryPath) {
|
|
|
9105
9274
|
// src/lib/proxy/proxy-manager.ts
|
|
9106
9275
|
import { spawn as spawn2 } from "child_process";
|
|
9107
9276
|
import fs7 from "fs";
|
|
9108
|
-
import
|
|
9277
|
+
import path5 from "path";
|
|
9109
9278
|
|
|
9110
9279
|
// src/lib/proxy/mitm-addon-script.ts
|
|
9111
9280
|
var RUNNER_MITM_ADDON_SCRIPT = `#!/usr/bin/env python3
|
|
@@ -9601,7 +9770,7 @@ var ProxyManager = class {
|
|
|
9601
9770
|
process = null;
|
|
9602
9771
|
isRunning = false;
|
|
9603
9772
|
constructor(config) {
|
|
9604
|
-
const addonPath =
|
|
9773
|
+
const addonPath = path5.join(config.caDir, "mitm_addon.py");
|
|
9605
9774
|
this.config = {
|
|
9606
9775
|
...DEFAULT_PROXY_OPTIONS,
|
|
9607
9776
|
...config,
|
|
@@ -9628,7 +9797,7 @@ var ProxyManager = class {
|
|
|
9628
9797
|
* Ensure the addon script exists at the configured path
|
|
9629
9798
|
*/
|
|
9630
9799
|
ensureAddonScript() {
|
|
9631
|
-
const addonDir =
|
|
9800
|
+
const addonDir = path5.dirname(this.config.addonPath);
|
|
9632
9801
|
if (!fs7.existsSync(addonDir)) {
|
|
9633
9802
|
fs7.mkdirSync(addonDir, { recursive: true });
|
|
9634
9803
|
}
|
|
@@ -9644,7 +9813,7 @@ var ProxyManager = class {
|
|
|
9644
9813
|
if (!fs7.existsSync(this.config.caDir)) {
|
|
9645
9814
|
throw new Error(`Proxy CA directory not found: ${this.config.caDir}`);
|
|
9646
9815
|
}
|
|
9647
|
-
const caCertPath =
|
|
9816
|
+
const caCertPath = path5.join(this.config.caDir, "mitmproxy-ca.pem");
|
|
9648
9817
|
if (!fs7.existsSync(caCertPath)) {
|
|
9649
9818
|
throw new Error(`Proxy CA certificate not found: ${caCertPath}`);
|
|
9650
9819
|
}
|
|
@@ -10097,7 +10266,21 @@ async function executeJob(context, config, options = {}) {
|
|
|
10097
10266
|
const guestConnectionPromise = guest.waitForGuestConnection(3e4);
|
|
10098
10267
|
logger9.log(`Creating VM ${vmId}...`);
|
|
10099
10268
|
vm = new FirecrackerVM(vmConfig);
|
|
10100
|
-
|
|
10269
|
+
const snapshotConfig = config.firecracker.snapshot;
|
|
10270
|
+
let snapshotPaths;
|
|
10271
|
+
if (snapshotConfig) {
|
|
10272
|
+
const snapshotDir = path6.dirname(snapshotConfig.snapshot);
|
|
10273
|
+
const originalBaseDir = path6.dirname(snapshotDir);
|
|
10274
|
+
const snapshotBaseDir = runnerPaths.snapshotBaseDir(originalBaseDir);
|
|
10275
|
+
const snapshotWorkDir = runnerPaths.snapshotWorkDir(snapshotBaseDir);
|
|
10276
|
+
snapshotPaths = {
|
|
10277
|
+
snapshot: snapshotConfig.snapshot,
|
|
10278
|
+
memory: snapshotConfig.memory,
|
|
10279
|
+
snapshotOverlay: vmPaths.overlay(snapshotWorkDir),
|
|
10280
|
+
snapshotVsockDir: vmPaths.vsockDir(snapshotWorkDir)
|
|
10281
|
+
};
|
|
10282
|
+
}
|
|
10283
|
+
await withSandboxTiming("vm_create", () => vm.start(snapshotPaths));
|
|
10101
10284
|
guestIp = vm.getGuestIp();
|
|
10102
10285
|
vethNsIp = vm.getNetns()?.vethNsIp ?? null;
|
|
10103
10286
|
if (!guestIp || !vethNsIp) {
|
|
@@ -10125,6 +10308,10 @@ async function executeJob(context, config, options = {}) {
|
|
|
10125
10308
|
logger9.log(`Waiting for guest connection...`);
|
|
10126
10309
|
await withSandboxTiming("guest_wait", () => guestConnectionPromise);
|
|
10127
10310
|
logger9.log(`Guest client ready`);
|
|
10311
|
+
if (config.firecracker.snapshot) {
|
|
10312
|
+
const timestamp = (Date.now() / 1e3).toFixed(3);
|
|
10313
|
+
await guest.exec(`date -s "@${timestamp}"`);
|
|
10314
|
+
}
|
|
10128
10315
|
if (context.storageManifest) {
|
|
10129
10316
|
await withSandboxTiming(
|
|
10130
10317
|
"storage_download",
|
|
@@ -10327,7 +10514,7 @@ async function isPortInUse(port) {
|
|
|
10327
10514
|
|
|
10328
10515
|
// src/lib/runner/runner-lock.ts
|
|
10329
10516
|
import fs10 from "fs";
|
|
10330
|
-
import
|
|
10517
|
+
import path7 from "path";
|
|
10331
10518
|
var logger11 = createLogger("RunnerLock");
|
|
10332
10519
|
var DEFAULT_PID_FILE = runtimePaths.runnerPid;
|
|
10333
10520
|
var currentPidFile = null;
|
|
@@ -10344,7 +10531,7 @@ function isProcessRunning(pid) {
|
|
|
10344
10531
|
}
|
|
10345
10532
|
function acquireRunnerLock(options = {}) {
|
|
10346
10533
|
const pidFile = options.pidFile ?? DEFAULT_PID_FILE;
|
|
10347
|
-
const runDir =
|
|
10534
|
+
const runDir = path7.dirname(pidFile);
|
|
10348
10535
|
fs10.mkdirSync(runDir, { recursive: true });
|
|
10349
10536
|
if (fs10.existsSync(pidFile)) {
|
|
10350
10537
|
const pidStr = fs10.readFileSync(pidFile, "utf-8").trim();
|
|
@@ -10378,7 +10565,7 @@ function releaseRunnerLock() {
|
|
|
10378
10565
|
var logger12 = createLogger("Runner");
|
|
10379
10566
|
async function setupEnvironment(options) {
|
|
10380
10567
|
const { config } = options;
|
|
10381
|
-
|
|
10568
|
+
acquireRunnerLock();
|
|
10382
10569
|
const networkCheck = checkNetworkPrerequisites();
|
|
10383
10570
|
if (!networkCheck.ok) {
|
|
10384
10571
|
logger12.error("Network prerequisites not met:");
|
|
@@ -10408,10 +10595,16 @@ async function setupEnvironment(options) {
|
|
|
10408
10595
|
);
|
|
10409
10596
|
}
|
|
10410
10597
|
logger12.log("Initializing overlay pool...");
|
|
10598
|
+
const snapshotConfig = config.firecracker.snapshot;
|
|
10411
10599
|
await initOverlayPool({
|
|
10412
10600
|
size: config.sandbox.max_concurrent + 2,
|
|
10413
10601
|
replenishThreshold: config.sandbox.max_concurrent,
|
|
10414
|
-
poolDir: runnerPaths.overlayPool(config.base_dir)
|
|
10602
|
+
poolDir: runnerPaths.overlayPool(config.base_dir),
|
|
10603
|
+
createFile: snapshotConfig ? (filePath) => execCommand(
|
|
10604
|
+
`cp --sparse=always "${snapshotConfig.overlay}" "${filePath}"`,
|
|
10605
|
+
false
|
|
10606
|
+
).then(() => {
|
|
10607
|
+
}) : void 0
|
|
10415
10608
|
});
|
|
10416
10609
|
logger12.log("Initializing namespace pool...");
|
|
10417
10610
|
await initNetnsPool({
|
|
@@ -10719,7 +10912,7 @@ import { existsSync as existsSync5, readFileSync as readFileSync3, readdirSync a
|
|
|
10719
10912
|
|
|
10720
10913
|
// src/lib/firecracker/process.ts
|
|
10721
10914
|
import { readdirSync, readFileSync as readFileSync2, existsSync as existsSync4 } from "fs";
|
|
10722
|
-
import
|
|
10915
|
+
import path8 from "path";
|
|
10723
10916
|
function parseFirecrackerCmdline(cmdline) {
|
|
10724
10917
|
const args = cmdline.split("\0");
|
|
10725
10918
|
if (!args[0]?.includes("firecracker")) return null;
|
|
@@ -10752,7 +10945,7 @@ function findFirecrackerProcesses() {
|
|
|
10752
10945
|
for (const entry of entries) {
|
|
10753
10946
|
if (!/^\d+$/.test(entry)) continue;
|
|
10754
10947
|
const pid = parseInt(entry, 10);
|
|
10755
|
-
const cmdlinePath =
|
|
10948
|
+
const cmdlinePath = path8.join(procDir, entry, "cmdline");
|
|
10756
10949
|
if (!existsSync4(cmdlinePath)) continue;
|
|
10757
10950
|
try {
|
|
10758
10951
|
const cmdline = readFileSync2(cmdlinePath, "utf-8");
|
|
@@ -10810,7 +11003,7 @@ function findMitmproxyProcess() {
|
|
|
10810
11003
|
for (const entry of entries) {
|
|
10811
11004
|
if (!/^\d+$/.test(entry)) continue;
|
|
10812
11005
|
const pid = parseInt(entry, 10);
|
|
10813
|
-
const cmdlinePath =
|
|
11006
|
+
const cmdlinePath = path8.join(procDir, entry, "cmdline");
|
|
10814
11007
|
if (!existsSync4(cmdlinePath)) continue;
|
|
10815
11008
|
try {
|
|
10816
11009
|
const cmdline = readFileSync2(cmdlinePath, "utf-8");
|
|
@@ -10826,142 +11019,127 @@ function findMitmproxyProcess() {
|
|
|
10826
11019
|
}
|
|
10827
11020
|
|
|
10828
11021
|
// src/commands/doctor.ts
|
|
10829
|
-
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
10839
|
-
|
|
10840
|
-
|
|
10841
|
-
|
|
10842
|
-
|
|
10843
|
-
console.log(`Mode: ${status.mode}`);
|
|
10844
|
-
if (status.started_at) {
|
|
10845
|
-
const started = new Date(status.started_at);
|
|
10846
|
-
const uptime = formatUptime(Date.now() - started.getTime());
|
|
10847
|
-
console.log(
|
|
10848
|
-
`Started: ${started.toLocaleString()} (uptime: ${uptime})`
|
|
10849
|
-
);
|
|
10850
|
-
}
|
|
10851
|
-
} catch {
|
|
10852
|
-
console.log("Mode: unknown (status.json unreadable)");
|
|
10853
|
-
}
|
|
10854
|
-
} else {
|
|
10855
|
-
console.log("Mode: unknown (no status.json)");
|
|
10856
|
-
}
|
|
10857
|
-
console.log("");
|
|
10858
|
-
console.log("API Connectivity:");
|
|
10859
|
-
try {
|
|
10860
|
-
await pollForJob(config.server, config.group);
|
|
10861
|
-
console.log(` \u2713 Connected to ${config.server.url}`);
|
|
10862
|
-
console.log(" \u2713 Authentication: OK");
|
|
10863
|
-
} catch (error) {
|
|
10864
|
-
console.log(` \u2717 Cannot connect to ${config.server.url}`);
|
|
10865
|
-
console.log(
|
|
10866
|
-
` Error: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
10867
|
-
);
|
|
10868
|
-
}
|
|
10869
|
-
console.log("");
|
|
10870
|
-
console.log("Network:");
|
|
10871
|
-
const warnings = [];
|
|
10872
|
-
const proxyPort = config.proxy.port;
|
|
10873
|
-
const mitmProc = findMitmproxyProcess();
|
|
10874
|
-
const portInUse = await isPortInUse(proxyPort);
|
|
10875
|
-
if (mitmProc) {
|
|
10876
|
-
console.log(
|
|
10877
|
-
` \u2713 Proxy mitmproxy (PID ${mitmProc.pid}) on :${proxyPort}`
|
|
10878
|
-
);
|
|
10879
|
-
} else if (portInUse) {
|
|
10880
|
-
console.log(
|
|
10881
|
-
` \u26A0\uFE0F Proxy port :${proxyPort} in use but mitmproxy process not found`
|
|
10882
|
-
);
|
|
10883
|
-
warnings.push({
|
|
10884
|
-
message: `Port ${proxyPort} is in use but mitmproxy process not detected`
|
|
10885
|
-
});
|
|
10886
|
-
} else {
|
|
10887
|
-
console.log(` \u2717 Proxy mitmproxy not running`);
|
|
10888
|
-
warnings.push({ message: "Proxy mitmproxy is not running" });
|
|
10889
|
-
}
|
|
10890
|
-
console.log(
|
|
10891
|
-
` \u2139 Namespaces: each VM runs in isolated namespace with IP ${SNAPSHOT_NETWORK.guestIp}`
|
|
10892
|
-
);
|
|
10893
|
-
console.log("");
|
|
10894
|
-
const processes = findFirecrackerProcesses();
|
|
10895
|
-
const workspaces = existsSync5(workspacesDir) ? readdirSync2(workspacesDir).filter(runnerPaths.isVmWorkspace) : [];
|
|
10896
|
-
const jobs = [];
|
|
10897
|
-
const statusVmIds = /* @__PURE__ */ new Set();
|
|
10898
|
-
if (status?.active_run_ids) {
|
|
10899
|
-
for (const runId of status.active_run_ids) {
|
|
10900
|
-
const vmId = createVmId(runId);
|
|
10901
|
-
statusVmIds.add(vmId);
|
|
10902
|
-
const proc = processes.find((p) => p.vmId === vmId);
|
|
10903
|
-
jobs.push({
|
|
10904
|
-
runId,
|
|
10905
|
-
vmId,
|
|
10906
|
-
hasProcess: !!proc,
|
|
10907
|
-
pid: proc?.pid
|
|
10908
|
-
});
|
|
10909
|
-
}
|
|
10910
|
-
}
|
|
10911
|
-
const maxConcurrent = config.sandbox.max_concurrent;
|
|
10912
|
-
console.log(`Runs (${jobs.length} active, max ${maxConcurrent}):`);
|
|
10913
|
-
if (jobs.length === 0) {
|
|
10914
|
-
console.log(" No active runs");
|
|
10915
|
-
} else {
|
|
10916
|
-
console.log(
|
|
10917
|
-
" Run ID VM ID Status"
|
|
10918
|
-
);
|
|
10919
|
-
for (const job of jobs) {
|
|
10920
|
-
const statusText = job.hasProcess ? `\u2713 Running (PID ${job.pid})` : "\u26A0\uFE0F No process";
|
|
10921
|
-
console.log(` ${job.runId} ${job.vmId} ${statusText}`);
|
|
10922
|
-
}
|
|
10923
|
-
}
|
|
10924
|
-
console.log("");
|
|
10925
|
-
for (const job of jobs) {
|
|
10926
|
-
if (!job.hasProcess) {
|
|
10927
|
-
warnings.push({
|
|
10928
|
-
message: `Run ${job.vmId} in status.json but no Firecracker process running`
|
|
10929
|
-
});
|
|
10930
|
-
}
|
|
10931
|
-
}
|
|
10932
|
-
const processVmIds = new Set(processes.map((p) => p.vmId));
|
|
10933
|
-
for (const proc of processes) {
|
|
10934
|
-
if (!statusVmIds.has(proc.vmId)) {
|
|
10935
|
-
warnings.push({
|
|
10936
|
-
message: `Orphan process: PID ${proc.pid} (vmId ${proc.vmId}) not in status.json`
|
|
10937
|
-
});
|
|
10938
|
-
}
|
|
10939
|
-
}
|
|
10940
|
-
for (const ws of workspaces) {
|
|
10941
|
-
const vmId = runnerPaths.extractVmId(ws);
|
|
10942
|
-
if (!processVmIds.has(vmId) && !statusVmIds.has(vmId)) {
|
|
10943
|
-
warnings.push({
|
|
10944
|
-
message: `Orphan workspace: ${ws} (no matching job or process)`
|
|
10945
|
-
});
|
|
10946
|
-
}
|
|
10947
|
-
}
|
|
10948
|
-
console.log("Warnings:");
|
|
10949
|
-
if (warnings.length === 0) {
|
|
10950
|
-
console.log(" None");
|
|
10951
|
-
} else {
|
|
10952
|
-
for (const w of warnings) {
|
|
10953
|
-
console.log(` - ${w.message}`);
|
|
10954
|
-
}
|
|
10955
|
-
}
|
|
10956
|
-
process.exit(warnings.length > 0 ? 1 : 0);
|
|
10957
|
-
} catch (error) {
|
|
10958
|
-
console.error(
|
|
10959
|
-
`Error: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
10960
|
-
);
|
|
10961
|
-
process.exit(1);
|
|
11022
|
+
function displayRunnerStatus(statusFilePath) {
|
|
11023
|
+
if (!existsSync5(statusFilePath)) {
|
|
11024
|
+
console.log("Mode: unknown (no status.json)");
|
|
11025
|
+
return null;
|
|
11026
|
+
}
|
|
11027
|
+
try {
|
|
11028
|
+
const status = JSON.parse(
|
|
11029
|
+
readFileSync3(statusFilePath, "utf-8")
|
|
11030
|
+
);
|
|
11031
|
+
console.log(`Mode: ${status.mode}`);
|
|
11032
|
+
if (status.started_at) {
|
|
11033
|
+
const started = new Date(status.started_at);
|
|
11034
|
+
const uptime = formatUptime(Date.now() - started.getTime());
|
|
11035
|
+
console.log(`Started: ${started.toLocaleString()} (uptime: ${uptime})`);
|
|
10962
11036
|
}
|
|
11037
|
+
return status;
|
|
11038
|
+
} catch {
|
|
11039
|
+
console.log("Mode: unknown (status.json unreadable)");
|
|
11040
|
+
return null;
|
|
10963
11041
|
}
|
|
10964
|
-
|
|
11042
|
+
}
|
|
11043
|
+
async function checkApiConnectivity(config) {
|
|
11044
|
+
console.log("API Connectivity:");
|
|
11045
|
+
try {
|
|
11046
|
+
await pollForJob(config.server, config.group);
|
|
11047
|
+
console.log(` \u2713 Connected to ${config.server.url}`);
|
|
11048
|
+
console.log(" \u2713 Authentication: OK");
|
|
11049
|
+
} catch (error) {
|
|
11050
|
+
console.log(` \u2717 Cannot connect to ${config.server.url}`);
|
|
11051
|
+
console.log(
|
|
11052
|
+
` Error: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
11053
|
+
);
|
|
11054
|
+
}
|
|
11055
|
+
}
|
|
11056
|
+
async function checkNetwork(config, warnings) {
|
|
11057
|
+
console.log("Network:");
|
|
11058
|
+
const proxyPort = config.proxy.port;
|
|
11059
|
+
const mitmProc = findMitmproxyProcess();
|
|
11060
|
+
const portInUse = await isPortInUse(proxyPort);
|
|
11061
|
+
if (mitmProc) {
|
|
11062
|
+
console.log(` \u2713 Proxy mitmproxy (PID ${mitmProc.pid}) on :${proxyPort}`);
|
|
11063
|
+
} else if (portInUse) {
|
|
11064
|
+
console.log(
|
|
11065
|
+
` \u26A0\uFE0F Proxy port :${proxyPort} in use but mitmproxy process not found`
|
|
11066
|
+
);
|
|
11067
|
+
warnings.push({
|
|
11068
|
+
message: `Port ${proxyPort} is in use but mitmproxy process not detected`
|
|
11069
|
+
});
|
|
11070
|
+
} else {
|
|
11071
|
+
console.log(` \u2717 Proxy mitmproxy not running`);
|
|
11072
|
+
warnings.push({ message: "Proxy mitmproxy is not running" });
|
|
11073
|
+
}
|
|
11074
|
+
console.log(
|
|
11075
|
+
` \u2139 Namespaces: each VM runs in isolated namespace with IP ${SNAPSHOT_NETWORK.guestIp}`
|
|
11076
|
+
);
|
|
11077
|
+
}
|
|
11078
|
+
function buildJobInfo(status, processes) {
|
|
11079
|
+
const jobs = [];
|
|
11080
|
+
const statusVmIds = /* @__PURE__ */ new Set();
|
|
11081
|
+
if (status?.active_run_ids) {
|
|
11082
|
+
for (const runId of status.active_run_ids) {
|
|
11083
|
+
const vmId = createVmId(runId);
|
|
11084
|
+
statusVmIds.add(vmId);
|
|
11085
|
+
const proc = processes.find((p) => p.vmId === vmId);
|
|
11086
|
+
jobs.push({
|
|
11087
|
+
runId,
|
|
11088
|
+
vmId,
|
|
11089
|
+
hasProcess: !!proc,
|
|
11090
|
+
pid: proc?.pid
|
|
11091
|
+
});
|
|
11092
|
+
}
|
|
11093
|
+
}
|
|
11094
|
+
return { jobs, statusVmIds };
|
|
11095
|
+
}
|
|
11096
|
+
function displayRuns(jobs, maxConcurrent) {
|
|
11097
|
+
console.log(`Runs (${jobs.length} active, max ${maxConcurrent}):`);
|
|
11098
|
+
if (jobs.length === 0) {
|
|
11099
|
+
console.log(" No active runs");
|
|
11100
|
+
return;
|
|
11101
|
+
}
|
|
11102
|
+
console.log(" Run ID VM ID Status");
|
|
11103
|
+
for (const job of jobs) {
|
|
11104
|
+
const statusText = job.hasProcess ? `\u2713 Running (PID ${job.pid})` : "\u26A0\uFE0F No process";
|
|
11105
|
+
console.log(` ${job.runId} ${job.vmId} ${statusText}`);
|
|
11106
|
+
}
|
|
11107
|
+
}
|
|
11108
|
+
function detectOrphanResources(jobs, processes, workspaces, statusVmIds, warnings) {
|
|
11109
|
+
for (const job of jobs) {
|
|
11110
|
+
if (!job.hasProcess) {
|
|
11111
|
+
warnings.push({
|
|
11112
|
+
message: `Run ${job.vmId} in status.json but no Firecracker process running`
|
|
11113
|
+
});
|
|
11114
|
+
}
|
|
11115
|
+
}
|
|
11116
|
+
const processVmIds = new Set(processes.map((p) => p.vmId));
|
|
11117
|
+
for (const proc of processes) {
|
|
11118
|
+
if (!statusVmIds.has(proc.vmId)) {
|
|
11119
|
+
warnings.push({
|
|
11120
|
+
message: `Orphan process: PID ${proc.pid} (vmId ${proc.vmId}) not in status.json`
|
|
11121
|
+
});
|
|
11122
|
+
}
|
|
11123
|
+
}
|
|
11124
|
+
for (const ws of workspaces) {
|
|
11125
|
+
const vmId = runnerPaths.extractVmId(ws);
|
|
11126
|
+
if (!processVmIds.has(vmId) && !statusVmIds.has(vmId)) {
|
|
11127
|
+
warnings.push({
|
|
11128
|
+
message: `Orphan workspace: ${ws} (no matching job or process)`
|
|
11129
|
+
});
|
|
11130
|
+
}
|
|
11131
|
+
}
|
|
11132
|
+
}
|
|
11133
|
+
function displayWarnings(warnings) {
|
|
11134
|
+
console.log("Warnings:");
|
|
11135
|
+
if (warnings.length === 0) {
|
|
11136
|
+
console.log(" None");
|
|
11137
|
+
} else {
|
|
11138
|
+
for (const w of warnings) {
|
|
11139
|
+
console.log(` - ${w.message}`);
|
|
11140
|
+
}
|
|
11141
|
+
}
|
|
11142
|
+
}
|
|
10965
11143
|
function formatUptime(ms) {
|
|
10966
11144
|
const seconds = Math.floor(ms / 1e3);
|
|
10967
11145
|
const minutes = Math.floor(seconds / 60);
|
|
@@ -10972,6 +11150,34 @@ function formatUptime(ms) {
|
|
|
10972
11150
|
if (minutes > 0) return `${minutes}m`;
|
|
10973
11151
|
return `${seconds}s`;
|
|
10974
11152
|
}
|
|
11153
|
+
var doctorCommand = new Command2("doctor").description("Diagnose runner health, check network, and detect issues").option("--config <path>", "Config file path", "./runner.yaml").action(async (options) => {
|
|
11154
|
+
try {
|
|
11155
|
+
const config = loadConfig(options.config);
|
|
11156
|
+
const statusFilePath = runnerPaths.statusFile(config.base_dir);
|
|
11157
|
+
const workspacesDir = runnerPaths.workspacesDir(config.base_dir);
|
|
11158
|
+
const warnings = [];
|
|
11159
|
+
console.log(`Runner: ${config.name}`);
|
|
11160
|
+
const status = displayRunnerStatus(statusFilePath);
|
|
11161
|
+
console.log("");
|
|
11162
|
+
await checkApiConnectivity(config);
|
|
11163
|
+
console.log("");
|
|
11164
|
+
await checkNetwork(config, warnings);
|
|
11165
|
+
console.log("");
|
|
11166
|
+
const processes = findFirecrackerProcesses();
|
|
11167
|
+
const workspaces = existsSync5(workspacesDir) ? readdirSync2(workspacesDir).filter(runnerPaths.isVmWorkspace) : [];
|
|
11168
|
+
const { jobs, statusVmIds } = buildJobInfo(status, processes);
|
|
11169
|
+
displayRuns(jobs, config.sandbox.max_concurrent);
|
|
11170
|
+
console.log("");
|
|
11171
|
+
detectOrphanResources(jobs, processes, workspaces, statusVmIds, warnings);
|
|
11172
|
+
displayWarnings(warnings);
|
|
11173
|
+
process.exit(warnings.length > 0 ? 1 : 0);
|
|
11174
|
+
} catch (error) {
|
|
11175
|
+
console.error(
|
|
11176
|
+
`Error: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
11177
|
+
);
|
|
11178
|
+
process.exit(1);
|
|
11179
|
+
}
|
|
11180
|
+
});
|
|
10975
11181
|
|
|
10976
11182
|
// src/commands/kill.ts
|
|
10977
11183
|
import { Command as Command3 } from "commander";
|
|
@@ -11208,10 +11414,16 @@ var benchmarkCommand = new Command4("benchmark").description(
|
|
|
11208
11414
|
process.exit(1);
|
|
11209
11415
|
}
|
|
11210
11416
|
timer.log("Initializing pools...");
|
|
11417
|
+
const snapshotConfig = config.firecracker.snapshot;
|
|
11211
11418
|
await initOverlayPool({
|
|
11212
11419
|
size: 2,
|
|
11213
11420
|
replenishThreshold: 1,
|
|
11214
|
-
poolDir: runnerPaths.overlayPool(config.base_dir)
|
|
11421
|
+
poolDir: runnerPaths.overlayPool(config.base_dir),
|
|
11422
|
+
createFile: snapshotConfig ? (filePath) => execCommand(
|
|
11423
|
+
`cp --sparse=always "${snapshotConfig.overlay}" "${filePath}"`,
|
|
11424
|
+
false
|
|
11425
|
+
).then(() => {
|
|
11426
|
+
}) : void 0
|
|
11215
11427
|
});
|
|
11216
11428
|
await initNetnsPool({ name: config.name, size: 2 });
|
|
11217
11429
|
poolsInitialized = true;
|
|
@@ -11239,12 +11451,219 @@ var benchmarkCommand = new Command4("benchmark").description(
|
|
|
11239
11451
|
process.exit(exitCode);
|
|
11240
11452
|
});
|
|
11241
11453
|
|
|
11454
|
+
// src/commands/snapshot.ts
|
|
11455
|
+
import { Command as Command5 } from "commander";
|
|
11456
|
+
import { spawn as spawn3 } from "child_process";
|
|
11457
|
+
import fs11 from "fs";
|
|
11458
|
+
import os2 from "os";
|
|
11459
|
+
import readline3 from "readline";
|
|
11460
|
+
var logger15 = createLogger("Snapshot");
|
|
11461
|
+
function startFirecracker(nsName, firecrackerBinary, apiSocketPath, workDir) {
|
|
11462
|
+
logger15.log("Starting Firecracker with API socket...");
|
|
11463
|
+
const currentUser = os2.userInfo().username;
|
|
11464
|
+
const fcProcess = spawn3(
|
|
11465
|
+
"sudo",
|
|
11466
|
+
[
|
|
11467
|
+
"ip",
|
|
11468
|
+
"netns",
|
|
11469
|
+
"exec",
|
|
11470
|
+
nsName,
|
|
11471
|
+
"sudo",
|
|
11472
|
+
"-u",
|
|
11473
|
+
currentUser,
|
|
11474
|
+
firecrackerBinary,
|
|
11475
|
+
"--api-sock",
|
|
11476
|
+
apiSocketPath
|
|
11477
|
+
],
|
|
11478
|
+
{
|
|
11479
|
+
cwd: workDir,
|
|
11480
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
11481
|
+
detached: false
|
|
11482
|
+
}
|
|
11483
|
+
);
|
|
11484
|
+
if (fcProcess.stdout) {
|
|
11485
|
+
const stdoutRL = readline3.createInterface({ input: fcProcess.stdout });
|
|
11486
|
+
stdoutRL.on("line", (line) => {
|
|
11487
|
+
if (line.trim()) logger15.log(`[FC] ${line}`);
|
|
11488
|
+
});
|
|
11489
|
+
}
|
|
11490
|
+
if (fcProcess.stderr) {
|
|
11491
|
+
const stderrRL = readline3.createInterface({ input: fcProcess.stderr });
|
|
11492
|
+
stderrRL.on("line", (line) => {
|
|
11493
|
+
if (line.trim()) logger15.log(`[FC stderr] ${line}`);
|
|
11494
|
+
});
|
|
11495
|
+
}
|
|
11496
|
+
fcProcess.on("error", (err) => logger15.log(`Firecracker error: ${err}`));
|
|
11497
|
+
fcProcess.on(
|
|
11498
|
+
"exit",
|
|
11499
|
+
(code, signal) => logger15.log(`Firecracker exited: code=${code}, signal=${signal}`)
|
|
11500
|
+
);
|
|
11501
|
+
return fcProcess;
|
|
11502
|
+
}
|
|
11503
|
+
var snapshotCommand = new Command5("snapshot").description("Generate a Firecracker snapshot for fast VM startup").argument("<output-dir>", "Output directory for snapshot files").option("--config <path>", "Config file path", "./runner.yaml").action(
|
|
11504
|
+
async (outputDir, opts) => {
|
|
11505
|
+
const options = {
|
|
11506
|
+
config: opts.config ?? "./runner.yaml",
|
|
11507
|
+
output: outputDir
|
|
11508
|
+
};
|
|
11509
|
+
const timer = new Timer();
|
|
11510
|
+
setGlobalLogger(timer.log.bind(timer));
|
|
11511
|
+
logger15.log("Loading configuration...");
|
|
11512
|
+
const config = loadDebugConfig(options.config);
|
|
11513
|
+
validateFirecrackerPaths(config.firecracker);
|
|
11514
|
+
const nsName = "vm0-snapshot";
|
|
11515
|
+
const workDir = runnerPaths.snapshotWorkDir(config.base_dir);
|
|
11516
|
+
const overlayPath = vmPaths.overlay(workDir);
|
|
11517
|
+
const vsockPath = vmPaths.vsock(workDir);
|
|
11518
|
+
const apiSocketPath = vmPaths.apiSock(workDir);
|
|
11519
|
+
const outputSnapshot = snapshotOutputPaths.snapshot(options.output);
|
|
11520
|
+
const outputMemory = snapshotOutputPaths.memory(options.output);
|
|
11521
|
+
const outputOverlay = snapshotOutputPaths.overlay(options.output);
|
|
11522
|
+
let fcProcess = null;
|
|
11523
|
+
let vsockClient = null;
|
|
11524
|
+
let exitCode = 0;
|
|
11525
|
+
try {
|
|
11526
|
+
if (fs11.existsSync(workDir)) {
|
|
11527
|
+
logger15.log("Cleaning up stale work directory...");
|
|
11528
|
+
fs11.rmSync(workDir, { recursive: true, force: true });
|
|
11529
|
+
}
|
|
11530
|
+
logger15.log(`Creating directories...`);
|
|
11531
|
+
fs11.mkdirSync(options.output, { recursive: true });
|
|
11532
|
+
fs11.mkdirSync(workDir, { recursive: true });
|
|
11533
|
+
fs11.mkdirSync(vmPaths.vsockDir(workDir), { recursive: true });
|
|
11534
|
+
logger15.log("Creating overlay filesystem...");
|
|
11535
|
+
await createOverlayFile(overlayPath);
|
|
11536
|
+
logger15.log(`Overlay created: ${overlayPath}`);
|
|
11537
|
+
logger15.log(`Creating network namespace: ${nsName}`);
|
|
11538
|
+
await deleteNetns(nsName);
|
|
11539
|
+
await createNetnsWithTap(nsName, {
|
|
11540
|
+
tapName: SNAPSHOT_NETWORK.tapName,
|
|
11541
|
+
gatewayIpWithPrefix: `${SNAPSHOT_NETWORK.gatewayIp}/${SNAPSHOT_NETWORK.prefixLen}`
|
|
11542
|
+
});
|
|
11543
|
+
logger15.log("Network namespace created");
|
|
11544
|
+
fcProcess = startFirecracker(
|
|
11545
|
+
nsName,
|
|
11546
|
+
config.firecracker.binary,
|
|
11547
|
+
apiSocketPath,
|
|
11548
|
+
workDir
|
|
11549
|
+
);
|
|
11550
|
+
const apiClient = new FirecrackerClient(apiSocketPath);
|
|
11551
|
+
logger15.log("Waiting for API to be ready...");
|
|
11552
|
+
await apiClient.waitForReady();
|
|
11553
|
+
logger15.log("API ready");
|
|
11554
|
+
logger15.log("Configuring VM via API...");
|
|
11555
|
+
await Promise.all([
|
|
11556
|
+
apiClient.configureMachine({
|
|
11557
|
+
vcpu_count: config.sandbox.vcpu,
|
|
11558
|
+
mem_size_mib: config.sandbox.memory_mb
|
|
11559
|
+
}),
|
|
11560
|
+
apiClient.configureBootSource({
|
|
11561
|
+
kernel_image_path: config.firecracker.kernel,
|
|
11562
|
+
boot_args: buildBootArgs()
|
|
11563
|
+
}),
|
|
11564
|
+
apiClient.configureDrive({
|
|
11565
|
+
drive_id: "rootfs",
|
|
11566
|
+
path_on_host: config.firecracker.rootfs,
|
|
11567
|
+
is_root_device: true,
|
|
11568
|
+
is_read_only: true
|
|
11569
|
+
}),
|
|
11570
|
+
apiClient.configureDrive({
|
|
11571
|
+
drive_id: "overlay",
|
|
11572
|
+
path_on_host: overlayPath,
|
|
11573
|
+
is_root_device: false,
|
|
11574
|
+
is_read_only: false
|
|
11575
|
+
}),
|
|
11576
|
+
apiClient.configureNetworkInterface({
|
|
11577
|
+
iface_id: "eth0",
|
|
11578
|
+
guest_mac: SNAPSHOT_NETWORK.guestMac,
|
|
11579
|
+
host_dev_name: SNAPSHOT_NETWORK.tapName
|
|
11580
|
+
}),
|
|
11581
|
+
apiClient.configureVsock({
|
|
11582
|
+
guest_cid: 3,
|
|
11583
|
+
uds_path: vsockPath
|
|
11584
|
+
})
|
|
11585
|
+
]);
|
|
11586
|
+
logger15.log("VM configured");
|
|
11587
|
+
logger15.log("Starting vsock listener...");
|
|
11588
|
+
vsockClient = new VsockClient(vsockPath);
|
|
11589
|
+
const guestConnectionPromise = vsockClient.waitForGuestConnection(6e4);
|
|
11590
|
+
logger15.log("Starting VM...");
|
|
11591
|
+
await apiClient.startInstance();
|
|
11592
|
+
logger15.log("VM started");
|
|
11593
|
+
logger15.log("Waiting for guest connection...");
|
|
11594
|
+
await guestConnectionPromise;
|
|
11595
|
+
logger15.log("Guest connected");
|
|
11596
|
+
logger15.log("Verifying guest is responsive...");
|
|
11597
|
+
const reachable = await vsockClient.isReachable();
|
|
11598
|
+
if (!reachable) {
|
|
11599
|
+
throw new Error("Guest is not responsive");
|
|
11600
|
+
}
|
|
11601
|
+
logger15.log("Guest is responsive");
|
|
11602
|
+
logger15.log("Pausing VM...");
|
|
11603
|
+
await apiClient.pause();
|
|
11604
|
+
logger15.log("VM paused");
|
|
11605
|
+
logger15.log("Creating snapshot...");
|
|
11606
|
+
await apiClient.createSnapshot({
|
|
11607
|
+
snapshot_type: "Full",
|
|
11608
|
+
snapshot_path: outputSnapshot,
|
|
11609
|
+
mem_file_path: outputMemory
|
|
11610
|
+
});
|
|
11611
|
+
logger15.log("Snapshot created");
|
|
11612
|
+
logger15.log("Copying overlay as golden overlay...");
|
|
11613
|
+
await execCommand(
|
|
11614
|
+
`cp --sparse=always "${overlayPath}" "${outputOverlay}"`,
|
|
11615
|
+
false
|
|
11616
|
+
);
|
|
11617
|
+
logger15.log("Golden overlay created");
|
|
11618
|
+
logger15.log("=".repeat(40));
|
|
11619
|
+
logger15.log("Snapshot generation complete!");
|
|
11620
|
+
logger15.log("Files (logical size):");
|
|
11621
|
+
const lsOutput = await execCommand(`ls -lh "${options.output}"`, false);
|
|
11622
|
+
logger15.log(lsOutput);
|
|
11623
|
+
logger15.log("Actual disk usage:");
|
|
11624
|
+
const duOutput = await execCommand(
|
|
11625
|
+
`du -h "${options.output}"/*`,
|
|
11626
|
+
false
|
|
11627
|
+
);
|
|
11628
|
+
logger15.log(duOutput);
|
|
11629
|
+
logger15.log("=".repeat(40));
|
|
11630
|
+
} catch (error) {
|
|
11631
|
+
logger15.error(
|
|
11632
|
+
`Error: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
11633
|
+
);
|
|
11634
|
+
exitCode = 1;
|
|
11635
|
+
} finally {
|
|
11636
|
+
logger15.log("Cleaning up...");
|
|
11637
|
+
if (vsockClient) {
|
|
11638
|
+
vsockClient.close();
|
|
11639
|
+
}
|
|
11640
|
+
if (fcProcess && !fcProcess.killed) {
|
|
11641
|
+
fcProcess.kill("SIGKILL");
|
|
11642
|
+
}
|
|
11643
|
+
await execCommand(
|
|
11644
|
+
`pkill -9 -f "firecracker.*${apiSocketPath}"`,
|
|
11645
|
+
true
|
|
11646
|
+
).catch(() => {
|
|
11647
|
+
});
|
|
11648
|
+
await deleteNetns(nsName);
|
|
11649
|
+
if (fs11.existsSync(workDir)) {
|
|
11650
|
+
fs11.rmSync(workDir, { recursive: true, force: true });
|
|
11651
|
+
}
|
|
11652
|
+
logger15.log("Cleanup complete");
|
|
11653
|
+
}
|
|
11654
|
+
if (exitCode !== 0) {
|
|
11655
|
+
process.exit(exitCode);
|
|
11656
|
+
}
|
|
11657
|
+
}
|
|
11658
|
+
);
|
|
11659
|
+
|
|
11242
11660
|
// src/index.ts
|
|
11243
|
-
var version = true ? "3.
|
|
11661
|
+
var version = true ? "3.12.0" : "0.1.0";
|
|
11244
11662
|
program.name("vm0-runner").version(version).description("Self-hosted runner for VM0 agents");
|
|
11245
11663
|
program.addCommand(startCommand);
|
|
11246
11664
|
program.addCommand(doctorCommand);
|
|
11247
11665
|
program.addCommand(killCommand);
|
|
11248
11666
|
program.addCommand(benchmarkCommand);
|
|
11667
|
+
program.addCommand(snapshotCommand);
|
|
11249
11668
|
program.parse();
|
|
11250
11669
|
//# sourceMappingURL=index.js.map
|