@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.
- package/index.js +42 -24
- 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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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:
|
|
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.
|
|
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
|
|
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, "
|
|
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.
|
|
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);
|