@vm0/runner 2.15.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +83 -287
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -16,8 +16,7 @@ var SANDBOX_DEFAULTS = {
16
16
  max_concurrent: 1,
17
17
  vcpu: 2,
18
18
  memory_mb: 2048,
19
- poll_interval_ms: 5e3,
20
- guest_protocol: "vsock"
19
+ poll_interval_ms: 5e3
21
20
  };
22
21
  var PROXY_DEFAULTS = {
23
22
  port: 8080
@@ -36,8 +35,7 @@ var runnerConfigSchema = z.object({
36
35
  max_concurrent: z.number().int().min(1).default(SANDBOX_DEFAULTS.max_concurrent),
37
36
  vcpu: z.number().int().min(1).default(SANDBOX_DEFAULTS.vcpu),
38
37
  memory_mb: z.number().int().min(128).default(SANDBOX_DEFAULTS.memory_mb),
39
- poll_interval_ms: z.number().int().min(1e3).default(SANDBOX_DEFAULTS.poll_interval_ms),
40
- guest_protocol: z.enum(["vsock", "ssh"]).default(SANDBOX_DEFAULTS.guest_protocol)
38
+ poll_interval_ms: z.number().int().min(1e3).default(SANDBOX_DEFAULTS.poll_interval_ms)
41
39
  }).default(SANDBOX_DEFAULTS),
42
40
  firecracker: z.object({
43
41
  binary: z.string().min(1, "Firecracker binary path is required"),
@@ -64,8 +62,7 @@ var debugConfigSchema = z.object({
64
62
  max_concurrent: z.number().int().min(1).default(SANDBOX_DEFAULTS.max_concurrent),
65
63
  vcpu: z.number().int().min(1).default(SANDBOX_DEFAULTS.vcpu),
66
64
  memory_mb: z.number().int().min(128).default(SANDBOX_DEFAULTS.memory_mb),
67
- poll_interval_ms: z.number().int().min(1e3).default(SANDBOX_DEFAULTS.poll_interval_ms),
68
- guest_protocol: z.enum(["vsock", "ssh"]).default(SANDBOX_DEFAULTS.guest_protocol)
65
+ poll_interval_ms: z.number().int().min(1e3).default(SANDBOX_DEFAULTS.poll_interval_ms)
69
66
  }).default(SANDBOX_DEFAULTS),
70
67
  firecracker: z.object({
71
68
  binary: z.string().min(1, "Firecracker binary path is required"),
@@ -192,7 +189,7 @@ async function completeJob(apiUrl, context, exitCode, error) {
192
189
  }
193
190
 
194
191
  // src/lib/executor.ts
195
- import path5 from "path";
192
+ import path4 from "path";
196
193
 
197
194
  // src/lib/firecracker/vm.ts
198
195
  import { execSync as execSync2, spawn } from "child_process";
@@ -210,7 +207,7 @@ var FirecrackerClient = class {
210
207
  /**
211
208
  * Make HTTP request to Firecracker API
212
209
  */
213
- async request(method, path7, body) {
210
+ async request(method, path6, body) {
214
211
  return new Promise((resolve, reject) => {
215
212
  const bodyStr = body !== void 0 ? JSON.stringify(body) : void 0;
216
213
  const headers = {
@@ -223,11 +220,11 @@ var FirecrackerClient = class {
223
220
  headers["Content-Length"] = Buffer.byteLength(bodyStr);
224
221
  }
225
222
  console.log(
226
- `[FC API] ${method} ${path7}${bodyStr ? ` (${Buffer.byteLength(bodyStr)} bytes)` : ""}`
223
+ `[FC API] ${method} ${path6}${bodyStr ? ` (${Buffer.byteLength(bodyStr)} bytes)` : ""}`
227
224
  );
228
225
  const options = {
229
226
  socketPath: this.socketPath,
230
- path: path7,
227
+ path: path6,
231
228
  method,
232
229
  headers,
233
230
  // Disable agent to ensure fresh connection for each request
@@ -1224,216 +1221,9 @@ var FirecrackerVM = class {
1224
1221
  }
1225
1222
  };
1226
1223
 
1227
- // src/lib/firecracker/guest.ts
1228
- import { exec as exec3, execSync as execSync3 } from "child_process";
1229
- import { promisify as promisify3 } from "util";
1230
- import fs4 from "fs";
1231
- import path3 from "path";
1232
- import os from "os";
1233
- var execAsync3 = promisify3(exec3);
1234
- var DEFAULT_SSH_OPTIONS = [
1235
- "-o",
1236
- "StrictHostKeyChecking=no",
1237
- "-o",
1238
- "UserKnownHostsFile=/dev/null",
1239
- "-o",
1240
- "LogLevel=ERROR",
1241
- "-o",
1242
- "ConnectTimeout=10",
1243
- "-o",
1244
- "ServerAliveInterval=5",
1245
- "-o",
1246
- "ServerAliveCountMax=3"
1247
- ];
1248
- var SSHClient = class {
1249
- config;
1250
- sshOptions;
1251
- constructor(config) {
1252
- this.config = config;
1253
- this.sshOptions = [...DEFAULT_SSH_OPTIONS];
1254
- if (config.privateKeyPath) {
1255
- this.sshOptions.push("-i", config.privateKeyPath);
1256
- }
1257
- if (config.connectTimeout) {
1258
- const idx = this.sshOptions.indexOf("ConnectTimeout=10");
1259
- if (idx !== -1) {
1260
- this.sshOptions[idx] = `ConnectTimeout=${config.connectTimeout}`;
1261
- }
1262
- }
1263
- }
1264
- /**
1265
- * Build SSH command prefix
1266
- */
1267
- buildSSHCommand() {
1268
- return [
1269
- "ssh",
1270
- ...this.sshOptions,
1271
- `${this.config.user}@${this.config.host}`
1272
- ];
1273
- }
1274
- /**
1275
- * Execute a command on the remote VM
1276
- * @param command - The command to execute
1277
- * @param timeoutMs - Optional timeout in milliseconds (default: 300000ms = 5 minutes)
1278
- */
1279
- async exec(command, timeoutMs) {
1280
- const sshCmd = this.buildSSHCommand();
1281
- const escapedCommand = command.replace(/'/g, "'\\''");
1282
- const fullCmd = [...sshCmd, `'${escapedCommand}'`].join(" ");
1283
- try {
1284
- const { stdout, stderr } = await execAsync3(fullCmd, {
1285
- maxBuffer: 50 * 1024 * 1024,
1286
- // 50MB buffer
1287
- timeout: timeoutMs ?? 3e5
1288
- // Default 5 minutes, customizable per call
1289
- });
1290
- return {
1291
- exitCode: 0,
1292
- stdout: stdout || "",
1293
- stderr: stderr || ""
1294
- };
1295
- } catch (error) {
1296
- const execError = error;
1297
- return {
1298
- exitCode: execError.code ?? 1,
1299
- stdout: execError.stdout || "",
1300
- stderr: execError.stderr || execError.message || "Unknown error"
1301
- };
1302
- }
1303
- }
1304
- /**
1305
- * Execute a command and throw on non-zero exit
1306
- */
1307
- async execOrThrow(command) {
1308
- const result = await this.exec(command);
1309
- if (result.exitCode !== 0) {
1310
- throw new Error(
1311
- `Command failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`
1312
- );
1313
- }
1314
- return result.stdout;
1315
- }
1316
- /**
1317
- * Write content to a file on the remote VM
1318
- * Uses base64 encoding to safely transfer any content
1319
- */
1320
- async writeFile(remotePath, content) {
1321
- const encoded = Buffer.from(content).toString("base64");
1322
- const maxChunkSize = 65e3;
1323
- if (encoded.length <= maxChunkSize) {
1324
- await this.execOrThrow(`echo '${encoded}' | base64 -d > '${remotePath}'`);
1325
- } else {
1326
- await this.execOrThrow(`rm -f '${remotePath}'`);
1327
- for (let i = 0; i < encoded.length; i += maxChunkSize) {
1328
- const chunk = encoded.slice(i, i + maxChunkSize);
1329
- const operator = i === 0 ? ">" : ">>";
1330
- await this.execOrThrow(
1331
- `echo '${chunk}' | base64 -d ${operator} '${remotePath}'`
1332
- );
1333
- }
1334
- }
1335
- }
1336
- /**
1337
- * Write content to a file on the remote VM using sudo
1338
- * Used for writing to privileged locations like /usr/local/bin
1339
- */
1340
- async writeFileWithSudo(remotePath, content) {
1341
- const encoded = Buffer.from(content).toString("base64");
1342
- const maxChunkSize = 65e3;
1343
- if (encoded.length <= maxChunkSize) {
1344
- await this.execOrThrow(
1345
- `echo '${encoded}' | base64 -d | sudo tee '${remotePath}' > /dev/null`
1346
- );
1347
- } else {
1348
- await this.execOrThrow(`sudo rm -f '${remotePath}'`);
1349
- for (let i = 0; i < encoded.length; i += maxChunkSize) {
1350
- const chunk = encoded.slice(i, i + maxChunkSize);
1351
- const teeFlag = i === 0 ? "" : "-a";
1352
- await this.execOrThrow(
1353
- `echo '${chunk}' | base64 -d | sudo tee ${teeFlag} '${remotePath}' > /dev/null`
1354
- );
1355
- }
1356
- }
1357
- }
1358
- /**
1359
- * Read a file from the remote VM
1360
- */
1361
- async readFile(remotePath) {
1362
- const result = await this.exec(`cat '${remotePath}'`);
1363
- if (result.exitCode !== 0) {
1364
- throw new Error(`Failed to read file: ${result.stderr}`);
1365
- }
1366
- return result.stdout;
1367
- }
1368
- /**
1369
- * Check if SSH connection is available
1370
- * Uses a short timeout (15s) to ensure waitUntilReachable() respects its outer timeout
1371
- */
1372
- async isReachable() {
1373
- try {
1374
- const result = await this.exec("echo ok", 15e3);
1375
- return result.exitCode === 0 && result.stdout.trim() === "ok";
1376
- } catch {
1377
- return false;
1378
- }
1379
- }
1380
- /**
1381
- * Wait for SSH to become available
1382
- */
1383
- async waitUntilReachable(timeoutMs = 12e4, intervalMs = 2e3) {
1384
- const start = Date.now();
1385
- while (Date.now() - start < timeoutMs) {
1386
- if (await this.isReachable()) {
1387
- return;
1388
- }
1389
- await new Promise((resolve) => {
1390
- const remaining = timeoutMs - (Date.now() - start);
1391
- if (remaining > 0) {
1392
- setTimeout(resolve, Math.min(intervalMs, remaining));
1393
- } else {
1394
- resolve();
1395
- }
1396
- });
1397
- }
1398
- throw new Error(
1399
- `SSH not reachable after ${timeoutMs}ms at ${this.config.host}`
1400
- );
1401
- }
1402
- /**
1403
- * Create a directory on the remote VM (mkdir -p)
1404
- */
1405
- async mkdir(remotePath) {
1406
- await this.execOrThrow(`mkdir -p '${remotePath}'`);
1407
- }
1408
- /**
1409
- * Check if a file/directory exists on the remote VM
1410
- */
1411
- async exists(remotePath) {
1412
- const result = await this.exec(`test -e '${remotePath}'`);
1413
- return result.exitCode === 0;
1414
- }
1415
- /**
1416
- * Get the host IP
1417
- */
1418
- getHost() {
1419
- return this.config.host;
1420
- }
1421
- };
1422
- function getRunnerSSHKeyPath() {
1423
- const runnerKeyPath = "/opt/vm0-runner/ssh/id_rsa";
1424
- if (fs4.existsSync(runnerKeyPath)) {
1425
- return runnerKeyPath;
1426
- }
1427
- const userKeyPath = path3.join(os.homedir(), ".ssh", "id_rsa");
1428
- if (fs4.existsSync(userKeyPath)) {
1429
- return userKeyPath;
1430
- }
1431
- return "";
1432
- }
1433
-
1434
1224
  // src/lib/firecracker/vsock.ts
1435
1225
  import * as net from "net";
1436
- import * as fs5 from "fs";
1226
+ import * as fs4 from "fs";
1437
1227
  import * as crypto from "crypto";
1438
1228
  var VSOCK_PORT = 1e3;
1439
1229
  var CONNECT_TIMEOUT_MS = 5e3;
@@ -1479,7 +1269,7 @@ var VsockClient = class {
1479
1269
  return;
1480
1270
  }
1481
1271
  return new Promise((resolve, reject) => {
1482
- if (!fs5.existsSync(this.vsockPath)) {
1272
+ if (!fs4.existsSync(this.vsockPath)) {
1483
1273
  reject(new Error(`Vsock socket not found: ${this.vsockPath}`));
1484
1274
  return;
1485
1275
  }
@@ -2099,8 +1889,8 @@ function getErrorMap() {
2099
1889
  return overrideErrorMap;
2100
1890
  }
2101
1891
  var makeIssue = (params) => {
2102
- const { data, path: path7, errorMaps, issueData } = params;
2103
- const fullPath = [...path7, ...issueData.path || []];
1892
+ const { data, path: path6, errorMaps, issueData } = params;
1893
+ const fullPath = [...path6, ...issueData.path || []];
2104
1894
  const fullIssue = {
2105
1895
  ...issueData,
2106
1896
  path: fullPath
@@ -2199,11 +1989,11 @@ var errorUtil;
2199
1989
  errorUtil2.toString = (message) => typeof message === "string" ? message : message === null || message === void 0 ? void 0 : message.message;
2200
1990
  })(errorUtil || (errorUtil = {}));
2201
1991
  var ParseInputLazyPath = class {
2202
- constructor(parent, value, path7, key) {
1992
+ constructor(parent, value, path6, key) {
2203
1993
  this._cachedPath = [];
2204
1994
  this.parent = parent;
2205
1995
  this.data = value;
2206
- this._path = path7;
1996
+ this._path = path6;
2207
1997
  this._key = key;
2208
1998
  }
2209
1999
  get path() {
@@ -5969,7 +5759,7 @@ var unifiedRunRequestSchema = z6.object({
5969
5759
  volumeVersions: z6.record(z6.string(), z6.string()).optional(),
5970
5760
  // Debug flag to force real Claude in mock environments (internal use only)
5971
5761
  debugNoMockClaude: z6.boolean().optional(),
5972
- // Model provider for automatic LLM credential injection
5762
+ // Model provider for automatic credential injection
5973
5763
  modelProvider: z6.string().optional(),
5974
5764
  // Required
5975
5765
  prompt: z6.string().min(1, "Missing prompt")
@@ -8113,20 +7903,46 @@ var SCRIPT_PATHS = {
8113
7903
  };
8114
7904
 
8115
7905
  // ../../packages/core/src/feature-switch.ts
8116
- var PricingSwitch = {
8117
- key: "pricing" /* Pricing */,
8118
- maintainer: "ethan@vm0.ai",
8119
- enabled: false
8120
- };
8121
7906
  var FEATURE_SWITCHES = {
8122
- ["pricing" /* Pricing */]: PricingSwitch
7907
+ ["pricing" /* Pricing */]: {
7908
+ maintainer: "ethan@vm0.ai",
7909
+ enabled: false
7910
+ },
7911
+ ["dummy" /* Dummy */]: {
7912
+ maintainer: "ethan@vm0.ai",
7913
+ enabled: true
7914
+ },
7915
+ ["platformOnboarding" /* PlatformOnboarding */]: {
7916
+ maintainer: "ethan@vm0.ai",
7917
+ enabled: false
7918
+ },
7919
+ ["platformAgents" /* PlatformAgents */]: {
7920
+ maintainer: "ethan@vm0.ai",
7921
+ enabled: false
7922
+ },
7923
+ ["platformSecrets" /* PlatformSecrets */]: {
7924
+ maintainer: "ethan@vm0.ai",
7925
+ enabled: false
7926
+ },
7927
+ ["platformArtifacts" /* PlatformArtifacts */]: {
7928
+ maintainer: "ethan@vm0.ai",
7929
+ enabled: false
7930
+ },
7931
+ ["platformApiKeys" /* PlatformApiKeys */]: {
7932
+ maintainer: "ethan@vm0.ai",
7933
+ enabled: false
7934
+ },
7935
+ ["platformLogs" /* PlatformLogs */]: {
7936
+ maintainer: "ethan@vm0.ai",
7937
+ enabled: false
7938
+ }
8123
7939
  };
8124
7940
 
8125
7941
  // src/lib/scripts/index.ts
8126
7942
  var ENV_LOADER_PATH = "/usr/local/bin/vm0-agent/env-loader.mjs";
8127
7943
 
8128
7944
  // src/lib/proxy/vm-registry.ts
8129
- import fs6 from "fs";
7945
+ import fs5 from "fs";
8130
7946
  var DEFAULT_REGISTRY_PATH = "/tmp/vm0-vm-registry.json";
8131
7947
  var VMRegistry = class {
8132
7948
  registryPath;
@@ -8140,8 +7956,8 @@ var VMRegistry = class {
8140
7956
  */
8141
7957
  load() {
8142
7958
  try {
8143
- if (fs6.existsSync(this.registryPath)) {
8144
- const content = fs6.readFileSync(this.registryPath, "utf-8");
7959
+ if (fs5.existsSync(this.registryPath)) {
7960
+ const content = fs5.readFileSync(this.registryPath, "utf-8");
8145
7961
  return JSON.parse(content);
8146
7962
  }
8147
7963
  } catch {
@@ -8155,8 +7971,8 @@ var VMRegistry = class {
8155
7971
  this.data.updatedAt = Date.now();
8156
7972
  const content = JSON.stringify(this.data, null, 2);
8157
7973
  const tempPath = `${this.registryPath}.tmp`;
8158
- fs6.writeFileSync(tempPath, content, { mode: 420 });
8159
- fs6.renameSync(tempPath, this.registryPath);
7974
+ fs5.writeFileSync(tempPath, content, { mode: 420 });
7975
+ fs5.renameSync(tempPath, this.registryPath);
8160
7976
  }
8161
7977
  /**
8162
7978
  * Register a VM with its IP address
@@ -8231,8 +8047,8 @@ function initVMRegistry(registryPath) {
8231
8047
 
8232
8048
  // src/lib/proxy/proxy-manager.ts
8233
8049
  import { spawn as spawn2 } from "child_process";
8234
- import fs7 from "fs";
8235
- import path4 from "path";
8050
+ import fs6 from "fs";
8051
+ import path3 from "path";
8236
8052
 
8237
8053
  // src/lib/proxy/mitm-addon-script.ts
8238
8054
  var RUNNER_MITM_ADDON_SCRIPT = `#!/usr/bin/env python3
@@ -8725,7 +8541,7 @@ var ProxyManager = class {
8725
8541
  process = null;
8726
8542
  isRunning = false;
8727
8543
  constructor(config) {
8728
- const addonPath = path4.join(config.caDir, "mitm_addon.py");
8544
+ const addonPath = path3.join(config.caDir, "mitm_addon.py");
8729
8545
  this.config = {
8730
8546
  ...DEFAULT_PROXY_OPTIONS,
8731
8547
  ...config,
@@ -8752,11 +8568,11 @@ var ProxyManager = class {
8752
8568
  * Ensure the addon script exists at the configured path
8753
8569
  */
8754
8570
  ensureAddonScript() {
8755
- const addonDir = path4.dirname(this.config.addonPath);
8756
- if (!fs7.existsSync(addonDir)) {
8757
- fs7.mkdirSync(addonDir, { recursive: true });
8571
+ const addonDir = path3.dirname(this.config.addonPath);
8572
+ if (!fs6.existsSync(addonDir)) {
8573
+ fs6.mkdirSync(addonDir, { recursive: true });
8758
8574
  }
8759
- fs7.writeFileSync(this.config.addonPath, RUNNER_MITM_ADDON_SCRIPT, {
8575
+ fs6.writeFileSync(this.config.addonPath, RUNNER_MITM_ADDON_SCRIPT, {
8760
8576
  mode: 493
8761
8577
  });
8762
8578
  console.log(
@@ -8767,11 +8583,11 @@ var ProxyManager = class {
8767
8583
  * Validate proxy configuration
8768
8584
  */
8769
8585
  validateConfig() {
8770
- if (!fs7.existsSync(this.config.caDir)) {
8586
+ if (!fs6.existsSync(this.config.caDir)) {
8771
8587
  throw new Error(`Proxy CA directory not found: ${this.config.caDir}`);
8772
8588
  }
8773
- const caCertPath = path4.join(this.config.caDir, "mitmproxy-ca.pem");
8774
- if (!fs7.existsSync(caCertPath)) {
8589
+ const caCertPath = path3.join(this.config.caDir, "mitmproxy-ca.pem");
8590
+ if (!fs6.existsSync(caCertPath)) {
8775
8591
  throw new Error(`Proxy CA certificate not found: ${caCertPath}`);
8776
8592
  }
8777
8593
  this.ensureAddonScript();
@@ -9161,17 +8977,17 @@ function buildEnvironmentVariables(context, apiUrl) {
9161
8977
  }
9162
8978
 
9163
8979
  // src/lib/network-logs/network-logs.ts
9164
- import fs8 from "fs";
8980
+ import fs7 from "fs";
9165
8981
  function getNetworkLogPath(runId) {
9166
8982
  return `/tmp/vm0-network-${runId}.jsonl`;
9167
8983
  }
9168
8984
  function readNetworkLogs(runId) {
9169
8985
  const logPath = getNetworkLogPath(runId);
9170
- if (!fs8.existsSync(logPath)) {
8986
+ if (!fs7.existsSync(logPath)) {
9171
8987
  return [];
9172
8988
  }
9173
8989
  try {
9174
- const content = fs8.readFileSync(logPath, "utf-8");
8990
+ const content = fs7.readFileSync(logPath, "utf-8");
9175
8991
  const lines = content.split("\n").filter((line) => line.trim());
9176
8992
  return lines.map((line) => JSON.parse(line));
9177
8993
  } catch (err) {
@@ -9184,8 +9000,8 @@ function readNetworkLogs(runId) {
9184
9000
  function cleanupNetworkLogs(runId) {
9185
9001
  const logPath = getNetworkLogPath(runId);
9186
9002
  try {
9187
- if (fs8.existsSync(logPath)) {
9188
- fs8.unlinkSync(logPath);
9003
+ if (fs7.existsSync(logPath)) {
9004
+ fs7.unlinkSync(logPath);
9189
9005
  }
9190
9006
  } catch (err) {
9191
9007
  console.error(
@@ -9228,7 +9044,7 @@ async function uploadNetworkLogs(apiUrl, sandboxToken, runId) {
9228
9044
  }
9229
9045
 
9230
9046
  // src/lib/vm-setup/vm-setup.ts
9231
- import fs9 from "fs";
9047
+ import fs8 from "fs";
9232
9048
 
9233
9049
  // src/lib/scripts/utils.ts
9234
9050
  function getAllScripts() {
@@ -9290,12 +9106,12 @@ async function restoreSessionHistory(guest, resumeSession, workingDir, cliAgentT
9290
9106
  );
9291
9107
  }
9292
9108
  async function installProxyCA(guest, caCertPath) {
9293
- if (!fs9.existsSync(caCertPath)) {
9109
+ if (!fs8.existsSync(caCertPath)) {
9294
9110
  throw new Error(
9295
9111
  `Proxy CA certificate not found at ${caCertPath}. Run generate-proxy-ca.sh first.`
9296
9112
  );
9297
9113
  }
9298
- const caCert = fs9.readFileSync(caCertPath, "utf-8");
9114
+ const caCert = fs8.readFileSync(caCertPath, "utf-8");
9299
9115
  console.log(
9300
9116
  `[Executor] Installing proxy CA certificate (${caCert.length} bytes)`
9301
9117
  );
@@ -9376,7 +9192,7 @@ async function executeJob(context, config, options = {}) {
9376
9192
  const log = options.logger ?? ((msg) => console.log(msg));
9377
9193
  log(`[Executor] Starting job ${context.runId} in VM ${vmId}`);
9378
9194
  try {
9379
- const workspacesDir = path5.join(process.cwd(), "workspaces");
9195
+ const workspacesDir = path4.join(process.cwd(), "workspaces");
9380
9196
  const vmConfig = {
9381
9197
  vmId,
9382
9198
  vcpus: config.sandbox.vcpu,
@@ -9384,7 +9200,7 @@ async function executeJob(context, config, options = {}) {
9384
9200
  kernelPath: config.firecracker.kernel,
9385
9201
  rootfsPath: config.firecracker.rootfs,
9386
9202
  firecrackerBinary: config.firecracker.binary,
9387
- workDir: path5.join(workspacesDir, `vm0-${vmId}`)
9203
+ workDir: path4.join(workspacesDir, `vm0-${vmId}`)
9388
9204
  };
9389
9205
  log(`[Executor] Creating VM ${vmId}...`);
9390
9206
  vm = new FirecrackerVM(vmConfig);
@@ -9394,27 +9210,15 @@ async function executeJob(context, config, options = {}) {
9394
9210
  throw new Error("VM started but no IP address available");
9395
9211
  }
9396
9212
  log(`[Executor] VM ${vmId} started, guest IP: ${guestIp}`);
9397
- const guestProtocol = config.sandbox.guest_protocol;
9398
- let guest;
9399
- if (guestProtocol === "ssh") {
9400
- const sshKeyPath = getRunnerSSHKeyPath();
9401
- guest = new SSHClient({
9402
- host: guestIp,
9403
- user: "user",
9404
- privateKeyPath: sshKeyPath || void 0
9405
- });
9406
- log(`[Executor] Using SSH for guest communication: ${guestIp}`);
9407
- } else {
9408
- const vsockPath = vm.getVsockPath();
9409
- guest = new VsockClient(vsockPath);
9410
- log(`[Executor] Using vsock for guest communication: ${vsockPath}`);
9411
- }
9412
- log(`[Executor] Verifying ${guestProtocol} connectivity...`);
9213
+ const vsockPath = vm.getVsockPath();
9214
+ const guest = new VsockClient(vsockPath);
9215
+ log(`[Executor] Using vsock for guest communication: ${vsockPath}`);
9216
+ log(`[Executor] Verifying vsock connectivity...`);
9413
9217
  await withSandboxTiming(
9414
9218
  "guest_wait",
9415
9219
  () => guest.waitUntilReachable(3e4, 1e3)
9416
9220
  );
9417
- log(`[Executor] Guest client ready (${guestProtocol})`);
9221
+ log(`[Executor] Guest client ready`);
9418
9222
  const firewallConfig = context.experimentalFirewall;
9419
9223
  if (firewallConfig?.enabled) {
9420
9224
  const mitmEnabled = firewallConfig.experimental_mitm ?? false;
@@ -9429,7 +9233,7 @@ async function executeJob(context, config, options = {}) {
9429
9233
  sealSecretsEnabled
9430
9234
  });
9431
9235
  if (mitmEnabled) {
9432
- const caCertPath = path5.join(
9236
+ const caCertPath = path4.join(
9433
9237
  config.proxy.ca_dir,
9434
9238
  "mitmproxy-ca-cert.pem"
9435
9239
  );
@@ -9859,7 +9663,7 @@ import { dirname as dirname2, join as join3 } from "path";
9859
9663
 
9860
9664
  // src/lib/firecracker/process.ts
9861
9665
  import { readdirSync, readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
9862
- import path6 from "path";
9666
+ import path5 from "path";
9863
9667
  function parseFirecrackerCmdline(cmdline) {
9864
9668
  const args = cmdline.split("\0");
9865
9669
  if (!args[0]?.includes("firecracker")) return null;
@@ -9892,7 +9696,7 @@ function findFirecrackerProcesses() {
9892
9696
  for (const entry of entries) {
9893
9697
  if (!/^\d+$/.test(entry)) continue;
9894
9698
  const pid = parseInt(entry, 10);
9895
- const cmdlinePath = path6.join(procDir, entry, "cmdline");
9699
+ const cmdlinePath = path5.join(procDir, entry, "cmdline");
9896
9700
  if (!existsSync3(cmdlinePath)) continue;
9897
9701
  try {
9898
9702
  const cmdline = readFileSync2(cmdlinePath, "utf-8");
@@ -9949,7 +9753,7 @@ function findMitmproxyProcess() {
9949
9753
  for (const entry of entries) {
9950
9754
  if (!/^\d+$/.test(entry)) continue;
9951
9755
  const pid = parseInt(entry, 10);
9952
- const cmdlinePath = path6.join(procDir, entry, "cmdline");
9756
+ const cmdlinePath = path5.join(procDir, entry, "cmdline");
9953
9757
  if (!existsSync3(cmdlinePath)) continue;
9954
9758
  try {
9955
9759
  const cmdline = readFileSync2(cmdlinePath, "utf-8");
@@ -10345,7 +10149,7 @@ async function confirm(message) {
10345
10149
  }
10346
10150
 
10347
10151
  // src/commands/benchmark.ts
10348
- import { Command as Command4, Option } from "commander";
10152
+ import { Command as Command4 } from "commander";
10349
10153
  import crypto2 from "crypto";
10350
10154
 
10351
10155
  // src/lib/timing.ts
@@ -10398,19 +10202,11 @@ function createBenchmarkContext(prompt, options) {
10398
10202
  }
10399
10203
  var benchmarkCommand = new Command4("benchmark").description(
10400
10204
  "Run a VM performance benchmark (executes bash command directly)"
10401
- ).argument("<prompt>", "The bash command to execute in the VM").option("--config <path>", "Config file path", "./runner.yaml").option("--working-dir <path>", "Working directory in VM", "/home/user").option("--agent-type <type>", "Agent type", "claude-code").addOption(
10402
- new Option(
10403
- "--guest-protocol <protocol>",
10404
- "Guest communication protocol"
10405
- ).choices(["vsock", "ssh"])
10406
- ).action(async (prompt, options) => {
10205
+ ).argument("<prompt>", "The bash command to execute in the VM").option("--config <path>", "Config file path", "./runner.yaml").option("--working-dir <path>", "Working directory in VM", "/home/user").option("--agent-type <type>", "Agent type", "claude-code").action(async (prompt, options) => {
10407
10206
  const timer = new Timer();
10408
10207
  try {
10409
10208
  timer.log("Loading configuration...");
10410
10209
  const config = loadDebugConfig(options.config);
10411
- if (options.guestProtocol) {
10412
- config.sandbox.guest_protocol = options.guestProtocol;
10413
- }
10414
10210
  validateFirecrackerPaths(config.firecracker);
10415
10211
  timer.log("Checking network prerequisites...");
10416
10212
  const networkCheck = checkNetworkPrerequisites();
@@ -10444,7 +10240,7 @@ var benchmarkCommand = new Command4("benchmark").description(
10444
10240
  });
10445
10241
 
10446
10242
  // src/index.ts
10447
- var version = true ? "2.15.0" : "0.1.0";
10243
+ var version = true ? "3.0.1" : "0.1.0";
10448
10244
  program.name("vm0-runner").version(version).description("Self-hosted runner for VM0 agents");
10449
10245
  program.addCommand(startCommand);
10450
10246
  program.addCommand(doctorCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/runner",
3
- "version": "2.15.0",
3
+ "version": "3.0.1",
4
4
  "description": "Self-hosted runner for VM0 agents",
5
5
  "repository": {
6
6
  "type": "git",