@vm0/runner 2.0.1 → 2.0.3

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 +42 -24
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -105,7 +105,7 @@ async function claimJob(server, runId) {
105
105
  }
106
106
  return response.json();
107
107
  }
108
- async function completeJob(context, exitCode, error) {
108
+ async function completeJob(apiUrl, context, exitCode, error) {
109
109
  const headers = {
110
110
  Authorization: `Bearer ${context.sandboxToken}`,
111
111
  "Content-Type": "application/json"
@@ -114,18 +114,15 @@ async function completeJob(context, exitCode, error) {
114
114
  if (bypassSecret) {
115
115
  headers["x-vercel-protection-bypass"] = bypassSecret;
116
116
  }
117
- const response = await fetch(
118
- `${context.apiUrl}/api/webhooks/agent/complete`,
119
- {
120
- method: "POST",
121
- headers,
122
- body: JSON.stringify({
123
- runId: context.runId,
124
- exitCode,
125
- error
126
- })
127
- }
128
- );
117
+ const response = await fetch(`${apiUrl}/api/webhooks/agent/complete`, {
118
+ method: "POST",
119
+ headers,
120
+ body: JSON.stringify({
121
+ runId: context.runId,
122
+ exitCode,
123
+ error
124
+ })
125
+ });
129
126
  if (!response.ok) {
130
127
  const errorData = await response.json();
131
128
  throw new Error(
@@ -827,6 +824,28 @@ var SSHClient = class {
827
824
  }
828
825
  }
829
826
  }
827
+ /**
828
+ * Write content to a file on the remote VM using sudo
829
+ * Used for writing to privileged locations like /usr/local/bin
830
+ */
831
+ async writeFileWithSudo(remotePath, content) {
832
+ const encoded = Buffer.from(content).toString("base64");
833
+ const maxChunkSize = 65e3;
834
+ if (encoded.length <= maxChunkSize) {
835
+ await this.execOrThrow(
836
+ `echo '${encoded}' | base64 -d | sudo tee '${remotePath}' > /dev/null`
837
+ );
838
+ } else {
839
+ await this.execOrThrow(`sudo rm -f '${remotePath}'`);
840
+ for (let i = 0; i < encoded.length; i += maxChunkSize) {
841
+ const chunk = encoded.slice(i, i + maxChunkSize);
842
+ const teeFlag = i === 0 ? "" : "-a";
843
+ await this.execOrThrow(
844
+ `echo '${chunk}' | base64 -d | sudo tee ${teeFlag} '${remotePath}' > /dev/null`
845
+ );
846
+ }
847
+ }
848
+ }
830
849
  /**
831
850
  * Read a file from the remote VM
832
851
  */
@@ -6169,7 +6188,6 @@ var executionContextSchema = z15.object({
6169
6188
  secretNames: z15.array(z15.string()).nullable(),
6170
6189
  checkpointId: z15.string().uuid().nullable(),
6171
6190
  sandboxToken: z15.string(),
6172
- apiUrl: z15.string(),
6173
6191
  // New fields for E2B parity:
6174
6192
  workingDir: z15.string(),
6175
6193
  storageManifest: storageManifestSchema.nullable(),
@@ -9010,9 +9028,9 @@ function getAllScripts() {
9010
9028
  function getVmIdFromRunId(runId) {
9011
9029
  return runId.split("-")[0] || runId.substring(0, 8);
9012
9030
  }
9013
- function buildEnvironmentVariables(context) {
9031
+ function buildEnvironmentVariables(context, apiUrl) {
9014
9032
  const envVars = {
9015
- VM0_API_URL: context.apiUrl,
9033
+ VM0_API_URL: apiUrl,
9016
9034
  VM0_RUN_ID: context.runId,
9017
9035
  VM0_API_TOKEN: context.sandboxToken,
9018
9036
  VM0_PROMPT: context.prompt,
@@ -9054,13 +9072,13 @@ var ENV_JSON_PATH = "/tmp/vm0-env.json";
9054
9072
  async function uploadScripts(ssh) {
9055
9073
  const scripts = getAllScripts();
9056
9074
  await ssh.execOrThrow(
9057
- `mkdir -p ${SCRIPT_PATHS.baseDir} ${SCRIPT_PATHS.libDir}`
9075
+ `sudo mkdir -p ${SCRIPT_PATHS.baseDir} ${SCRIPT_PATHS.libDir}`
9058
9076
  );
9059
9077
  for (const script of scripts) {
9060
- await ssh.writeFile(script.path, script.content);
9078
+ await ssh.writeFileWithSudo(script.path, script.content);
9061
9079
  }
9062
9080
  await ssh.execOrThrow(
9063
- `chmod +x ${SCRIPT_PATHS.baseDir}/*.py ${SCRIPT_PATHS.libDir}/*.py 2>/dev/null || true`
9081
+ `sudo chmod +x ${SCRIPT_PATHS.baseDir}/*.py ${SCRIPT_PATHS.libDir}/*.py 2>/dev/null || true`
9064
9082
  );
9065
9083
  }
9066
9084
  async function downloadStorages(ssh, manifest) {
@@ -9105,7 +9123,7 @@ async function configureDNS(ssh) {
9105
9123
  nameserver 8.8.4.4
9106
9124
  nameserver 1.1.1.1`;
9107
9125
  await ssh.execOrThrow(
9108
- `rm -f /etc/resolv.conf && echo '${dnsConfig}' > /etc/resolv.conf`
9126
+ `sudo sh -c 'rm -f /etc/resolv.conf && echo "${dnsConfig}" > /etc/resolv.conf'`
9109
9127
  );
9110
9128
  }
9111
9129
  async function executeJob(context, config) {
@@ -9132,7 +9150,7 @@ async function executeJob(context, config) {
9132
9150
  }
9133
9151
  console.log(`[Executor] VM ${vmId} started, guest IP: ${guestIp}`);
9134
9152
  const privateKeyPath = getRunnerSSHKeyPath();
9135
- const ssh = createVMSSHClient(guestIp, "root", privateKeyPath || void 0);
9153
+ const ssh = createVMSSHClient(guestIp, "user", privateKeyPath || void 0);
9136
9154
  console.log(`[Executor] Waiting for SSH on ${guestIp}...`);
9137
9155
  await ssh.waitUntilReachable(12e4, 2e3);
9138
9156
  console.log(`[Executor] SSH ready on ${guestIp}`);
@@ -9152,7 +9170,7 @@ async function executeJob(context, config) {
9152
9170
  context.cliAgentType || "claude-code"
9153
9171
  );
9154
9172
  }
9155
- const envVars = buildEnvironmentVariables(context);
9173
+ const envVars = buildEnvironmentVariables(context, config.server.url);
9156
9174
  const envJson = JSON.stringify(envVars);
9157
9175
  console.log(
9158
9176
  `[Executor] Writing env JSON (${envJson.length} bytes) to ${ENV_JSON_PATH}`
@@ -9232,7 +9250,7 @@ async function executeJob2(context, config) {
9232
9250
  } catch (err) {
9233
9251
  const error = err instanceof Error ? err.message : "Unknown execution error";
9234
9252
  console.error(` Job ${context.runId} execution failed: ${error}`);
9235
- const result = await completeJob(context, 1, error);
9253
+ const result = await completeJob(config.server.url, context, 1, error);
9236
9254
  console.log(` Job ${context.runId} reported as ${result.status}`);
9237
9255
  }
9238
9256
  }
@@ -9337,7 +9355,7 @@ var statusCommand = new Command2("status").description("Show runner status").act
9337
9355
  });
9338
9356
 
9339
9357
  // src/index.ts
9340
- var version = true ? "2.0.1" : "0.1.0";
9358
+ var version = true ? "2.0.3" : "0.1.0";
9341
9359
  program.name("vm0-runner").version(version).description("Self-hosted runner for VM0 agents");
9342
9360
  program.addCommand(startCommand);
9343
9361
  program.addCommand(statusCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/runner",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Self-hosted runner for VM0 agents",
5
5
  "repository": {
6
6
  "type": "git",