@vm0/cli 5.7.2 → 5.8.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 +406 -176
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command35 } from "commander";
5
- import chalk36 from "chalk";
4
+ import { Command as Command36 } from "commander";
5
+ import chalk37 from "chalk";
6
6
 
7
7
  // src/lib/api/auth.ts
8
8
  import chalk from "chalk";
@@ -333,7 +333,9 @@ var storedExecutionContextSchema = z2.object({
333
333
  encryptedSecrets: z2.string().nullable(),
334
334
  // AES-256-GCM encrypted secrets
335
335
  cliAgentType: z2.string(),
336
- experimentalFirewall: experimentalFirewallSchema.optional()
336
+ experimentalFirewall: experimentalFirewallSchema.optional(),
337
+ // Debug flag to force real Claude in mock environments (internal use only)
338
+ debugNoMockClaude: z2.boolean().optional()
337
339
  });
338
340
  var executionContextSchema = z2.object({
339
341
  runId: z2.string().uuid(),
@@ -351,7 +353,9 @@ var executionContextSchema = z2.object({
351
353
  secretValues: z2.array(z2.string()).nullable(),
352
354
  cliAgentType: z2.string(),
353
355
  // Experimental firewall configuration
354
- experimentalFirewall: experimentalFirewallSchema.optional()
356
+ experimentalFirewall: experimentalFirewallSchema.optional(),
357
+ // Debug flag to force real Claude in mock environments (internal use only)
358
+ debugNoMockClaude: z2.boolean().optional()
355
359
  });
356
360
  var runnersJobClaimContract = c.router({
357
361
  claim: {
@@ -634,6 +638,8 @@ var unifiedRunRequestSchema = z4.object({
634
638
  vars: z4.record(z4.string(), z4.string()).optional(),
635
639
  secrets: z4.record(z4.string(), z4.string()).optional(),
636
640
  volumeVersions: z4.record(z4.string(), z4.string()).optional(),
641
+ // Debug flag to force real Claude in mock environments (internal use only)
642
+ debugNoMockClaude: z4.boolean().optional(),
637
643
  // Required
638
644
  prompt: z4.string().min(1, "Missing prompt")
639
645
  });
@@ -2586,6 +2592,16 @@ function getProviderDisplayName(provider) {
2586
2592
  return PROVIDER_DISPLAY_NAMES[provider];
2587
2593
  }
2588
2594
 
2595
+ // ../../packages/core/src/feature-switch.ts
2596
+ var PricingSwitch = {
2597
+ key: "pricing" /* Pricing */,
2598
+ maintainer: "ethan@vm0.ai",
2599
+ enabled: false
2600
+ };
2601
+ var FEATURE_SWITCHES = {
2602
+ ["pricing" /* Pricing */]: PricingSwitch
2603
+ };
2604
+
2589
2605
  // src/lib/api/api-client.ts
2590
2606
  import { initClient } from "@ts-rest/core";
2591
2607
  var ApiClient = class {
@@ -3256,6 +3272,26 @@ var ApiClient = class {
3256
3272
  const message = errorBody.error?.message || `Volume "${id}" not found`;
3257
3273
  throw new Error(message);
3258
3274
  }
3275
+ /**
3276
+ * Get usage statistics
3277
+ */
3278
+ async getUsage(options) {
3279
+ const baseUrl = await this.getBaseUrl();
3280
+ const headers = await this.getHeaders();
3281
+ const params = new URLSearchParams({
3282
+ start_date: options.startDate,
3283
+ end_date: options.endDate
3284
+ });
3285
+ const response = await fetch(`${baseUrl}/api/usage?${params}`, {
3286
+ method: "GET",
3287
+ headers
3288
+ });
3289
+ if (!response.ok) {
3290
+ const error = await response.json();
3291
+ throw new Error(error.error?.message || "Failed to fetch usage data");
3292
+ }
3293
+ return response.json();
3294
+ }
3259
3295
  /**
3260
3296
  * Generic GET request
3261
3297
  */
@@ -5103,7 +5139,7 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
5103
5139
  ).option(
5104
5140
  "--conversation <id>",
5105
5141
  "Resume from conversation ID (for fine-grained control)"
5106
- ).option("-v, --verbose", "Show verbose output with timing information").action(
5142
+ ).option("-v, --verbose", "Show verbose output with timing information").option("--debug-no-mock-claude").action(
5107
5143
  async (identifier, prompt, options) => {
5108
5144
  const startTimestamp = /* @__PURE__ */ new Date();
5109
5145
  const verbose = options.verbose;
@@ -5204,7 +5240,8 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
5204
5240
  artifactName: options.artifactName,
5205
5241
  artifactVersion: options.artifactVersion,
5206
5242
  volumeVersions: Object.keys(options.volumeVersion).length > 0 ? options.volumeVersion : void 0,
5207
- conversationId: options.conversation
5243
+ conversationId: options.conversation,
5244
+ debugNoMockClaude: options.debugNoMockClaude || void 0
5208
5245
  });
5209
5246
  if (response.status === "failed") {
5210
5247
  console.error(chalk5.red("\u2717 Run preparation failed"));
@@ -5269,7 +5306,7 @@ runCmd.command("resume").description("Resume an agent run from a checkpoint (use
5269
5306
  "Volume version override (repeatable)",
5270
5307
  collectVolumeVersions,
5271
5308
  {}
5272
- ).option("-v, --verbose", "Show verbose output with timing information").action(
5309
+ ).option("-v, --verbose", "Show verbose output with timing information").option("--debug-no-mock-claude").action(
5273
5310
  async (checkpointId, prompt, options, command) => {
5274
5311
  const startTimestamp = /* @__PURE__ */ new Date();
5275
5312
  const allOpts = command.optsWithGlobals();
@@ -5310,7 +5347,8 @@ runCmd.command("resume").description("Resume an agent run from a checkpoint (use
5310
5347
  prompt,
5311
5348
  vars: Object.keys(vars).length > 0 ? vars : void 0,
5312
5349
  secrets: loadedSecrets,
5313
- volumeVersions: Object.keys(allOpts.volumeVersion).length > 0 ? allOpts.volumeVersion : void 0
5350
+ volumeVersions: Object.keys(allOpts.volumeVersion).length > 0 ? allOpts.volumeVersion : void 0,
5351
+ debugNoMockClaude: options.debugNoMockClaude || allOpts.debugNoMockClaude || void 0
5314
5352
  });
5315
5353
  if (response.status === "failed") {
5316
5354
  console.error(chalk5.red("\u2717 Run preparation failed"));
@@ -5367,7 +5405,7 @@ runCmd.command("continue").description(
5367
5405
  "Volume version override (repeatable)",
5368
5406
  collectVolumeVersions,
5369
5407
  {}
5370
- ).option("-v, --verbose", "Show verbose output with timing information").action(
5408
+ ).option("-v, --verbose", "Show verbose output with timing information").option("--debug-no-mock-claude").action(
5371
5409
  async (agentSessionId, prompt, options, command) => {
5372
5410
  const startTimestamp = /* @__PURE__ */ new Date();
5373
5411
  const allOpts = command.optsWithGlobals();
@@ -5409,7 +5447,8 @@ runCmd.command("continue").description(
5409
5447
  prompt,
5410
5448
  vars: Object.keys(vars).length > 0 ? vars : void 0,
5411
5449
  secrets: loadedSecrets,
5412
- volumeVersions: Object.keys(allOpts.volumeVersion).length > 0 ? allOpts.volumeVersion : void 0
5450
+ volumeVersions: Object.keys(allOpts.volumeVersion).length > 0 ? allOpts.volumeVersion : void 0,
5451
+ debugNoMockClaude: options.debugNoMockClaude || allOpts.debugNoMockClaude || void 0
5413
5452
  });
5414
5453
  if (response.status === "failed") {
5415
5454
  console.error(chalk5.red("\u2717 Run preparation failed"));
@@ -6731,180 +6770,186 @@ async function autoPullArtifact(runOutput, artifactDir) {
6731
6770
  }
6732
6771
  }
6733
6772
  var cookCmd = new Command17().name("cook").description("One-click agent preparation and execution from vm0.yaml");
6734
- cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip confirmation prompts").action(async (prompt, options) => {
6735
- const shouldExit = await checkAndUpgrade("5.7.2", prompt);
6736
- if (shouldExit) {
6737
- process.exit(0);
6738
- }
6739
- const cwd = process.cwd();
6740
- console.log(chalk21.bold(`Reading config: ${CONFIG_FILE3}`));
6741
- if (!existsSync8(CONFIG_FILE3)) {
6742
- console.error(chalk21.red(`\u2717 Config file not found: ${CONFIG_FILE3}`));
6743
- process.exit(1);
6744
- }
6745
- let config;
6746
- try {
6747
- const content = await readFile7(CONFIG_FILE3, "utf8");
6748
- config = parseYaml4(content);
6749
- } catch (error) {
6750
- console.error(chalk21.red("\u2717 Invalid YAML format"));
6751
- if (error instanceof Error) {
6752
- console.error(chalk21.dim(` ${error.message}`));
6773
+ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip confirmation prompts").option("--debug-no-mock-claude").action(
6774
+ async (prompt, options) => {
6775
+ const shouldExit = await checkAndUpgrade("5.8.0", prompt);
6776
+ if (shouldExit) {
6777
+ process.exit(0);
6753
6778
  }
6754
- process.exit(1);
6755
- }
6756
- const validation = validateAgentCompose(config);
6757
- if (!validation.valid) {
6758
- console.error(chalk21.red(`\u2717 ${validation.error}`));
6759
- process.exit(1);
6760
- }
6761
- const agentNames = Object.keys(config.agents);
6762
- const agentName = agentNames[0];
6763
- const volumeCount = config.volumes ? Object.keys(config.volumes).length : 0;
6764
- console.log(
6765
- chalk21.green(`\u2713 Config validated: 1 agent, ${volumeCount} volume(s)`)
6766
- );
6767
- const requiredVarNames = extractRequiredVarNames(config);
6768
- if (requiredVarNames.length > 0) {
6769
- const envFilePath = path12.join(cwd, ".env");
6770
- const missingVars = checkMissingVariables(requiredVarNames, envFilePath);
6771
- if (missingVars.length > 0) {
6772
- await generateEnvPlaceholders(missingVars, envFilePath);
6773
- console.log();
6774
- console.log(
6775
- chalk21.yellow(
6776
- `\u26A0 Missing environment variables. Please fill in values in .env file:`
6777
- )
6778
- );
6779
- for (const varName of missingVars) {
6780
- console.log(chalk21.yellow(` ${varName}`));
6779
+ const cwd = process.cwd();
6780
+ console.log(chalk21.bold(`Reading config: ${CONFIG_FILE3}`));
6781
+ if (!existsSync8(CONFIG_FILE3)) {
6782
+ console.error(chalk21.red(`\u2717 Config file not found: ${CONFIG_FILE3}`));
6783
+ process.exit(1);
6784
+ }
6785
+ let config;
6786
+ try {
6787
+ const content = await readFile7(CONFIG_FILE3, "utf8");
6788
+ config = parseYaml4(content);
6789
+ } catch (error) {
6790
+ console.error(chalk21.red("\u2717 Invalid YAML format"));
6791
+ if (error instanceof Error) {
6792
+ console.error(chalk21.dim(` ${error.message}`));
6781
6793
  }
6782
6794
  process.exit(1);
6783
6795
  }
6784
- }
6785
- if (config.volumes && Object.keys(config.volumes).length > 0) {
6786
- console.log();
6787
- console.log(chalk21.bold("Processing volumes:"));
6788
- for (const volumeConfig of Object.values(config.volumes)) {
6789
- const volumeDir = path12.join(cwd, volumeConfig.name);
6790
- if (!existsSync8(volumeDir)) {
6791
- console.error(
6792
- chalk21.red(
6793
- `\u2717 Directory not found: ${volumeConfig.name}. Create the directory and add files first.`
6796
+ const validation = validateAgentCompose(config);
6797
+ if (!validation.valid) {
6798
+ console.error(chalk21.red(`\u2717 ${validation.error}`));
6799
+ process.exit(1);
6800
+ }
6801
+ const agentNames = Object.keys(config.agents);
6802
+ const agentName = agentNames[0];
6803
+ const volumeCount = config.volumes ? Object.keys(config.volumes).length : 0;
6804
+ console.log(
6805
+ chalk21.green(`\u2713 Config validated: 1 agent, ${volumeCount} volume(s)`)
6806
+ );
6807
+ const requiredVarNames = extractRequiredVarNames(config);
6808
+ if (requiredVarNames.length > 0) {
6809
+ const envFilePath = path12.join(cwd, ".env");
6810
+ const missingVars = checkMissingVariables(
6811
+ requiredVarNames,
6812
+ envFilePath
6813
+ );
6814
+ if (missingVars.length > 0) {
6815
+ await generateEnvPlaceholders(missingVars, envFilePath);
6816
+ console.log();
6817
+ console.log(
6818
+ chalk21.yellow(
6819
+ `\u26A0 Missing environment variables. Please fill in values in .env file:`
6794
6820
  )
6795
6821
  );
6822
+ for (const varName of missingVars) {
6823
+ console.log(chalk21.yellow(` ${varName}`));
6824
+ }
6796
6825
  process.exit(1);
6797
6826
  }
6798
- try {
6799
- printCommand(`cd ${volumeConfig.name}`);
6800
- const existingConfig = await readStorageConfig(volumeDir);
6801
- if (!existingConfig) {
6802
- printCommand(`vm0 volume init --name ${volumeConfig.name}`);
6803
- await execVm0Command(
6804
- ["volume", "init", "--name", volumeConfig.name],
6805
- {
6806
- cwd: volumeDir,
6807
- silent: true
6808
- }
6827
+ }
6828
+ if (config.volumes && Object.keys(config.volumes).length > 0) {
6829
+ console.log();
6830
+ console.log(chalk21.bold("Processing volumes:"));
6831
+ for (const volumeConfig of Object.values(config.volumes)) {
6832
+ const volumeDir = path12.join(cwd, volumeConfig.name);
6833
+ if (!existsSync8(volumeDir)) {
6834
+ console.error(
6835
+ chalk21.red(
6836
+ `\u2717 Directory not found: ${volumeConfig.name}. Create the directory and add files first.`
6837
+ )
6809
6838
  );
6839
+ process.exit(1);
6810
6840
  }
6811
- printCommand("vm0 volume push");
6812
- await execVm0Command(["volume", "push"], {
6813
- cwd: volumeDir,
6814
- silent: true
6815
- });
6816
- printCommand("cd ..");
6817
- } catch (error) {
6818
- console.error(chalk21.red(`\u2717 Failed`));
6819
- if (error instanceof Error) {
6820
- console.error(chalk21.dim(` ${error.message}`));
6841
+ try {
6842
+ printCommand(`cd ${volumeConfig.name}`);
6843
+ const existingConfig = await readStorageConfig(volumeDir);
6844
+ if (!existingConfig) {
6845
+ printCommand(`vm0 volume init --name ${volumeConfig.name}`);
6846
+ await execVm0Command(
6847
+ ["volume", "init", "--name", volumeConfig.name],
6848
+ {
6849
+ cwd: volumeDir,
6850
+ silent: true
6851
+ }
6852
+ );
6853
+ }
6854
+ printCommand("vm0 volume push");
6855
+ await execVm0Command(["volume", "push"], {
6856
+ cwd: volumeDir,
6857
+ silent: true
6858
+ });
6859
+ printCommand("cd ..");
6860
+ } catch (error) {
6861
+ console.error(chalk21.red(`\u2717 Failed`));
6862
+ if (error instanceof Error) {
6863
+ console.error(chalk21.dim(` ${error.message}`));
6864
+ }
6865
+ process.exit(1);
6821
6866
  }
6822
- process.exit(1);
6823
6867
  }
6824
6868
  }
6825
- }
6826
- console.log();
6827
- console.log(chalk21.bold("Processing artifact:"));
6828
- const artifactDir = path12.join(cwd, ARTIFACT_DIR);
6829
- try {
6830
- if (!existsSync8(artifactDir)) {
6831
- printCommand(`mkdir ${ARTIFACT_DIR}`);
6832
- await mkdir6(artifactDir, { recursive: true });
6833
- }
6834
- printCommand(`cd ${ARTIFACT_DIR}`);
6835
- const existingConfig = await readStorageConfig(artifactDir);
6836
- if (!existingConfig) {
6837
- printCommand(`vm0 artifact init --name ${ARTIFACT_DIR}`);
6838
- await execVm0Command(["artifact", "init", "--name", ARTIFACT_DIR], {
6869
+ console.log();
6870
+ console.log(chalk21.bold("Processing artifact:"));
6871
+ const artifactDir = path12.join(cwd, ARTIFACT_DIR);
6872
+ try {
6873
+ if (!existsSync8(artifactDir)) {
6874
+ printCommand(`mkdir ${ARTIFACT_DIR}`);
6875
+ await mkdir6(artifactDir, { recursive: true });
6876
+ }
6877
+ printCommand(`cd ${ARTIFACT_DIR}`);
6878
+ const existingConfig = await readStorageConfig(artifactDir);
6879
+ if (!existingConfig) {
6880
+ printCommand(`vm0 artifact init --name ${ARTIFACT_DIR}`);
6881
+ await execVm0Command(["artifact", "init", "--name", ARTIFACT_DIR], {
6882
+ cwd: artifactDir,
6883
+ silent: true
6884
+ });
6885
+ }
6886
+ printCommand("vm0 artifact push");
6887
+ await execVm0Command(["artifact", "push"], {
6839
6888
  cwd: artifactDir,
6840
6889
  silent: true
6841
6890
  });
6891
+ printCommand("cd ..");
6892
+ } catch (error) {
6893
+ console.error(chalk21.red(`\u2717 Failed`));
6894
+ if (error instanceof Error) {
6895
+ console.error(chalk21.dim(` ${error.message}`));
6896
+ }
6897
+ process.exit(1);
6842
6898
  }
6843
- printCommand("vm0 artifact push");
6844
- await execVm0Command(["artifact", "push"], {
6845
- cwd: artifactDir,
6846
- silent: true
6847
- });
6848
- printCommand("cd ..");
6849
- } catch (error) {
6850
- console.error(chalk21.red(`\u2717 Failed`));
6851
- if (error instanceof Error) {
6852
- console.error(chalk21.dim(` ${error.message}`));
6853
- }
6854
- process.exit(1);
6855
- }
6856
- console.log();
6857
- console.log(chalk21.bold("Composing agent:"));
6858
- const composeArgs = options.yes ? ["compose", "--yes", CONFIG_FILE3] : ["compose", CONFIG_FILE3];
6859
- printCommand(`vm0 ${composeArgs.join(" ")}`);
6860
- try {
6861
- await execVm0Command(composeArgs, {
6862
- cwd
6863
- });
6864
- } catch (error) {
6865
- console.error(chalk21.red(`\u2717 Compose failed`));
6866
- if (error instanceof Error) {
6867
- console.error(chalk21.dim(` ${error.message}`));
6868
- }
6869
- process.exit(1);
6870
- }
6871
- if (prompt) {
6872
6899
  console.log();
6873
- console.log(chalk21.bold("Running agent:"));
6874
- printCommand(
6875
- `vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "${prompt}"`
6876
- );
6877
- console.log();
6878
- let runOutput;
6900
+ console.log(chalk21.bold("Composing agent:"));
6901
+ const composeArgs = options.yes ? ["compose", "--yes", CONFIG_FILE3] : ["compose", CONFIG_FILE3];
6902
+ printCommand(`vm0 ${composeArgs.join(" ")}`);
6879
6903
  try {
6880
- const runArgs = [
6881
- "run",
6882
- agentName,
6883
- "--artifact-name",
6884
- ARTIFACT_DIR,
6885
- prompt
6886
- ];
6887
- runOutput = await execVm0RunWithCapture(runArgs, { cwd });
6888
- } catch {
6904
+ await execVm0Command(composeArgs, {
6905
+ cwd
6906
+ });
6907
+ } catch (error) {
6908
+ console.error(chalk21.red(`\u2717 Compose failed`));
6909
+ if (error instanceof Error) {
6910
+ console.error(chalk21.dim(` ${error.message}`));
6911
+ }
6889
6912
  process.exit(1);
6890
6913
  }
6891
- const runIds = parseRunIdsFromOutput(runOutput);
6892
- if (runIds.runId || runIds.sessionId || runIds.checkpointId) {
6893
- await saveCookState({
6894
- lastRunId: runIds.runId,
6895
- lastSessionId: runIds.sessionId,
6896
- lastCheckpointId: runIds.checkpointId
6897
- });
6914
+ if (prompt) {
6915
+ console.log();
6916
+ console.log(chalk21.bold("Running agent:"));
6917
+ printCommand(
6918
+ `vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "${prompt}"`
6919
+ );
6920
+ console.log();
6921
+ let runOutput;
6922
+ try {
6923
+ const runArgs = [
6924
+ "run",
6925
+ agentName,
6926
+ "--artifact-name",
6927
+ ARTIFACT_DIR,
6928
+ ...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
6929
+ prompt
6930
+ ];
6931
+ runOutput = await execVm0RunWithCapture(runArgs, { cwd });
6932
+ } catch {
6933
+ process.exit(1);
6934
+ }
6935
+ const runIds = parseRunIdsFromOutput(runOutput);
6936
+ if (runIds.runId || runIds.sessionId || runIds.checkpointId) {
6937
+ await saveCookState({
6938
+ lastRunId: runIds.runId,
6939
+ lastSessionId: runIds.sessionId,
6940
+ lastCheckpointId: runIds.checkpointId
6941
+ });
6942
+ }
6943
+ await autoPullArtifact(runOutput, artifactDir);
6944
+ } else {
6945
+ console.log();
6946
+ console.log("To run your agent:");
6947
+ printCommand(
6948
+ `vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "your prompt"`
6949
+ );
6898
6950
  }
6899
- await autoPullArtifact(runOutput, artifactDir);
6900
- } else {
6901
- console.log();
6902
- console.log("To run your agent:");
6903
- printCommand(
6904
- `vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "your prompt"`
6905
- );
6906
6951
  }
6907
- });
6952
+ );
6908
6953
  cookCmd.command("logs").description("View logs from the last cook run").option("-a, --agent", "Show agent events (default)").option("-s, --system", "Show system log").option("-m, --metrics", "Show metrics").option("-n, --network", "Show network logs (proxy traffic)").option(
6909
6954
  "--since <time>",
6910
6955
  "Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z)"
@@ -6952,7 +6997,7 @@ cookCmd.command("logs").description("View logs from the last cook run").option("
6952
6997
  );
6953
6998
  cookCmd.command("continue").description(
6954
6999
  "Continue from the last session (latest conversation and artifact)"
6955
- ).argument("<prompt>", "Prompt for the continued agent").action(async (prompt) => {
7000
+ ).argument("<prompt>", "Prompt for the continued agent").option("--debug-no-mock-claude").action(async (prompt, options) => {
6956
7001
  const state = await loadCookState();
6957
7002
  if (!state.lastSessionId) {
6958
7003
  console.error(chalk21.red("\u2717 No previous session found"));
@@ -6966,7 +7011,13 @@ cookCmd.command("continue").description(
6966
7011
  let runOutput;
6967
7012
  try {
6968
7013
  runOutput = await execVm0RunWithCapture(
6969
- ["run", "continue", state.lastSessionId, prompt],
7014
+ [
7015
+ "run",
7016
+ "continue",
7017
+ state.lastSessionId,
7018
+ ...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
7019
+ prompt
7020
+ ],
6970
7021
  { cwd }
6971
7022
  );
6972
7023
  } catch {
@@ -6984,7 +7035,7 @@ cookCmd.command("continue").description(
6984
7035
  });
6985
7036
  cookCmd.command("resume").description(
6986
7037
  "Resume from the last checkpoint (snapshotted conversation and artifact)"
6987
- ).argument("<prompt>", "Prompt for the resumed agent").action(async (prompt) => {
7038
+ ).argument("<prompt>", "Prompt for the resumed agent").option("--debug-no-mock-claude").action(async (prompt, options) => {
6988
7039
  const state = await loadCookState();
6989
7040
  if (!state.lastCheckpointId) {
6990
7041
  console.error(chalk21.red("\u2717 No previous checkpoint found"));
@@ -6998,7 +7049,13 @@ cookCmd.command("resume").description(
6998
7049
  let runOutput;
6999
7050
  try {
7000
7051
  runOutput = await execVm0RunWithCapture(
7001
- ["run", "resume", state.lastCheckpointId, prompt],
7052
+ [
7053
+ "run",
7054
+ "resume",
7055
+ state.lastCheckpointId,
7056
+ ...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
7057
+ prompt
7058
+ ],
7002
7059
  { cwd }
7003
7060
  );
7004
7061
  } catch {
@@ -7394,10 +7451,10 @@ var setCommand = new Command20().name("set").description("Set your scope slug").
7394
7451
  // src/commands/scope/index.ts
7395
7452
  var scopeCommand = new Command21().name("scope").description("Manage your scope (namespace for images)").addCommand(statusCommand3).addCommand(setCommand);
7396
7453
 
7397
- // src/commands/agents/index.ts
7454
+ // src/commands/agent/index.ts
7398
7455
  import { Command as Command24 } from "commander";
7399
7456
 
7400
- // src/commands/agents/list.ts
7457
+ // src/commands/agent/list.ts
7401
7458
  import { Command as Command22 } from "commander";
7402
7459
  import chalk25 from "chalk";
7403
7460
  var listCommand3 = new Command22().name("list").alias("ls").description("List all agent composes").option("-s, --scope <scope>", "Scope to list composes from").action(async (options) => {
@@ -7443,7 +7500,7 @@ var listCommand3 = new Command22().name("list").alias("ls").description("List al
7443
7500
  }
7444
7501
  });
7445
7502
 
7446
- // src/commands/agents/inspect.ts
7503
+ // src/commands/agent/inspect.ts
7447
7504
  import { Command as Command23 } from "commander";
7448
7505
  import chalk26 from "chalk";
7449
7506
 
@@ -7553,7 +7610,7 @@ async function deriveComposeVariableSources(content, options) {
7553
7610
  return results;
7554
7611
  }
7555
7612
 
7556
- // src/commands/agents/inspect.ts
7613
+ // src/commands/agent/inspect.ts
7557
7614
  function formatComposeOutput(name, versionId, content, variableSources) {
7558
7615
  console.log(chalk26.bold("Name:") + ` ${name}`);
7559
7616
  console.log(chalk26.bold("Version:") + ` ${versionId}`);
@@ -7635,7 +7692,7 @@ var inspectCommand = new Command23().name("inspect").description("Inspect an age
7635
7692
  } catch (error) {
7636
7693
  if (error instanceof Error && error.message.includes("not found")) {
7637
7694
  console.error(chalk26.red(`\u2717 Agent compose not found: ${name}`));
7638
- console.error(chalk26.dim(" Run: vm0 agents list"));
7695
+ console.error(chalk26.dim(" Run: vm0 agent list"));
7639
7696
  process.exit(1);
7640
7697
  }
7641
7698
  throw error;
@@ -7702,8 +7759,8 @@ var inspectCommand = new Command23().name("inspect").description("Inspect an age
7702
7759
  }
7703
7760
  );
7704
7761
 
7705
- // src/commands/agents/index.ts
7706
- var agentsCommand = new Command24().name("agents").description("Manage agent composes").addCommand(listCommand3).addCommand(inspectCommand);
7762
+ // src/commands/agent/index.ts
7763
+ var agentCommand = new Command24().name("agent").description("Manage agent composes").addCommand(listCommand3).addCommand(inspectCommand);
7707
7764
 
7708
7765
  // src/commands/init.ts
7709
7766
  import { Command as Command25 } from "commander";
@@ -9398,11 +9455,183 @@ var disableCommand = new Command33().name("disable").description("Disable a sche
9398
9455
  // src/commands/schedule/index.ts
9399
9456
  var scheduleCommand = new Command34().name("schedule").description("Manage agent schedules").addCommand(initCommand4).addCommand(deployCommand).addCommand(listCommand4).addCommand(statusCommand4).addCommand(deleteCommand).addCommand(enableCommand).addCommand(disableCommand);
9400
9457
 
9458
+ // src/commands/usage.ts
9459
+ import { Command as Command35 } from "commander";
9460
+ import chalk36 from "chalk";
9461
+
9462
+ // src/lib/utils/duration-formatter.ts
9463
+ function formatDuration(ms) {
9464
+ if (ms === null || ms === void 0 || ms === 0) {
9465
+ return "-";
9466
+ }
9467
+ if (ms < 0) {
9468
+ return "-";
9469
+ }
9470
+ const totalSeconds = Math.floor(ms / 1e3);
9471
+ if (totalSeconds === 0) {
9472
+ return "< 1s";
9473
+ }
9474
+ const hours = Math.floor(totalSeconds / 3600);
9475
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
9476
+ const seconds = totalSeconds % 60;
9477
+ const parts = [];
9478
+ if (hours > 0) {
9479
+ parts.push(`${hours}h`);
9480
+ }
9481
+ if (minutes > 0) {
9482
+ parts.push(`${minutes}m`);
9483
+ }
9484
+ if (seconds > 0) {
9485
+ parts.push(`${seconds}s`);
9486
+ }
9487
+ return parts.join(" ");
9488
+ }
9489
+
9490
+ // src/commands/usage.ts
9491
+ var MAX_RANGE_MS = 30 * 24 * 60 * 60 * 1e3;
9492
+ var DEFAULT_RANGE_MS = 7 * 24 * 60 * 60 * 1e3;
9493
+ function formatDateDisplay(dateStr) {
9494
+ const date = new Date(dateStr);
9495
+ return date.toLocaleDateString("en-US", { month: "short", day: "numeric" });
9496
+ }
9497
+ function formatDateRange(start, end) {
9498
+ const startDate = new Date(start);
9499
+ const endDate = new Date(end);
9500
+ endDate.setDate(endDate.getDate() - 1);
9501
+ const startStr = startDate.toLocaleDateString("en-US", {
9502
+ month: "short",
9503
+ day: "numeric"
9504
+ });
9505
+ const endStr = endDate.toLocaleDateString("en-US", {
9506
+ month: "short",
9507
+ day: "numeric",
9508
+ year: "numeric"
9509
+ });
9510
+ return `${startStr} - ${endStr}`;
9511
+ }
9512
+ function fillMissingDates(daily, startDate, endDate) {
9513
+ const dateMap = /* @__PURE__ */ new Map();
9514
+ for (const day of daily) {
9515
+ dateMap.set(day.date, day);
9516
+ }
9517
+ const result = [];
9518
+ const current = new Date(startDate);
9519
+ current.setUTCHours(0, 0, 0, 0);
9520
+ while (current < endDate) {
9521
+ const dateStr = current.toISOString().split("T")[0];
9522
+ const existing = dateMap.get(dateStr);
9523
+ if (existing) {
9524
+ result.push(existing);
9525
+ } else {
9526
+ result.push({ date: dateStr, run_count: 0, run_time_ms: 0 });
9527
+ }
9528
+ current.setDate(current.getDate() + 1);
9529
+ }
9530
+ result.sort((a, b) => b.date.localeCompare(a.date));
9531
+ return result;
9532
+ }
9533
+ var usageCommand = new Command35().name("usage").description("View usage statistics").option("--since <date>", "Start date (ISO format or relative: 7d, 30d)").option(
9534
+ "--until <date>",
9535
+ "End date (ISO format or relative, defaults to now)"
9536
+ ).action(async (options) => {
9537
+ try {
9538
+ const now = /* @__PURE__ */ new Date();
9539
+ let endDate;
9540
+ let startDate;
9541
+ if (options.until) {
9542
+ try {
9543
+ const untilMs = parseTime(options.until);
9544
+ endDate = new Date(untilMs);
9545
+ } catch {
9546
+ console.error(
9547
+ chalk36.red(
9548
+ "Error: Invalid --until format. Use ISO (2026-01-01) or relative (7d, 30d)"
9549
+ )
9550
+ );
9551
+ process.exit(1);
9552
+ }
9553
+ } else {
9554
+ endDate = now;
9555
+ }
9556
+ if (options.since) {
9557
+ try {
9558
+ const sinceMs = parseTime(options.since);
9559
+ startDate = new Date(sinceMs);
9560
+ } catch {
9561
+ console.error(
9562
+ chalk36.red(
9563
+ "Error: Invalid --since format. Use ISO (2026-01-01) or relative (7d, 30d)"
9564
+ )
9565
+ );
9566
+ process.exit(1);
9567
+ }
9568
+ } else {
9569
+ startDate = new Date(endDate.getTime() - DEFAULT_RANGE_MS);
9570
+ }
9571
+ if (startDate >= endDate) {
9572
+ console.error(chalk36.red("Error: --since must be before --until"));
9573
+ process.exit(1);
9574
+ }
9575
+ const rangeMs = endDate.getTime() - startDate.getTime();
9576
+ if (rangeMs > MAX_RANGE_MS) {
9577
+ console.error(
9578
+ chalk36.red(
9579
+ "Error: Time range exceeds maximum of 30 days. Use --until to specify an end date."
9580
+ )
9581
+ );
9582
+ process.exit(1);
9583
+ }
9584
+ const usage = await apiClient.getUsage({
9585
+ startDate: startDate.toISOString(),
9586
+ endDate: endDate.toISOString()
9587
+ });
9588
+ const filledDaily = fillMissingDates(
9589
+ usage.daily,
9590
+ new Date(usage.period.start),
9591
+ new Date(usage.period.end)
9592
+ );
9593
+ console.log();
9594
+ console.log(
9595
+ chalk36.bold(
9596
+ `Usage Summary (${formatDateRange(usage.period.start, usage.period.end)})`
9597
+ )
9598
+ );
9599
+ console.log();
9600
+ console.log(chalk36.dim("DATE RUNS RUN TIME"));
9601
+ for (const day of filledDaily) {
9602
+ const dateDisplay = formatDateDisplay(day.date).padEnd(10);
9603
+ const runsDisplay = String(day.run_count).padStart(6);
9604
+ const timeDisplay = formatDuration(day.run_time_ms);
9605
+ console.log(`${dateDisplay}${runsDisplay} ${timeDisplay}`);
9606
+ }
9607
+ console.log(chalk36.dim("\u2500".repeat(29)));
9608
+ const totalRunsDisplay = String(usage.summary.total_runs).padStart(6);
9609
+ const totalTimeDisplay = formatDuration(usage.summary.total_run_time_ms);
9610
+ console.log(
9611
+ `${"TOTAL".padEnd(10)}${totalRunsDisplay} ${totalTimeDisplay}`
9612
+ );
9613
+ console.log();
9614
+ } catch (error) {
9615
+ if (error instanceof Error) {
9616
+ if (error.message.includes("Not authenticated")) {
9617
+ console.error(
9618
+ chalk36.red("Error: Not authenticated. Run: vm0 auth login")
9619
+ );
9620
+ } else {
9621
+ console.error(chalk36.red(`Error: ${error.message}`));
9622
+ }
9623
+ } else {
9624
+ console.error(chalk36.red("Error: An unexpected error occurred"));
9625
+ }
9626
+ process.exit(1);
9627
+ }
9628
+ });
9629
+
9401
9630
  // src/index.ts
9402
- var program = new Command35();
9403
- program.name("vm0").description("VM0 CLI - A modern build tool").version("5.7.2");
9631
+ var program = new Command36();
9632
+ program.name("vm0").description("VM0 CLI - A modern build tool").version("5.8.0");
9404
9633
  program.command("info").description("Display environment information").action(async () => {
9405
- console.log(chalk36.bold("System Information:"));
9634
+ console.log(chalk37.bold("System Information:"));
9406
9635
  console.log(`Node Version: ${process.version}`);
9407
9636
  console.log(`Platform: ${process.platform}`);
9408
9637
  console.log(`Architecture: ${process.arch}`);
@@ -9429,10 +9658,11 @@ program.addCommand(artifactCommand);
9429
9658
  program.addCommand(cookCommand);
9430
9659
  program.addCommand(logsCommand);
9431
9660
  program.addCommand(scopeCommand);
9432
- program.addCommand(agentsCommand);
9661
+ program.addCommand(agentCommand);
9433
9662
  program.addCommand(initCommand3);
9434
9663
  program.addCommand(setupGithubCommand);
9435
9664
  program.addCommand(scheduleCommand);
9665
+ program.addCommand(usageCommand);
9436
9666
  if (process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("vm0")) {
9437
9667
  program.parse();
9438
9668
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "5.7.2",
3
+ "version": "5.8.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",