@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.
Files changed (2) hide show
  1. package/index.js +241 -9
  2. 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
- return {
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
- throw new Error(error43.error || "Failed to create run");
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 = 0;
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(event.eventData);
12898
+ const parsed = ClaudeEventParser.parse(
12899
+ event.eventData
12900
+ );
12706
12901
  if (parsed) {
12707
12902
  EventRenderer.render(parsed);
12708
- if (parsed.type === "result") {
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 runCommand = new Command2().name("run").description("Execute an agent").argument(
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "CLI application",
5
5
  "type": "module",
6
6
  "bin": {