@vm0/cli 0.3.0 → 1.1.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 +179 -9
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -12182,9 +12182,9 @@ async function getToken() {
|
|
|
12182
12182
|
}
|
|
12183
12183
|
async function getApiUrl() {
|
|
12184
12184
|
const config2 = await loadConfig();
|
|
12185
|
-
const
|
|
12186
|
-
if (
|
|
12187
|
-
return
|
|
12185
|
+
const apiUrl = process.env.VM0_API_URL;
|
|
12186
|
+
if (apiUrl) {
|
|
12187
|
+
return apiUrl.startsWith("http") ? apiUrl : `https://${apiUrl}`;
|
|
12188
12188
|
}
|
|
12189
12189
|
return config2.apiUrl ?? "https://www.vm0.ai";
|
|
12190
12190
|
}
|
|
@@ -12319,10 +12319,15 @@ var ApiClient = class {
|
|
|
12319
12319
|
if (!token) {
|
|
12320
12320
|
throw new Error("Not authenticated. Run: vm0 auth login");
|
|
12321
12321
|
}
|
|
12322
|
-
|
|
12322
|
+
const headers = {
|
|
12323
12323
|
Authorization: `Bearer ${token}`,
|
|
12324
12324
|
"Content-Type": "application/json"
|
|
12325
12325
|
};
|
|
12326
|
+
const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
12327
|
+
if (bypassSecret) {
|
|
12328
|
+
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
12329
|
+
}
|
|
12330
|
+
return headers;
|
|
12326
12331
|
}
|
|
12327
12332
|
async getBaseUrl() {
|
|
12328
12333
|
const apiUrl = await getApiUrl();
|
|
@@ -12393,6 +12398,20 @@ var ApiClient = class {
|
|
|
12393
12398
|
}
|
|
12394
12399
|
return await response.json();
|
|
12395
12400
|
}
|
|
12401
|
+
async resumeRun(body) {
|
|
12402
|
+
const baseUrl = await this.getBaseUrl();
|
|
12403
|
+
const headers = await this.getHeaders();
|
|
12404
|
+
const response = await fetch(`${baseUrl}/api/agent/runs/resume`, {
|
|
12405
|
+
method: "POST",
|
|
12406
|
+
headers,
|
|
12407
|
+
body: JSON.stringify(body)
|
|
12408
|
+
});
|
|
12409
|
+
if (!response.ok) {
|
|
12410
|
+
const error43 = await response.json();
|
|
12411
|
+
throw new Error(error43.error || "Failed to resume run");
|
|
12412
|
+
}
|
|
12413
|
+
return await response.json();
|
|
12414
|
+
}
|
|
12396
12415
|
};
|
|
12397
12416
|
var apiClient = new ApiClient();
|
|
12398
12417
|
|
|
@@ -12428,6 +12447,29 @@ function validateAgentConfig(config2) {
|
|
|
12428
12447
|
return { valid: true };
|
|
12429
12448
|
}
|
|
12430
12449
|
|
|
12450
|
+
// src/lib/env-expander.ts
|
|
12451
|
+
function expandEnvVars(value) {
|
|
12452
|
+
return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
|
|
12453
|
+
return process.env[varName] ?? "";
|
|
12454
|
+
});
|
|
12455
|
+
}
|
|
12456
|
+
function expandEnvVarsInObject(obj) {
|
|
12457
|
+
if (typeof obj === "string") {
|
|
12458
|
+
return expandEnvVars(obj);
|
|
12459
|
+
}
|
|
12460
|
+
if (Array.isArray(obj)) {
|
|
12461
|
+
return obj.map((item) => expandEnvVarsInObject(item));
|
|
12462
|
+
}
|
|
12463
|
+
if (obj !== null && typeof obj === "object") {
|
|
12464
|
+
const result = {};
|
|
12465
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
12466
|
+
result[key] = expandEnvVarsInObject(value);
|
|
12467
|
+
}
|
|
12468
|
+
return result;
|
|
12469
|
+
}
|
|
12470
|
+
return obj;
|
|
12471
|
+
}
|
|
12472
|
+
|
|
12431
12473
|
// src/commands/build.ts
|
|
12432
12474
|
var buildCommand = new Command().name("build").description("Create or update agent configuration").argument("<config-file>", "Path to config YAML file").action(async (configFile) => {
|
|
12433
12475
|
try {
|
|
@@ -12446,6 +12488,7 @@ var buildCommand = new Command().name("build").description("Create or update age
|
|
|
12446
12488
|
}
|
|
12447
12489
|
process.exit(1);
|
|
12448
12490
|
}
|
|
12491
|
+
config2 = expandEnvVarsInObject(config2);
|
|
12449
12492
|
const validation = validateAgentConfig(config2);
|
|
12450
12493
|
if (!validation.valid) {
|
|
12451
12494
|
console.error(chalk2.red(`\u2717 ${validation.error}`));
|
|
@@ -12503,6 +12546,12 @@ var ClaudeEventParser = class {
|
|
|
12503
12546
|
return this.parseUserMessage(rawEvent);
|
|
12504
12547
|
case "result":
|
|
12505
12548
|
return this.parseResultEvent(rawEvent);
|
|
12549
|
+
case "vm0_start":
|
|
12550
|
+
return this.parseVm0StartEvent(rawEvent);
|
|
12551
|
+
case "vm0_result":
|
|
12552
|
+
return this.parseVm0ResultEvent(rawEvent);
|
|
12553
|
+
case "vm0_error":
|
|
12554
|
+
return this.parseVm0ErrorEvent(rawEvent);
|
|
12506
12555
|
default:
|
|
12507
12556
|
return null;
|
|
12508
12557
|
}
|
|
@@ -12585,6 +12634,42 @@ var ClaudeEventParser = class {
|
|
|
12585
12634
|
}
|
|
12586
12635
|
};
|
|
12587
12636
|
}
|
|
12637
|
+
static parseVm0StartEvent(event) {
|
|
12638
|
+
return {
|
|
12639
|
+
type: "vm0_start",
|
|
12640
|
+
timestamp: new Date(event.timestamp),
|
|
12641
|
+
data: {
|
|
12642
|
+
runId: event.runId,
|
|
12643
|
+
agentConfigId: event.agentConfigId,
|
|
12644
|
+
agentName: event.agentName,
|
|
12645
|
+
prompt: event.prompt,
|
|
12646
|
+
dynamicVars: event.dynamicVars
|
|
12647
|
+
}
|
|
12648
|
+
};
|
|
12649
|
+
}
|
|
12650
|
+
static parseVm0ResultEvent(event) {
|
|
12651
|
+
return {
|
|
12652
|
+
type: "vm0_result",
|
|
12653
|
+
timestamp: new Date(event.timestamp),
|
|
12654
|
+
data: {
|
|
12655
|
+
runId: event.runId,
|
|
12656
|
+
checkpointId: event.checkpointId,
|
|
12657
|
+
volumeSnapshots: event.volumeSnapshots
|
|
12658
|
+
}
|
|
12659
|
+
};
|
|
12660
|
+
}
|
|
12661
|
+
static parseVm0ErrorEvent(event) {
|
|
12662
|
+
return {
|
|
12663
|
+
type: "vm0_error",
|
|
12664
|
+
timestamp: new Date(event.timestamp),
|
|
12665
|
+
data: {
|
|
12666
|
+
runId: event.runId,
|
|
12667
|
+
error: event.error,
|
|
12668
|
+
errorType: event.errorType,
|
|
12669
|
+
sandboxId: event.sandboxId
|
|
12670
|
+
}
|
|
12671
|
+
};
|
|
12672
|
+
}
|
|
12588
12673
|
};
|
|
12589
12674
|
|
|
12590
12675
|
// src/lib/event-renderer.ts
|
|
@@ -12610,6 +12695,15 @@ var EventRenderer = class {
|
|
|
12610
12695
|
case "result":
|
|
12611
12696
|
this.renderResult(event);
|
|
12612
12697
|
break;
|
|
12698
|
+
case "vm0_start":
|
|
12699
|
+
this.renderVm0Start(event);
|
|
12700
|
+
break;
|
|
12701
|
+
case "vm0_result":
|
|
12702
|
+
this.renderVm0Result(event);
|
|
12703
|
+
break;
|
|
12704
|
+
case "vm0_error":
|
|
12705
|
+
this.renderVm0Error(event);
|
|
12706
|
+
break;
|
|
12613
12707
|
}
|
|
12614
12708
|
}
|
|
12615
12709
|
static renderInit(event) {
|
|
@@ -12678,6 +12772,32 @@ var EventRenderer = class {
|
|
|
12678
12772
|
);
|
|
12679
12773
|
}
|
|
12680
12774
|
}
|
|
12775
|
+
static renderVm0Start(event) {
|
|
12776
|
+
console.log(chalk3.cyan("[vm0_start]") + " Run starting");
|
|
12777
|
+
const prompt = String(event.data.prompt || "");
|
|
12778
|
+
const displayPrompt = prompt.length > 100 ? prompt.substring(0, 100) + "..." : prompt;
|
|
12779
|
+
console.log(` Prompt: ${chalk3.gray(displayPrompt)}`);
|
|
12780
|
+
if (event.data.agentName) {
|
|
12781
|
+
console.log(` Agent: ${chalk3.gray(String(event.data.agentName))}`);
|
|
12782
|
+
}
|
|
12783
|
+
}
|
|
12784
|
+
static renderVm0Result(event) {
|
|
12785
|
+
console.log(chalk3.green("[vm0_result]") + " \u2713 Run completed successfully");
|
|
12786
|
+
console.log(
|
|
12787
|
+
` Checkpoint: ${chalk3.gray(String(event.data.checkpointId || ""))}`
|
|
12788
|
+
);
|
|
12789
|
+
const volumeSnapshots = Number(event.data.volumeSnapshots || 0);
|
|
12790
|
+
if (volumeSnapshots > 0) {
|
|
12791
|
+
console.log(` Volume snapshots: ${chalk3.gray(String(volumeSnapshots))}`);
|
|
12792
|
+
}
|
|
12793
|
+
}
|
|
12794
|
+
static renderVm0Error(event) {
|
|
12795
|
+
console.log(chalk3.red("[vm0_error]") + " \u2717 Run failed");
|
|
12796
|
+
console.log(` Error: ${chalk3.red(String(event.data.error || ""))}`);
|
|
12797
|
+
if (event.data.errorType) {
|
|
12798
|
+
console.log(` Type: ${chalk3.gray(String(event.data.errorType))}`);
|
|
12799
|
+
}
|
|
12800
|
+
}
|
|
12681
12801
|
};
|
|
12682
12802
|
|
|
12683
12803
|
// src/commands/run.ts
|
|
@@ -12693,19 +12813,32 @@ function isUUID(str) {
|
|
|
12693
12813
|
return /^[0-9a-f-]{36}$/i.test(str);
|
|
12694
12814
|
}
|
|
12695
12815
|
async function pollEvents(runId) {
|
|
12696
|
-
let nextSequence =
|
|
12816
|
+
let nextSequence = -1;
|
|
12697
12817
|
let complete = false;
|
|
12698
12818
|
const pollIntervalMs = 500;
|
|
12819
|
+
const timeoutMs = 3 * 60 * 1e3;
|
|
12820
|
+
const startTime = Date.now();
|
|
12699
12821
|
while (!complete) {
|
|
12822
|
+
const elapsed = Date.now() - startTime;
|
|
12823
|
+
if (elapsed > timeoutMs) {
|
|
12824
|
+
console.error(
|
|
12825
|
+
chalk4.red(
|
|
12826
|
+
"\n\u2717 Agent execution timed out after 3 minutes without receiving events"
|
|
12827
|
+
)
|
|
12828
|
+
);
|
|
12829
|
+
throw new Error("Agent execution timed out");
|
|
12830
|
+
}
|
|
12700
12831
|
try {
|
|
12701
12832
|
const response = await apiClient.getEvents(runId, {
|
|
12702
12833
|
since: nextSequence
|
|
12703
12834
|
});
|
|
12704
12835
|
for (const event of response.events) {
|
|
12705
|
-
const parsed = ClaudeEventParser.parse(
|
|
12836
|
+
const parsed = ClaudeEventParser.parse(
|
|
12837
|
+
event.eventData
|
|
12838
|
+
);
|
|
12706
12839
|
if (parsed) {
|
|
12707
12840
|
EventRenderer.render(parsed);
|
|
12708
|
-
if (parsed.type === "
|
|
12841
|
+
if (parsed.type === "vm0_result" || parsed.type === "vm0_error") {
|
|
12709
12842
|
complete = true;
|
|
12710
12843
|
}
|
|
12711
12844
|
}
|
|
@@ -12723,7 +12856,7 @@ async function pollEvents(runId) {
|
|
|
12723
12856
|
}
|
|
12724
12857
|
}
|
|
12725
12858
|
}
|
|
12726
|
-
var
|
|
12859
|
+
var runCmd = new Command2().name("run").description("Execute an agent").argument(
|
|
12727
12860
|
"<identifier>",
|
|
12728
12861
|
"Agent name or config ID (e.g., 'my-agent' or 'cfg-abc-123')"
|
|
12729
12862
|
).argument("<prompt>", "Prompt for the agent").option(
|
|
@@ -12794,6 +12927,43 @@ var runCommand = new Command2().name("run").description("Execute an agent").argu
|
|
|
12794
12927
|
}
|
|
12795
12928
|
}
|
|
12796
12929
|
);
|
|
12930
|
+
runCmd.command("resume").description("Resume an agent run from a checkpoint").argument("<checkpointId>", "Checkpoint ID to resume from").argument("<prompt>", "Prompt for the resumed agent").action(async (checkpointId, prompt) => {
|
|
12931
|
+
try {
|
|
12932
|
+
if (!isUUID(checkpointId)) {
|
|
12933
|
+
console.error(
|
|
12934
|
+
chalk4.red(`\u2717 Invalid checkpoint ID format: ${checkpointId}`)
|
|
12935
|
+
);
|
|
12936
|
+
console.error(chalk4.gray(" Checkpoint ID must be a valid UUID"));
|
|
12937
|
+
process.exit(1);
|
|
12938
|
+
}
|
|
12939
|
+
console.log(chalk4.blue("\nResuming agent run from checkpoint..."));
|
|
12940
|
+
console.log(chalk4.gray(` Checkpoint ID: ${checkpointId}`));
|
|
12941
|
+
console.log(chalk4.gray(` Prompt: ${prompt}`));
|
|
12942
|
+
console.log();
|
|
12943
|
+
console.log(chalk4.blue("Executing in sandbox..."));
|
|
12944
|
+
console.log();
|
|
12945
|
+
const response = await apiClient.resumeRun({
|
|
12946
|
+
checkpointId,
|
|
12947
|
+
prompt
|
|
12948
|
+
});
|
|
12949
|
+
await pollEvents(response.runId);
|
|
12950
|
+
} catch (error43) {
|
|
12951
|
+
if (error43 instanceof Error) {
|
|
12952
|
+
if (error43.message.includes("Not authenticated")) {
|
|
12953
|
+
console.error(chalk4.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
12954
|
+
} else if (error43.message.includes("not found")) {
|
|
12955
|
+
console.error(chalk4.red(`\u2717 Checkpoint not found: ${checkpointId}`));
|
|
12956
|
+
} else {
|
|
12957
|
+
console.error(chalk4.red("\u2717 Resume failed"));
|
|
12958
|
+
console.error(chalk4.gray(` ${error43.message}`));
|
|
12959
|
+
}
|
|
12960
|
+
} else {
|
|
12961
|
+
console.error(chalk4.red("\u2717 An unexpected error occurred"));
|
|
12962
|
+
}
|
|
12963
|
+
process.exit(1);
|
|
12964
|
+
}
|
|
12965
|
+
});
|
|
12966
|
+
var runCommand = runCmd;
|
|
12797
12967
|
|
|
12798
12968
|
// src/index.ts
|
|
12799
12969
|
var program = new Command3();
|
|
@@ -12811,7 +12981,7 @@ program.command("info").description("Display environment information").action(as
|
|
|
12811
12981
|
console.log(`API Host: ${apiUrl}`);
|
|
12812
12982
|
});
|
|
12813
12983
|
var authCommand = program.command("auth").description("Authentication commands");
|
|
12814
|
-
authCommand.command("login").description("Log in to VM0 (use
|
|
12984
|
+
authCommand.command("login").description("Log in to VM0 (use VM0_API_URL env var to set API URL)").action(async () => {
|
|
12815
12985
|
await authenticate();
|
|
12816
12986
|
});
|
|
12817
12987
|
authCommand.command("logout").description("Log out of VM0").action(async () => {
|