@vm0/cli 1.0.0 → 1.2.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 +241 -9
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -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();
|
|
@@ -12343,7 +12348,7 @@ var ApiClient = class {
|
|
|
12343
12348
|
);
|
|
12344
12349
|
if (!response.ok) {
|
|
12345
12350
|
const error43 = await response.json();
|
|
12346
|
-
throw new Error(error43.error || `Config not found: ${name}`);
|
|
12351
|
+
throw new Error(error43.error?.message || `Config not found: ${name}`);
|
|
12347
12352
|
}
|
|
12348
12353
|
return await response.json();
|
|
12349
12354
|
}
|
|
@@ -12357,7 +12362,7 @@ var ApiClient = class {
|
|
|
12357
12362
|
});
|
|
12358
12363
|
if (!response.ok) {
|
|
12359
12364
|
const error43 = await response.json();
|
|
12360
|
-
throw new Error(error43.error || "Failed to create config");
|
|
12365
|
+
throw new Error(error43.error?.message || "Failed to create config");
|
|
12361
12366
|
}
|
|
12362
12367
|
return await response.json();
|
|
12363
12368
|
}
|
|
@@ -12371,7 +12376,8 @@ var ApiClient = class {
|
|
|
12371
12376
|
});
|
|
12372
12377
|
if (!response.ok) {
|
|
12373
12378
|
const error43 = await response.json();
|
|
12374
|
-
|
|
12379
|
+
const message = error43.error?.message || "Failed to create run";
|
|
12380
|
+
throw new Error(message);
|
|
12375
12381
|
}
|
|
12376
12382
|
return await response.json();
|
|
12377
12383
|
}
|
|
@@ -12389,7 +12395,21 @@ var ApiClient = class {
|
|
|
12389
12395
|
);
|
|
12390
12396
|
if (!response.ok) {
|
|
12391
12397
|
const error43 = await response.json();
|
|
12392
|
-
throw new Error(error43.error || "Failed to fetch events");
|
|
12398
|
+
throw new Error(error43.error?.message || "Failed to fetch events");
|
|
12399
|
+
}
|
|
12400
|
+
return await response.json();
|
|
12401
|
+
}
|
|
12402
|
+
async resumeRun(body) {
|
|
12403
|
+
const baseUrl = await this.getBaseUrl();
|
|
12404
|
+
const headers = await this.getHeaders();
|
|
12405
|
+
const response = await fetch(`${baseUrl}/api/agent/runs/resume`, {
|
|
12406
|
+
method: "POST",
|
|
12407
|
+
headers,
|
|
12408
|
+
body: JSON.stringify(body)
|
|
12409
|
+
});
|
|
12410
|
+
if (!response.ok) {
|
|
12411
|
+
const error43 = await response.json();
|
|
12412
|
+
throw new Error(error43.error?.message || "Failed to resume run");
|
|
12393
12413
|
}
|
|
12394
12414
|
return await response.json();
|
|
12395
12415
|
}
|
|
@@ -12428,6 +12448,62 @@ function validateAgentConfig(config2) {
|
|
|
12428
12448
|
return { valid: true };
|
|
12429
12449
|
}
|
|
12430
12450
|
|
|
12451
|
+
// src/lib/env-expander.ts
|
|
12452
|
+
function expandEnvVars(value) {
|
|
12453
|
+
return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
|
|
12454
|
+
return process.env[varName] ?? "";
|
|
12455
|
+
});
|
|
12456
|
+
}
|
|
12457
|
+
function extractEnvVarReferences(obj) {
|
|
12458
|
+
const varNames = /* @__PURE__ */ new Set();
|
|
12459
|
+
function scan(value) {
|
|
12460
|
+
if (typeof value === "string") {
|
|
12461
|
+
const matches = value.matchAll(/\$\{([^}]+)\}/g);
|
|
12462
|
+
for (const match of matches) {
|
|
12463
|
+
const varName = match[1];
|
|
12464
|
+
if (varName) {
|
|
12465
|
+
varNames.add(varName);
|
|
12466
|
+
}
|
|
12467
|
+
}
|
|
12468
|
+
} else if (Array.isArray(value)) {
|
|
12469
|
+
for (const item of value) {
|
|
12470
|
+
scan(item);
|
|
12471
|
+
}
|
|
12472
|
+
} else if (value !== null && typeof value === "object") {
|
|
12473
|
+
for (const val of Object.values(value)) {
|
|
12474
|
+
scan(val);
|
|
12475
|
+
}
|
|
12476
|
+
}
|
|
12477
|
+
}
|
|
12478
|
+
scan(obj);
|
|
12479
|
+
return Array.from(varNames);
|
|
12480
|
+
}
|
|
12481
|
+
function validateEnvVars(varNames) {
|
|
12482
|
+
const missing = [];
|
|
12483
|
+
for (const varName of varNames) {
|
|
12484
|
+
if (process.env[varName] === void 0) {
|
|
12485
|
+
missing.push(varName);
|
|
12486
|
+
}
|
|
12487
|
+
}
|
|
12488
|
+
return missing;
|
|
12489
|
+
}
|
|
12490
|
+
function expandEnvVarsInObject(obj) {
|
|
12491
|
+
if (typeof obj === "string") {
|
|
12492
|
+
return expandEnvVars(obj);
|
|
12493
|
+
}
|
|
12494
|
+
if (Array.isArray(obj)) {
|
|
12495
|
+
return obj.map((item) => expandEnvVarsInObject(item));
|
|
12496
|
+
}
|
|
12497
|
+
if (obj !== null && typeof obj === "object") {
|
|
12498
|
+
const result = {};
|
|
12499
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
12500
|
+
result[key] = expandEnvVarsInObject(value);
|
|
12501
|
+
}
|
|
12502
|
+
return result;
|
|
12503
|
+
}
|
|
12504
|
+
return obj;
|
|
12505
|
+
}
|
|
12506
|
+
|
|
12431
12507
|
// src/commands/build.ts
|
|
12432
12508
|
var buildCommand = new Command().name("build").description("Create or update agent configuration").argument("<config-file>", "Path to config YAML file").action(async (configFile) => {
|
|
12433
12509
|
try {
|
|
@@ -12446,6 +12522,24 @@ var buildCommand = new Command().name("build").description("Create or update age
|
|
|
12446
12522
|
}
|
|
12447
12523
|
process.exit(1);
|
|
12448
12524
|
}
|
|
12525
|
+
const referencedVars = extractEnvVarReferences(config2);
|
|
12526
|
+
const missingVars = validateEnvVars(referencedVars);
|
|
12527
|
+
if (missingVars.length > 0) {
|
|
12528
|
+
console.error(chalk2.red("\u2717 Missing required environment variables:"));
|
|
12529
|
+
for (const varName of missingVars) {
|
|
12530
|
+
console.error(chalk2.red(` - ${varName}`));
|
|
12531
|
+
}
|
|
12532
|
+
console.error();
|
|
12533
|
+
console.error(
|
|
12534
|
+
chalk2.gray("Please set these variables before running 'vm0 build'.")
|
|
12535
|
+
);
|
|
12536
|
+
console.error(chalk2.gray("Example:"));
|
|
12537
|
+
for (const varName of missingVars) {
|
|
12538
|
+
console.error(chalk2.gray(` export ${varName}=your-value`));
|
|
12539
|
+
}
|
|
12540
|
+
process.exit(1);
|
|
12541
|
+
}
|
|
12542
|
+
config2 = expandEnvVarsInObject(config2);
|
|
12449
12543
|
const validation = validateAgentConfig(config2);
|
|
12450
12544
|
if (!validation.valid) {
|
|
12451
12545
|
console.error(chalk2.red(`\u2717 ${validation.error}`));
|
|
@@ -12503,6 +12597,12 @@ var ClaudeEventParser = class {
|
|
|
12503
12597
|
return this.parseUserMessage(rawEvent);
|
|
12504
12598
|
case "result":
|
|
12505
12599
|
return this.parseResultEvent(rawEvent);
|
|
12600
|
+
case "vm0_start":
|
|
12601
|
+
return this.parseVm0StartEvent(rawEvent);
|
|
12602
|
+
case "vm0_result":
|
|
12603
|
+
return this.parseVm0ResultEvent(rawEvent);
|
|
12604
|
+
case "vm0_error":
|
|
12605
|
+
return this.parseVm0ErrorEvent(rawEvent);
|
|
12506
12606
|
default:
|
|
12507
12607
|
return null;
|
|
12508
12608
|
}
|
|
@@ -12585,6 +12685,42 @@ var ClaudeEventParser = class {
|
|
|
12585
12685
|
}
|
|
12586
12686
|
};
|
|
12587
12687
|
}
|
|
12688
|
+
static parseVm0StartEvent(event) {
|
|
12689
|
+
return {
|
|
12690
|
+
type: "vm0_start",
|
|
12691
|
+
timestamp: new Date(event.timestamp),
|
|
12692
|
+
data: {
|
|
12693
|
+
runId: event.runId,
|
|
12694
|
+
agentConfigId: event.agentConfigId,
|
|
12695
|
+
agentName: event.agentName,
|
|
12696
|
+
prompt: event.prompt,
|
|
12697
|
+
dynamicVars: event.dynamicVars
|
|
12698
|
+
}
|
|
12699
|
+
};
|
|
12700
|
+
}
|
|
12701
|
+
static parseVm0ResultEvent(event) {
|
|
12702
|
+
return {
|
|
12703
|
+
type: "vm0_result",
|
|
12704
|
+
timestamp: new Date(event.timestamp),
|
|
12705
|
+
data: {
|
|
12706
|
+
runId: event.runId,
|
|
12707
|
+
checkpointId: event.checkpointId,
|
|
12708
|
+
volumeSnapshots: event.volumeSnapshots
|
|
12709
|
+
}
|
|
12710
|
+
};
|
|
12711
|
+
}
|
|
12712
|
+
static parseVm0ErrorEvent(event) {
|
|
12713
|
+
return {
|
|
12714
|
+
type: "vm0_error",
|
|
12715
|
+
timestamp: new Date(event.timestamp),
|
|
12716
|
+
data: {
|
|
12717
|
+
runId: event.runId,
|
|
12718
|
+
error: event.error,
|
|
12719
|
+
errorType: event.errorType,
|
|
12720
|
+
sandboxId: event.sandboxId
|
|
12721
|
+
}
|
|
12722
|
+
};
|
|
12723
|
+
}
|
|
12588
12724
|
};
|
|
12589
12725
|
|
|
12590
12726
|
// src/lib/event-renderer.ts
|
|
@@ -12610,6 +12746,15 @@ var EventRenderer = class {
|
|
|
12610
12746
|
case "result":
|
|
12611
12747
|
this.renderResult(event);
|
|
12612
12748
|
break;
|
|
12749
|
+
case "vm0_start":
|
|
12750
|
+
this.renderVm0Start(event);
|
|
12751
|
+
break;
|
|
12752
|
+
case "vm0_result":
|
|
12753
|
+
this.renderVm0Result(event);
|
|
12754
|
+
break;
|
|
12755
|
+
case "vm0_error":
|
|
12756
|
+
this.renderVm0Error(event);
|
|
12757
|
+
break;
|
|
12613
12758
|
}
|
|
12614
12759
|
}
|
|
12615
12760
|
static renderInit(event) {
|
|
@@ -12678,6 +12823,43 @@ var EventRenderer = class {
|
|
|
12678
12823
|
);
|
|
12679
12824
|
}
|
|
12680
12825
|
}
|
|
12826
|
+
static renderVm0Start(event) {
|
|
12827
|
+
console.log(chalk3.cyan("[vm0_start]") + " Run starting");
|
|
12828
|
+
const prompt = String(event.data.prompt || "");
|
|
12829
|
+
const displayPrompt = prompt.length > 100 ? prompt.substring(0, 100) + "..." : prompt;
|
|
12830
|
+
console.log(` Prompt: ${chalk3.gray(displayPrompt)}`);
|
|
12831
|
+
if (event.data.agentName) {
|
|
12832
|
+
console.log(` Agent: ${chalk3.gray(String(event.data.agentName))}`);
|
|
12833
|
+
}
|
|
12834
|
+
}
|
|
12835
|
+
static renderVm0Result(event) {
|
|
12836
|
+
console.log(chalk3.green("[vm0_result]") + " \u2713 Run completed successfully");
|
|
12837
|
+
console.log(
|
|
12838
|
+
` Checkpoint: ${chalk3.gray(String(event.data.checkpointId || ""))}`
|
|
12839
|
+
);
|
|
12840
|
+
const volumeSnapshots = Number(event.data.volumeSnapshots || 0);
|
|
12841
|
+
if (volumeSnapshots > 0) {
|
|
12842
|
+
console.log(` Volume snapshots: ${chalk3.gray(String(volumeSnapshots))}`);
|
|
12843
|
+
}
|
|
12844
|
+
}
|
|
12845
|
+
static renderVm0Error(event) {
|
|
12846
|
+
console.log(chalk3.red("[vm0_error]") + " \u2717 Run failed");
|
|
12847
|
+
let errorMessage = "";
|
|
12848
|
+
if (typeof event.data.error === "string") {
|
|
12849
|
+
errorMessage = event.data.error;
|
|
12850
|
+
} else if (event.data.error && typeof event.data.error === "object") {
|
|
12851
|
+
const errorObj = event.data.error;
|
|
12852
|
+
if ("message" in errorObj && typeof errorObj.message === "string") {
|
|
12853
|
+
errorMessage = errorObj.message;
|
|
12854
|
+
} else {
|
|
12855
|
+
errorMessage = JSON.stringify(event.data.error);
|
|
12856
|
+
}
|
|
12857
|
+
}
|
|
12858
|
+
console.log(` Error: ${chalk3.red(errorMessage || "Unknown error")}`);
|
|
12859
|
+
if (event.data.errorType) {
|
|
12860
|
+
console.log(` Type: ${chalk3.gray(String(event.data.errorType))}`);
|
|
12861
|
+
}
|
|
12862
|
+
}
|
|
12681
12863
|
};
|
|
12682
12864
|
|
|
12683
12865
|
// src/commands/run.ts
|
|
@@ -12693,19 +12875,32 @@ function isUUID(str) {
|
|
|
12693
12875
|
return /^[0-9a-f-]{36}$/i.test(str);
|
|
12694
12876
|
}
|
|
12695
12877
|
async function pollEvents(runId) {
|
|
12696
|
-
let nextSequence =
|
|
12878
|
+
let nextSequence = -1;
|
|
12697
12879
|
let complete = false;
|
|
12698
12880
|
const pollIntervalMs = 500;
|
|
12881
|
+
const timeoutMs = 3 * 60 * 1e3;
|
|
12882
|
+
const startTime = Date.now();
|
|
12699
12883
|
while (!complete) {
|
|
12884
|
+
const elapsed = Date.now() - startTime;
|
|
12885
|
+
if (elapsed > timeoutMs) {
|
|
12886
|
+
console.error(
|
|
12887
|
+
chalk4.red(
|
|
12888
|
+
"\n\u2717 Agent execution timed out after 3 minutes without receiving events"
|
|
12889
|
+
)
|
|
12890
|
+
);
|
|
12891
|
+
throw new Error("Agent execution timed out");
|
|
12892
|
+
}
|
|
12700
12893
|
try {
|
|
12701
12894
|
const response = await apiClient.getEvents(runId, {
|
|
12702
12895
|
since: nextSequence
|
|
12703
12896
|
});
|
|
12704
12897
|
for (const event of response.events) {
|
|
12705
|
-
const parsed = ClaudeEventParser.parse(
|
|
12898
|
+
const parsed = ClaudeEventParser.parse(
|
|
12899
|
+
event.eventData
|
|
12900
|
+
);
|
|
12706
12901
|
if (parsed) {
|
|
12707
12902
|
EventRenderer.render(parsed);
|
|
12708
|
-
if (parsed.type === "
|
|
12903
|
+
if (parsed.type === "vm0_result" || parsed.type === "vm0_error") {
|
|
12709
12904
|
complete = true;
|
|
12710
12905
|
}
|
|
12711
12906
|
}
|
|
@@ -12723,7 +12918,7 @@ async function pollEvents(runId) {
|
|
|
12723
12918
|
}
|
|
12724
12919
|
}
|
|
12725
12920
|
}
|
|
12726
|
-
var
|
|
12921
|
+
var runCmd = new Command2().name("run").description("Execute an agent").argument(
|
|
12727
12922
|
"<identifier>",
|
|
12728
12923
|
"Agent name or config ID (e.g., 'my-agent' or 'cfg-abc-123')"
|
|
12729
12924
|
).argument("<prompt>", "Prompt for the agent").option(
|
|
@@ -12794,6 +12989,43 @@ var runCommand = new Command2().name("run").description("Execute an agent").argu
|
|
|
12794
12989
|
}
|
|
12795
12990
|
}
|
|
12796
12991
|
);
|
|
12992
|
+
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) => {
|
|
12993
|
+
try {
|
|
12994
|
+
if (!isUUID(checkpointId)) {
|
|
12995
|
+
console.error(
|
|
12996
|
+
chalk4.red(`\u2717 Invalid checkpoint ID format: ${checkpointId}`)
|
|
12997
|
+
);
|
|
12998
|
+
console.error(chalk4.gray(" Checkpoint ID must be a valid UUID"));
|
|
12999
|
+
process.exit(1);
|
|
13000
|
+
}
|
|
13001
|
+
console.log(chalk4.blue("\nResuming agent run from checkpoint..."));
|
|
13002
|
+
console.log(chalk4.gray(` Checkpoint ID: ${checkpointId}`));
|
|
13003
|
+
console.log(chalk4.gray(` Prompt: ${prompt}`));
|
|
13004
|
+
console.log();
|
|
13005
|
+
console.log(chalk4.blue("Executing in sandbox..."));
|
|
13006
|
+
console.log();
|
|
13007
|
+
const response = await apiClient.resumeRun({
|
|
13008
|
+
checkpointId,
|
|
13009
|
+
prompt
|
|
13010
|
+
});
|
|
13011
|
+
await pollEvents(response.runId);
|
|
13012
|
+
} catch (error43) {
|
|
13013
|
+
if (error43 instanceof Error) {
|
|
13014
|
+
if (error43.message.includes("Not authenticated")) {
|
|
13015
|
+
console.error(chalk4.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
13016
|
+
} else if (error43.message.includes("not found")) {
|
|
13017
|
+
console.error(chalk4.red(`\u2717 Checkpoint not found: ${checkpointId}`));
|
|
13018
|
+
} else {
|
|
13019
|
+
console.error(chalk4.red("\u2717 Resume failed"));
|
|
13020
|
+
console.error(chalk4.gray(` ${error43.message}`));
|
|
13021
|
+
}
|
|
13022
|
+
} else {
|
|
13023
|
+
console.error(chalk4.red("\u2717 An unexpected error occurred"));
|
|
13024
|
+
}
|
|
13025
|
+
process.exit(1);
|
|
13026
|
+
}
|
|
13027
|
+
});
|
|
13028
|
+
var runCommand = runCmd;
|
|
12797
13029
|
|
|
12798
13030
|
// src/index.ts
|
|
12799
13031
|
var program = new Command3();
|