@vm0/cli 7.1.1 → 8.0.1

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 +1168 -1644
  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 Command47 } from "commander";
5
- import chalk47 from "chalk";
4
+ import { Command as Command45 } from "commander";
5
+ import chalk45 from "chalk";
6
6
 
7
7
  // src/lib/api/auth.ts
8
8
  import chalk from "chalk";
@@ -79,7 +79,7 @@ async function exchangeToken(apiUrl, deviceCode) {
79
79
  return response.json();
80
80
  }
81
81
  function delay(ms) {
82
- return new Promise((resolve2) => setTimeout(resolve2, ms));
82
+ return new Promise((resolve) => setTimeout(resolve, ms));
83
83
  }
84
84
  async function authenticate(apiUrl) {
85
85
  const targetApiUrl = apiUrl ?? await getApiUrl();
@@ -2950,10 +2950,6 @@ var FEATURE_SWITCHES = {
2950
2950
  maintainer: "ethan@vm0.ai",
2951
2951
  enabled: true
2952
2952
  },
2953
- ["platformOnboarding" /* PlatformOnboarding */]: {
2954
- maintainer: "ethan@vm0.ai",
2955
- enabled: false
2956
- },
2957
2953
  ["platformAgents" /* PlatformAgents */]: {
2958
2954
  maintainer: "ethan@vm0.ai",
2959
2955
  enabled: false
@@ -3024,10 +3020,10 @@ async function getRawHeaders() {
3024
3020
  }
3025
3021
  return headers;
3026
3022
  }
3027
- async function httpGet(path16) {
3023
+ async function httpGet(path14) {
3028
3024
  const baseUrl = await getBaseUrl();
3029
3025
  const headers = await getRawHeaders();
3030
- return fetch(`${baseUrl}${path16}`, {
3026
+ return fetch(`${baseUrl}${path14}`, {
3031
3027
  method: "GET",
3032
3028
  headers
3033
3029
  });
@@ -3588,49 +3584,49 @@ var cliComposeSchema = z23.object({
3588
3584
  function formatZodError(error) {
3589
3585
  const issue = error.issues[0];
3590
3586
  if (!issue) return "Validation failed";
3591
- const path16 = issue.path.join(".");
3587
+ const path14 = issue.path.join(".");
3592
3588
  const message = issue.message;
3593
- if (!path16) return message;
3589
+ if (!path14) return message;
3594
3590
  if (issue.code === "invalid_type") {
3595
3591
  const received = issue.received;
3596
3592
  const isMissing = received === "undefined" || message.includes("received undefined") || message === "Required";
3597
- if (path16 === "version" && isMissing) {
3593
+ if (path14 === "version" && isMissing) {
3598
3594
  return "Missing config.version";
3599
3595
  }
3600
- if (path16 === "agents" && isMissing) {
3596
+ if (path14 === "agents" && isMissing) {
3601
3597
  return "Missing agents object in config";
3602
3598
  }
3603
- if (path16.startsWith("volumes.") && path16.endsWith(".name")) {
3604
- const volumeKey = path16.split(".")[1];
3599
+ if (path14.startsWith("volumes.") && path14.endsWith(".name")) {
3600
+ const volumeKey = path14.split(".")[1];
3605
3601
  return `Volume "${volumeKey}" must have a 'name' field (string)`;
3606
3602
  }
3607
- if (path16.startsWith("volumes.") && path16.endsWith(".version")) {
3608
- const volumeKey = path16.split(".")[1];
3603
+ if (path14.startsWith("volumes.") && path14.endsWith(".version")) {
3604
+ const volumeKey = path14.split(".")[1];
3609
3605
  return `Volume "${volumeKey}" must have a 'version' field (string)`;
3610
3606
  }
3611
3607
  if (issue.expected === "array") {
3612
- const fieldName = path16.replace(/^agents\.[^.]+\./, "agent.");
3608
+ const fieldName = path14.replace(/^agents\.[^.]+\./, "agent.");
3613
3609
  return `${fieldName} must be an array`;
3614
3610
  }
3615
3611
  if (issue.expected === "string" && received === "number") {
3616
- const fieldName = path16.replace(/^agents\.[^.]+\./, "agent.");
3612
+ const fieldName = path14.replace(/^agents\.[^.]+\./, "agent.");
3617
3613
  const match = fieldName.match(/^(agent\.[^.]+)\.\d+$/);
3618
3614
  if (match) {
3619
3615
  return `Each entry in ${match[1]?.replace("agent.", "")} must be a string`;
3620
3616
  }
3621
3617
  }
3622
3618
  }
3623
- if (issue.code === "invalid_key" && path16.startsWith("agents.")) {
3619
+ if (issue.code === "invalid_key" && path14.startsWith("agents.")) {
3624
3620
  return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
3625
3621
  }
3626
- if (message === "Invalid key in record" && path16.startsWith("agents.")) {
3622
+ if (message === "Invalid key in record" && path14.startsWith("agents.")) {
3627
3623
  return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
3628
3624
  }
3629
3625
  if (issue.code === "custom") {
3630
3626
  return message;
3631
3627
  }
3632
- if (path16.startsWith("agents.")) {
3633
- const cleanPath = path16.replace(/^agents\.[^.]+\./, "agent.");
3628
+ if (path14.startsWith("agents.")) {
3629
+ const cleanPath = path14.replace(/^agents\.[^.]+\./, "agent.");
3634
3630
  if (message.startsWith("Invalid input:")) {
3635
3631
  const match = message.match(/expected (\w+), received (\w+)/);
3636
3632
  if (match && match[1] === "string" && match[2] === "number") {
@@ -3642,7 +3638,7 @@ function formatZodError(error) {
3642
3638
  }
3643
3639
  return `${cleanPath}: ${message}`;
3644
3640
  }
3645
- return `${path16}: ${message}`;
3641
+ return `${path14}: ${message}`;
3646
3642
  }
3647
3643
  function validateAgentName(name) {
3648
3644
  return cliAgentNameSchema.safeParse(name).success;
@@ -3815,7 +3811,7 @@ function excludeVm0Filter(filePath) {
3815
3811
  return !shouldExclude;
3816
3812
  }
3817
3813
  function listTarFiles(tarPath) {
3818
- return new Promise((resolve2, reject) => {
3814
+ return new Promise((resolve, reject) => {
3819
3815
  const files = [];
3820
3816
  tar.list({
3821
3817
  file: tarPath,
@@ -3824,7 +3820,7 @@ function listTarFiles(tarPath) {
3824
3820
  files.push(entry.path);
3825
3821
  }
3826
3822
  }
3827
- }).then(() => resolve2(files)).catch(reject);
3823
+ }).then(() => resolve(files)).catch(reject);
3828
3824
  });
3829
3825
  }
3830
3826
  async function listLocalFiles(dir, excludeDirs = [".vm0"]) {
@@ -3886,11 +3882,11 @@ async function removeEmptyDirs(dir, excludeDirs = [".vm0"]) {
3886
3882
 
3887
3883
  // src/lib/storage/direct-upload.ts
3888
3884
  async function hashFileStream(filePath) {
3889
- return new Promise((resolve2, reject) => {
3885
+ return new Promise((resolve, reject) => {
3890
3886
  const hash = createHash("sha256");
3891
3887
  const stream = fs3.createReadStream(filePath);
3892
3888
  stream.on("data", (chunk) => hash.update(chunk));
3893
- stream.on("end", () => resolve2(hash.digest("hex")));
3889
+ stream.on("end", () => resolve(hash.digest("hex")));
3894
3890
  stream.on("error", reject);
3895
3891
  });
3896
3892
  }
@@ -3975,7 +3971,7 @@ function createManifest(files) {
3975
3971
  return Buffer.from(JSON.stringify(manifest, null, 2));
3976
3972
  }
3977
3973
  function sleep(ms) {
3978
- return new Promise((resolve2) => setTimeout(resolve2, ms));
3974
+ return new Promise((resolve) => setTimeout(resolve, ms));
3979
3975
  }
3980
3976
  async function uploadToPresignedUrl(presignedUrl, data, contentType, maxRetries = 3) {
3981
3977
  let lastError = null;
@@ -4549,7 +4545,6 @@ var EventRenderer = class {
4549
4545
  // src/commands/run/shared.ts
4550
4546
  import chalk5 from "chalk";
4551
4547
  import * as fs5 from "fs";
4552
- import * as path5 from "path";
4553
4548
  import { config as dotenvConfig } from "dotenv";
4554
4549
 
4555
4550
  // src/lib/events/claude-event-parser.ts
@@ -5783,7 +5778,7 @@ var ApiClient = class {
5783
5778
  /**
5784
5779
  * Generic GET request
5785
5780
  */
5786
- async get(path16) {
5781
+ async get(path14) {
5787
5782
  const baseUrl = await this.getBaseUrl();
5788
5783
  const token = await getToken();
5789
5784
  if (!token) {
@@ -5796,7 +5791,7 @@ var ApiClient = class {
5796
5791
  if (bypassSecret) {
5797
5792
  headers["x-vercel-protection-bypass"] = bypassSecret;
5798
5793
  }
5799
- return fetch(`${baseUrl}${path16}`, {
5794
+ return fetch(`${baseUrl}${path14}`, {
5800
5795
  method: "GET",
5801
5796
  headers
5802
5797
  });
@@ -5804,7 +5799,7 @@ var ApiClient = class {
5804
5799
  /**
5805
5800
  * Generic POST request
5806
5801
  */
5807
- async post(path16, options) {
5802
+ async post(path14, options) {
5808
5803
  const baseUrl = await this.getBaseUrl();
5809
5804
  const token = await getToken();
5810
5805
  if (!token) {
@@ -5820,7 +5815,7 @@ var ApiClient = class {
5820
5815
  if (bypassSecret) {
5821
5816
  headers["x-vercel-protection-bypass"] = bypassSecret;
5822
5817
  }
5823
- return fetch(`${baseUrl}${path16}`, {
5818
+ return fetch(`${baseUrl}${path14}`, {
5824
5819
  method: "POST",
5825
5820
  headers,
5826
5821
  body: options?.body
@@ -5829,7 +5824,7 @@ var ApiClient = class {
5829
5824
  /**
5830
5825
  * Generic DELETE request
5831
5826
  */
5832
- async delete(path16) {
5827
+ async delete(path14) {
5833
5828
  const baseUrl = await this.getBaseUrl();
5834
5829
  const token = await getToken();
5835
5830
  if (!token) {
@@ -5842,7 +5837,7 @@ var ApiClient = class {
5842
5837
  if (bypassSecret) {
5843
5838
  headers["x-vercel-protection-bypass"] = bypassSecret;
5844
5839
  }
5845
- return fetch(`${baseUrl}${path16}`, {
5840
+ return fetch(`${baseUrl}${path14}`, {
5846
5841
  method: "DELETE",
5847
5842
  headers
5848
5843
  });
@@ -5887,7 +5882,7 @@ async function streamEvents(runId, options) {
5887
5882
  const ablyClient = createRealtimeClient(async () => {
5888
5883
  return apiClient.getRealtimeToken(runId);
5889
5884
  });
5890
- return new Promise((resolve2, reject) => {
5885
+ return new Promise((resolve, reject) => {
5891
5886
  const channelName = getRunChannelName(runId);
5892
5887
  const channel = ablyClient.channels.get(channelName, {
5893
5888
  params: { rewind: "2m" }
@@ -5948,7 +5943,7 @@ async function streamEvents(runId, options) {
5948
5943
  result = { succeeded: false, runId };
5949
5944
  }
5950
5945
  cleanup();
5951
- resolve2(result);
5946
+ resolve(result);
5952
5947
  }
5953
5948
  }
5954
5949
  channel.subscribe(handleMessage).catch((err) => {
@@ -5992,30 +5987,32 @@ function extractSecretNames(composeContent) {
5992
5987
  const grouped = groupVariablesBySource(refs);
5993
5988
  return grouped.secrets.map((r) => r.name);
5994
5989
  }
5995
- function loadValues(cliValues, configNames) {
5990
+ function loadValues(cliValues, configNames, envFilePath) {
5996
5991
  const result = { ...cliValues };
5997
5992
  const missingNames = configNames.filter((name) => !(name in result));
5998
5993
  if (missingNames.length > 0) {
5999
- const envFilePath = path5.resolve(process.cwd(), ".env");
6000
- let dotenvValues = {};
6001
- if (fs5.existsSync(envFilePath)) {
5994
+ const envValues = {};
5995
+ for (const name of missingNames) {
5996
+ const envValue = process.env[name];
5997
+ if (envValue !== void 0) {
5998
+ envValues[name] = envValue;
5999
+ }
6000
+ }
6001
+ let fileValues = {};
6002
+ if (envFilePath) {
6003
+ if (!fs5.existsSync(envFilePath)) {
6004
+ throw new Error(`Environment file not found: ${envFilePath}`);
6005
+ }
6002
6006
  const dotenvResult = dotenvConfig({ path: envFilePath, quiet: true });
6003
6007
  if (dotenvResult.parsed) {
6004
- dotenvValues = Object.fromEntries(
6008
+ fileValues = Object.fromEntries(
6005
6009
  Object.entries(dotenvResult.parsed).filter(
6006
6010
  ([key]) => missingNames.includes(key)
6007
6011
  )
6008
6012
  );
6009
6013
  }
6010
6014
  }
6011
- const envValues = {};
6012
- for (const name of missingNames) {
6013
- const envValue = process.env[name];
6014
- if (envValue !== void 0) {
6015
- envValues[name] = envValue;
6016
- }
6017
- }
6018
- Object.assign(result, dotenvValues, envValues);
6015
+ Object.assign(result, envValues, fileValues);
6019
6016
  }
6020
6017
  return Object.keys(result).length > 0 ? result : void 0;
6021
6018
  }
@@ -6130,7 +6127,7 @@ async function pollEvents(runId, options) {
6130
6127
  result = { succeeded: false, runId };
6131
6128
  }
6132
6129
  if (!complete) {
6133
- await new Promise((resolve2) => setTimeout(resolve2, pollIntervalMs));
6130
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
6134
6131
  }
6135
6132
  }
6136
6133
  return result;
@@ -6173,13 +6170,16 @@ var mainRunCommand = new Command2().name("run").description("Run an agent").argu
6173
6170
  "<agent-name>",
6174
6171
  "Agent reference: [scope/]name[:version] (e.g., 'my-agent', 'lancy/my-agent:abc123', 'my-agent:latest')"
6175
6172
  ).argument("<prompt>", "Prompt for the agent").option(
6173
+ "--env-file <path>",
6174
+ "Load environment variables from file (priority: CLI flags > file > env vars)"
6175
+ ).option(
6176
6176
  "--vars <KEY=value>",
6177
- "Variables for ${{ vars.xxx }} (repeatable, falls back to env vars and .env)",
6177
+ "Variables for ${{ vars.xxx }} (repeatable, falls back to --env-file or env vars)",
6178
6178
  collectKeyValue,
6179
6179
  {}
6180
6180
  ).option(
6181
6181
  "--secrets <KEY=value>",
6182
- "Secrets for ${{ secrets.xxx }} (repeatable, falls back to env vars and .env)",
6182
+ "Secrets for ${{ secrets.xxx }} (repeatable, falls back to --env-file or env vars)",
6183
6183
  collectKeyValue,
6184
6184
  {}
6185
6185
  ).option("--artifact-name <name>", "Artifact storage name (required for run)").option(
@@ -6256,9 +6256,13 @@ var mainRunCommand = new Command2().name("run").description("Run an agent").argu
6256
6256
  }
6257
6257
  }
6258
6258
  const varNames = extractVarNames(composeContent);
6259
- const vars = loadValues(options.vars, varNames);
6259
+ const vars = loadValues(options.vars, varNames, options.envFile);
6260
6260
  const secretNames = extractSecretNames(composeContent);
6261
- const secrets = loadValues(options.secrets, secretNames);
6261
+ const secrets = loadValues(
6262
+ options.secrets,
6263
+ secretNames,
6264
+ options.envFile
6265
+ );
6262
6266
  if (verbose && varNames.length > 0) {
6263
6267
  console.log(chalk6.dim(` Required vars: ${varNames.join(", ")}`));
6264
6268
  if (vars) {
@@ -6350,6 +6354,8 @@ var mainRunCommand = new Command2().name("run").description("Run an agent").argu
6350
6354
  console.error(
6351
6355
  chalk6.dim(" Make sure the version hash is correct.")
6352
6356
  );
6357
+ } else if (error.message.startsWith("Environment file not found:")) {
6358
+ console.error(chalk6.red(`\u2717 ${error.message}`));
6353
6359
  } else if (error.message.includes("not found")) {
6354
6360
  console.error(chalk6.red(`\u2717 Agent not found: ${identifier}`));
6355
6361
  console.error(
@@ -6373,13 +6379,16 @@ var mainRunCommand = new Command2().name("run").description("Run an agent").argu
6373
6379
  import { Command as Command3, Option as Option2 } from "commander";
6374
6380
  import chalk7 from "chalk";
6375
6381
  var resumeCommand = new Command3().name("resume").description("Resume an agent run from a checkpoint (uses all snapshot data)").argument("<checkpointId>", "Checkpoint ID to resume from").argument("<prompt>", "Prompt for the resumed agent").option(
6382
+ "--env-file <path>",
6383
+ "Load environment variables from file (priority: CLI flags > file > env vars)"
6384
+ ).option(
6376
6385
  "--vars <KEY=value>",
6377
- "Variables for ${{ vars.xxx }} (repeatable, falls back to env vars and .env)",
6386
+ "Variables for ${{ vars.xxx }} (repeatable, falls back to --env-file or env vars)",
6378
6387
  collectKeyValue,
6379
6388
  {}
6380
6389
  ).option(
6381
6390
  "--secrets <KEY=value>",
6382
- "Secrets for ${{ secrets.xxx }} (repeatable, required for resume)",
6391
+ "Secrets for ${{ secrets.xxx }} (repeatable, falls back to --env-file or env vars)",
6383
6392
  collectKeyValue,
6384
6393
  {}
6385
6394
  ).option(
@@ -6411,7 +6420,8 @@ var resumeCommand = new Command3().name("resume").description("Resume an agent r
6411
6420
  }
6412
6421
  const checkpointInfo = await getCheckpoint(checkpointId);
6413
6422
  const requiredSecretNames = checkpointInfo.agentComposeSnapshot.secretNames || [];
6414
- const loadedSecrets = loadValues(secrets, requiredSecretNames);
6423
+ const envFile = options.envFile || allOpts.envFile;
6424
+ const loadedSecrets = loadValues(secrets, requiredSecretNames, envFile);
6415
6425
  if (verbose) {
6416
6426
  logVerbosePreFlight("Resuming agent run from checkpoint", [
6417
6427
  { label: "Checkpoint ID", value: checkpointId },
@@ -6474,6 +6484,8 @@ var resumeCommand = new Command3().name("resume").description("Resume an agent r
6474
6484
  console.error(
6475
6485
  chalk7.dim(" Try running without --experimental-realtime")
6476
6486
  );
6487
+ } else if (error.message.startsWith("Environment file not found:")) {
6488
+ console.error(chalk7.red(`\u2717 ${error.message}`));
6477
6489
  } else if (error.message.includes("not found")) {
6478
6490
  console.error(chalk7.red(`\u2717 Checkpoint not found: ${checkpointId}`));
6479
6491
  } else {
@@ -6494,13 +6506,16 @@ import chalk8 from "chalk";
6494
6506
  var continueCommand = new Command4().name("continue").description(
6495
6507
  "Continue an agent run from a session (uses latest artifact version)"
6496
6508
  ).argument("<agentSessionId>", "Agent session ID to continue from").argument("<prompt>", "Prompt for the continued agent").option(
6509
+ "--env-file <path>",
6510
+ "Load environment variables from file (priority: CLI flags > file > env vars)"
6511
+ ).option(
6497
6512
  "--vars <KEY=value>",
6498
- "Variables for ${{ vars.xxx }} (repeatable, falls back to env vars and .env)",
6513
+ "Variables for ${{ vars.xxx }} (repeatable, falls back to --env-file or env vars)",
6499
6514
  collectKeyValue,
6500
6515
  {}
6501
6516
  ).option(
6502
6517
  "--secrets <KEY=value>",
6503
- "Secrets for ${{ secrets.xxx }} (repeatable, required for continue)",
6518
+ "Secrets for ${{ secrets.xxx }} (repeatable, falls back to --env-file or env vars)",
6504
6519
  collectKeyValue,
6505
6520
  {}
6506
6521
  ).option(
@@ -6532,7 +6547,8 @@ var continueCommand = new Command4().name("continue").description(
6532
6547
  }
6533
6548
  const sessionInfo = await getSession(agentSessionId);
6534
6549
  const requiredSecretNames = sessionInfo.secretNames || [];
6535
- const loadedSecrets = loadValues(secrets, requiredSecretNames);
6550
+ const envFile = options.envFile || allOpts.envFile;
6551
+ const loadedSecrets = loadValues(secrets, requiredSecretNames, envFile);
6536
6552
  if (verbose) {
6537
6553
  logVerbosePreFlight("Continuing agent run from session", [
6538
6554
  { label: "Session ID", value: agentSessionId },
@@ -6596,6 +6612,8 @@ var continueCommand = new Command4().name("continue").description(
6596
6612
  console.error(
6597
6613
  chalk8.dim(" Try running without --experimental-realtime")
6598
6614
  );
6615
+ } else if (error.message.startsWith("Environment file not found:")) {
6616
+ console.error(chalk8.red(`\u2717 ${error.message}`));
6599
6617
  } else if (error.message.includes("not found")) {
6600
6618
  console.error(
6601
6619
  chalk8.red(`\u2717 Agent session not found: ${agentSessionId}`)
@@ -6623,13 +6641,13 @@ import { Command as Command11 } from "commander";
6623
6641
  // src/commands/volume/init.ts
6624
6642
  import { Command as Command5 } from "commander";
6625
6643
  import chalk9 from "chalk";
6626
- import path7 from "path";
6644
+ import path6 from "path";
6627
6645
 
6628
6646
  // src/lib/storage/storage-utils.ts
6629
6647
  import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
6630
6648
  import { existsSync as existsSync5 } from "fs";
6631
6649
  import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
6632
- import path6 from "path";
6650
+ import path5 from "path";
6633
6651
  var CONFIG_DIR2 = ".vm0";
6634
6652
  var CONFIG_FILE2 = "storage.yaml";
6635
6653
  function isValidStorageName(name) {
@@ -6640,8 +6658,8 @@ function isValidStorageName(name) {
6640
6658
  return pattern.test(name) && !name.includes("--");
6641
6659
  }
6642
6660
  async function readStorageConfig(basePath = process.cwd()) {
6643
- const configPath = path6.join(basePath, CONFIG_DIR2, CONFIG_FILE2);
6644
- const legacyConfigPath = path6.join(basePath, CONFIG_DIR2, "volume.yaml");
6661
+ const configPath = path5.join(basePath, CONFIG_DIR2, CONFIG_FILE2);
6662
+ const legacyConfigPath = path5.join(basePath, CONFIG_DIR2, "volume.yaml");
6645
6663
  let actualPath = null;
6646
6664
  if (existsSync5(configPath)) {
6647
6665
  actualPath = configPath;
@@ -6659,8 +6677,8 @@ async function readStorageConfig(basePath = process.cwd()) {
6659
6677
  return config;
6660
6678
  }
6661
6679
  async function writeStorageConfig(storageName, basePath = process.cwd(), type = "volume") {
6662
- const configDir = path6.join(basePath, CONFIG_DIR2);
6663
- const configPath = path6.join(configDir, CONFIG_FILE2);
6680
+ const configDir = path5.join(basePath, CONFIG_DIR2);
6681
+ const configPath = path5.join(configDir, CONFIG_FILE2);
6664
6682
  if (!existsSync5(configDir)) {
6665
6683
  await mkdir4(configDir, { recursive: true });
6666
6684
  }
@@ -6736,19 +6754,37 @@ async function promptSelect(message, choices, initial) {
6736
6754
  );
6737
6755
  return response.value;
6738
6756
  }
6757
+ async function promptPassword(message) {
6758
+ if (!isInteractive()) {
6759
+ return void 0;
6760
+ }
6761
+ const response = await prompts2(
6762
+ {
6763
+ type: "password",
6764
+ name: "value",
6765
+ message
6766
+ },
6767
+ {
6768
+ onCancel: () => {
6769
+ return false;
6770
+ }
6771
+ }
6772
+ );
6773
+ return response.value;
6774
+ }
6739
6775
 
6740
6776
  // src/commands/volume/init.ts
6741
6777
  var initCommand = new Command5().name("init").description("Initialize a volume in the current directory").option("-n, --name <name>", "Volume name (required in non-interactive mode)").action(async (options) => {
6742
6778
  try {
6743
6779
  const cwd = process.cwd();
6744
- const dirName = path7.basename(cwd);
6780
+ const dirName = path6.basename(cwd);
6745
6781
  const existingConfig = await readStorageConfig(cwd);
6746
6782
  if (existingConfig) {
6747
6783
  console.log(
6748
6784
  chalk9.yellow(`Volume already initialized: ${existingConfig.name}`)
6749
6785
  );
6750
6786
  console.log(
6751
- chalk9.dim(`Config file: ${path7.join(cwd, ".vm0", "storage.yaml")}`)
6787
+ chalk9.dim(`Config file: ${path6.join(cwd, ".vm0", "storage.yaml")}`)
6752
6788
  );
6753
6789
  return;
6754
6790
  }
@@ -6797,7 +6833,7 @@ var initCommand = new Command5().name("init").description("Initialize a volume i
6797
6833
  console.log(chalk9.green(`\u2713 Initialized volume: ${volumeName}`));
6798
6834
  console.log(
6799
6835
  chalk9.dim(
6800
- `\u2713 Config saved to ${path7.join(cwd, ".vm0", "storage.yaml")}`
6836
+ `\u2713 Config saved to ${path6.join(cwd, ".vm0", "storage.yaml")}`
6801
6837
  )
6802
6838
  );
6803
6839
  } catch (error) {
@@ -6865,7 +6901,7 @@ var pushCommand = new Command6().name("push").description("Push local files to c
6865
6901
  // src/commands/volume/pull.ts
6866
6902
  import { Command as Command7 } from "commander";
6867
6903
  import chalk12 from "chalk";
6868
- import path8 from "path";
6904
+ import path7 from "path";
6869
6905
  import * as fs6 from "fs";
6870
6906
  import * as os4 from "os";
6871
6907
  import * as tar3 from "tar";
@@ -6926,8 +6962,8 @@ var pullCommand = new Command7().name("pull").description("Pull cloud files to l
6926
6962
  const arrayBuffer = await s3Response.arrayBuffer();
6927
6963
  const tarBuffer = Buffer.from(arrayBuffer);
6928
6964
  console.log(chalk12.green(`\u2713 Downloaded ${formatBytes3(tarBuffer.length)}`));
6929
- const tmpDir = fs6.mkdtempSync(path8.join(os4.tmpdir(), "vm0-"));
6930
- const tarPath = path8.join(tmpDir, "volume.tar.gz");
6965
+ const tmpDir = fs6.mkdtempSync(path7.join(os4.tmpdir(), "vm0-"));
6966
+ const tarPath = path7.join(tmpDir, "volume.tar.gz");
6931
6967
  await fs6.promises.writeFile(tarPath, tarBuffer);
6932
6968
  console.log(chalk12.dim("Syncing local files..."));
6933
6969
  const remoteFiles = await listTarFiles(tarPath);
@@ -7080,7 +7116,7 @@ import chalk16 from "chalk";
7080
7116
 
7081
7117
  // src/lib/storage/clone-utils.ts
7082
7118
  import chalk15 from "chalk";
7083
- import path9 from "path";
7119
+ import path8 from "path";
7084
7120
  import * as fs7 from "fs";
7085
7121
  import * as os5 from "os";
7086
7122
  import * as tar4 from "tar";
@@ -7121,8 +7157,8 @@ async function cloneStorage(name, type, destination, options = {}) {
7121
7157
  const arrayBuffer = await s3Response.arrayBuffer();
7122
7158
  const tarBuffer = Buffer.from(arrayBuffer);
7123
7159
  console.log(chalk15.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
7124
- const tmpDir = fs7.mkdtempSync(path9.join(os5.tmpdir(), "vm0-clone-"));
7125
- const tarPath = path9.join(tmpDir, "archive.tar.gz");
7160
+ const tmpDir = fs7.mkdtempSync(path8.join(os5.tmpdir(), "vm0-clone-"));
7161
+ const tarPath = path8.join(tmpDir, "archive.tar.gz");
7126
7162
  await fs7.promises.writeFile(tarPath, tarBuffer);
7127
7163
  const files = await listTarFiles(tarPath);
7128
7164
  console.log(chalk15.dim("Extracting files..."));
@@ -7176,14 +7212,14 @@ import { Command as Command18 } from "commander";
7176
7212
  // src/commands/artifact/init.ts
7177
7213
  import { Command as Command12 } from "commander";
7178
7214
  import chalk17 from "chalk";
7179
- import path10 from "path";
7215
+ import path9 from "path";
7180
7216
  var initCommand2 = new Command12().name("init").description("Initialize an artifact in the current directory").option(
7181
7217
  "-n, --name <name>",
7182
7218
  "Artifact name (required in non-interactive mode)"
7183
7219
  ).action(async (options) => {
7184
7220
  try {
7185
7221
  const cwd = process.cwd();
7186
- const dirName = path10.basename(cwd);
7222
+ const dirName = path9.basename(cwd);
7187
7223
  const existingConfig = await readStorageConfig(cwd);
7188
7224
  if (existingConfig) {
7189
7225
  if (existingConfig.type === "artifact") {
@@ -7205,7 +7241,7 @@ var initCommand2 = new Command12().name("init").description("Initialize an artif
7205
7241
  );
7206
7242
  }
7207
7243
  console.log(
7208
- chalk17.dim(`Config file: ${path10.join(cwd, ".vm0", "storage.yaml")}`)
7244
+ chalk17.dim(`Config file: ${path9.join(cwd, ".vm0", "storage.yaml")}`)
7209
7245
  );
7210
7246
  return;
7211
7247
  }
@@ -7254,7 +7290,7 @@ var initCommand2 = new Command12().name("init").description("Initialize an artif
7254
7290
  console.log(chalk17.green(`\u2713 Initialized artifact: ${artifactName}`));
7255
7291
  console.log(
7256
7292
  chalk17.dim(
7257
- `\u2713 Config saved to ${path10.join(cwd, ".vm0", "storage.yaml")}`
7293
+ `\u2713 Config saved to ${path9.join(cwd, ".vm0", "storage.yaml")}`
7258
7294
  )
7259
7295
  );
7260
7296
  } catch (error) {
@@ -7327,7 +7363,7 @@ var pushCommand2 = new Command13().name("push").description("Push local files to
7327
7363
  // src/commands/artifact/pull.ts
7328
7364
  import { Command as Command14 } from "commander";
7329
7365
  import chalk19 from "chalk";
7330
- import path11 from "path";
7366
+ import path10 from "path";
7331
7367
  import * as fs8 from "fs";
7332
7368
  import * as os6 from "os";
7333
7369
  import * as tar5 from "tar";
@@ -7383,8 +7419,8 @@ var pullCommand2 = new Command14().name("pull").description("Pull cloud artifact
7383
7419
  const arrayBuffer = await s3Response.arrayBuffer();
7384
7420
  const tarBuffer = Buffer.from(arrayBuffer);
7385
7421
  console.log(chalk19.green(`\u2713 Downloaded ${formatBytes6(tarBuffer.length)}`));
7386
- const tmpDir = fs8.mkdtempSync(path11.join(os6.tmpdir(), "vm0-"));
7387
- const tarPath = path11.join(tmpDir, "artifact.tar.gz");
7422
+ const tmpDir = fs8.mkdtempSync(path10.join(os6.tmpdir(), "vm0-"));
7423
+ const tarPath = path10.join(tmpDir, "artifact.tar.gz");
7388
7424
  await fs8.promises.writeFile(tarPath, tarBuffer);
7389
7425
  console.log(chalk19.dim("Syncing local files..."));
7390
7426
  const remoteFiles = await listTarFiles(tarPath);
@@ -7556,9 +7592,9 @@ var artifactCommand = new Command18().name("artifact").description("Manage artif
7556
7592
  // src/commands/cook.ts
7557
7593
  import { Command as Command19, Option as Option4 } from "commander";
7558
7594
  import chalk24 from "chalk";
7559
- import { readFile as readFile7, mkdir as mkdir6, writeFile as writeFile6, appendFile } from "fs/promises";
7560
- import { existsSync as existsSync8, readFileSync } from "fs";
7561
- import path12 from "path";
7595
+ import { readFile as readFile7, mkdir as mkdir6 } from "fs/promises";
7596
+ import { existsSync as existsSync8 } from "fs";
7597
+ import path11 from "path";
7562
7598
  import { spawn as spawn2 } from "child_process";
7563
7599
  import { parse as parseYaml4 } from "yaml";
7564
7600
  import { config as dotenvConfig2 } from "dotenv";
@@ -7630,7 +7666,7 @@ async function getLatestVersion() {
7630
7666
  }
7631
7667
  }
7632
7668
  function performUpgrade(packageManager) {
7633
- return new Promise((resolve2) => {
7669
+ return new Promise((resolve) => {
7634
7670
  const isWindows = process.platform === "win32";
7635
7671
  const command = isWindows ? `${packageManager}.cmd` : packageManager;
7636
7672
  const args = packageManager === "pnpm" ? ["add", "-g", `${PACKAGE_NAME}@latest`] : ["install", "-g", `${PACKAGE_NAME}@latest`];
@@ -7639,10 +7675,10 @@ function performUpgrade(packageManager) {
7639
7675
  shell: isWindows
7640
7676
  });
7641
7677
  child.on("close", (code) => {
7642
- resolve2(code === 0);
7678
+ resolve(code === 0);
7643
7679
  });
7644
7680
  child.on("error", () => {
7645
- resolve2(false);
7681
+ resolve(false);
7646
7682
  });
7647
7683
  });
7648
7684
  }
@@ -7774,7 +7810,7 @@ function printCommand(cmd) {
7774
7810
  console.log(chalk24.dim(`> ${cmd}`));
7775
7811
  }
7776
7812
  function execVm0Command(args, options = {}) {
7777
- return new Promise((resolve2, reject) => {
7813
+ return new Promise((resolve, reject) => {
7778
7814
  const stdio = options.silent ? "pipe" : "inherit";
7779
7815
  const proc = spawn2("vm0", args, {
7780
7816
  cwd: options.cwd,
@@ -7793,7 +7829,7 @@ function execVm0Command(args, options = {}) {
7793
7829
  }
7794
7830
  proc.on("close", (code) => {
7795
7831
  if (code === 0) {
7796
- resolve2(stdout);
7832
+ resolve(stdout);
7797
7833
  } else {
7798
7834
  reject(new Error(stderr || `Command failed with exit code ${code}`));
7799
7835
  }
@@ -7804,7 +7840,7 @@ function execVm0Command(args, options = {}) {
7804
7840
  });
7805
7841
  }
7806
7842
  function execVm0RunWithCapture(args, options = {}) {
7807
- return new Promise((resolve2, reject) => {
7843
+ return new Promise((resolve, reject) => {
7808
7844
  const proc = spawn2("vm0", args, {
7809
7845
  cwd: options.cwd,
7810
7846
  stdio: ["inherit", "pipe", "pipe"],
@@ -7824,7 +7860,7 @@ function execVm0RunWithCapture(args, options = {}) {
7824
7860
  });
7825
7861
  proc.on("close", (code) => {
7826
7862
  if (code === 0) {
7827
- resolve2(stdout);
7863
+ resolve(stdout);
7828
7864
  } else {
7829
7865
  reject(new Error(stderr || `Command failed with exit code ${code}`));
7830
7866
  }
@@ -7871,36 +7907,26 @@ function extractRequiredVarNames(config) {
7871
7907
  return [.../* @__PURE__ */ new Set([...varNames, ...secretNames])];
7872
7908
  }
7873
7909
  function checkMissingVariables(varNames, envFilePath) {
7874
- let dotenvValues = {};
7875
- if (existsSync8(envFilePath)) {
7910
+ let fileValues = {};
7911
+ if (envFilePath) {
7912
+ if (!existsSync8(envFilePath)) {
7913
+ throw new Error(`Environment file not found: ${envFilePath}`);
7914
+ }
7876
7915
  const result = dotenvConfig2({ path: envFilePath, quiet: true });
7877
7916
  if (result.parsed) {
7878
- dotenvValues = result.parsed;
7917
+ fileValues = result.parsed;
7879
7918
  }
7880
7919
  }
7881
7920
  const missing = [];
7882
7921
  for (const name of varNames) {
7883
7922
  const inEnv = process.env[name] !== void 0;
7884
- const inDotenv = dotenvValues[name] !== void 0;
7885
- if (!inEnv && !inDotenv) {
7923
+ const inFile = fileValues[name] !== void 0;
7924
+ if (!inEnv && !inFile) {
7886
7925
  missing.push(name);
7887
7926
  }
7888
7927
  }
7889
7928
  return missing;
7890
7929
  }
7891
- async function generateEnvPlaceholders(missingVars, envFilePath) {
7892
- const placeholders = missingVars.map((name) => `${name}=`).join("\n");
7893
- if (existsSync8(envFilePath)) {
7894
- const existingContent = readFileSync(envFilePath, "utf8");
7895
- const needsNewline = existingContent.length > 0 && !existingContent.endsWith("\n");
7896
- const prefix = needsNewline ? "\n" : "";
7897
- await appendFile(envFilePath, `${prefix}${placeholders}
7898
- `);
7899
- } else {
7900
- await writeFile6(envFilePath, `${placeholders}
7901
- `);
7902
- }
7903
- }
7904
7930
  async function autoPullArtifact(runOutput, artifactDir) {
7905
7931
  const serverVersion = parseArtifactVersionFromCompletion(
7906
7932
  runOutput,
@@ -7926,11 +7952,14 @@ async function autoPullArtifact(runOutput, artifactDir) {
7926
7952
  }
7927
7953
  }
7928
7954
  var cookCmd = new Command19().name("cook").description("Quick start: prepare, compose and run agent from vm0.yaml");
7929
- cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip confirmation prompts").addOption(new Option4("--debug-no-mock-claude").hideHelp()).addOption(new Option4("--no-auto-update").hideHelp()).action(
7955
+ cookCmd.argument("[prompt]", "Prompt for the agent").option(
7956
+ "--env-file <path>",
7957
+ "Load environment variables from file (priority: CLI flags > file > env vars)"
7958
+ ).option("-y, --yes", "Skip confirmation prompts").addOption(new Option4("--debug-no-mock-claude").hideHelp()).addOption(new Option4("--no-auto-update").hideHelp()).action(
7930
7959
  // eslint-disable-next-line complexity -- TODO: refactor complex function
7931
7960
  async (prompt, options) => {
7932
7961
  if (!options.noAutoUpdate) {
7933
- const shouldExit = await checkAndUpgrade("7.1.1", prompt);
7962
+ const shouldExit = await checkAndUpgrade("8.0.1", prompt);
7934
7963
  if (shouldExit) {
7935
7964
  process.exit(0);
7936
7965
  }
@@ -7965,21 +7994,27 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
7965
7994
  );
7966
7995
  const requiredVarNames = extractRequiredVarNames(config);
7967
7996
  if (requiredVarNames.length > 0) {
7968
- const envFilePath = path12.join(cwd, ".env");
7969
- const missingVars = checkMissingVariables(
7970
- requiredVarNames,
7971
- envFilePath
7972
- );
7973
- if (missingVars.length > 0) {
7974
- await generateEnvPlaceholders(missingVars, envFilePath);
7975
- console.log();
7976
- console.log(
7977
- chalk24.yellow(
7978
- `\u26A0 Missing environment variables. Please fill in values in .env file:`
7979
- )
7997
+ try {
7998
+ const missingVars = checkMissingVariables(
7999
+ requiredVarNames,
8000
+ options.envFile
7980
8001
  );
7981
- for (const varName of missingVars) {
7982
- console.log(chalk24.yellow(` ${varName}`));
8002
+ if (missingVars.length > 0) {
8003
+ console.log();
8004
+ console.error(chalk24.red("\u2717 Missing required variables:"));
8005
+ for (const varName of missingVars) {
8006
+ console.error(chalk24.red(` ${varName}`));
8007
+ }
8008
+ console.error(
8009
+ chalk24.dim(
8010
+ "\n Provide via --env-file, or set as environment variables"
8011
+ )
8012
+ );
8013
+ process.exit(1);
8014
+ }
8015
+ } catch (error) {
8016
+ if (error instanceof Error) {
8017
+ console.error(chalk24.red(`\u2717 ${error.message}`));
7983
8018
  }
7984
8019
  process.exit(1);
7985
8020
  }
@@ -7988,7 +8023,7 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
7988
8023
  console.log();
7989
8024
  console.log(chalk24.bold("Processing volumes:"));
7990
8025
  for (const volumeConfig of Object.values(config.volumes)) {
7991
- const volumeDir = path12.join(cwd, volumeConfig.name);
8026
+ const volumeDir = path11.join(cwd, volumeConfig.name);
7992
8027
  if (!existsSync8(volumeDir)) {
7993
8028
  console.error(
7994
8029
  chalk24.red(
@@ -8027,7 +8062,7 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
8027
8062
  }
8028
8063
  console.log();
8029
8064
  console.log(chalk24.bold("Processing artifact:"));
8030
- const artifactDir = path12.join(cwd, ARTIFACT_DIR);
8065
+ const artifactDir = path11.join(cwd, ARTIFACT_DIR);
8031
8066
  try {
8032
8067
  if (!existsSync8(artifactDir)) {
8033
8068
  printCommand(`mkdir ${ARTIFACT_DIR}`);
@@ -8156,80 +8191,98 @@ cookCmd.command("logs").description("View logs from the last cook run").option("
8156
8191
  );
8157
8192
  cookCmd.command("continue").description(
8158
8193
  "Continue from the last session (latest conversation and artifact)"
8159
- ).argument("<prompt>", "Prompt for the continued agent").addOption(new Option4("--debug-no-mock-claude").hideHelp()).action(async (prompt, options) => {
8160
- const state = await loadCookState();
8161
- if (!state.lastSessionId) {
8162
- console.error(chalk24.red("\u2717 No previous session found"));
8163
- console.error(chalk24.dim(" Run 'vm0 cook <prompt>' first"));
8164
- process.exit(1);
8165
- }
8166
- const cwd = process.cwd();
8167
- const artifactDir = path12.join(cwd, ARTIFACT_DIR);
8168
- printCommand(`vm0 run continue ${state.lastSessionId} "${prompt}"`);
8169
- console.log();
8170
- let runOutput;
8171
- try {
8172
- runOutput = await execVm0RunWithCapture(
8173
- [
8174
- "run",
8175
- "continue",
8176
- state.lastSessionId,
8177
- ...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
8178
- prompt
8179
- ],
8180
- { cwd }
8194
+ ).argument("<prompt>", "Prompt for the continued agent").option(
8195
+ "--env-file <path>",
8196
+ "Load environment variables from file (priority: CLI flags > file > env vars)"
8197
+ ).addOption(new Option4("--debug-no-mock-claude").hideHelp()).action(
8198
+ async (prompt, options) => {
8199
+ const state = await loadCookState();
8200
+ if (!state.lastSessionId) {
8201
+ console.error(chalk24.red("\u2717 No previous session found"));
8202
+ console.error(chalk24.dim(" Run 'vm0 cook <prompt>' first"));
8203
+ process.exit(1);
8204
+ }
8205
+ const cwd = process.cwd();
8206
+ const artifactDir = path11.join(cwd, ARTIFACT_DIR);
8207
+ const envFileArg = options.envFile ? ` --env-file ${options.envFile}` : "";
8208
+ printCommand(
8209
+ `vm0 run continue${envFileArg} ${state.lastSessionId} "${prompt}"`
8181
8210
  );
8182
- } catch {
8183
- process.exit(1);
8184
- }
8185
- const newIds = parseRunIdsFromOutput(runOutput);
8186
- if (newIds.runId || newIds.sessionId || newIds.checkpointId) {
8187
- await saveCookState({
8188
- lastRunId: newIds.runId,
8189
- lastSessionId: newIds.sessionId,
8190
- lastCheckpointId: newIds.checkpointId
8191
- });
8211
+ console.log();
8212
+ let runOutput;
8213
+ try {
8214
+ runOutput = await execVm0RunWithCapture(
8215
+ [
8216
+ "run",
8217
+ "continue",
8218
+ ...options.envFile ? ["--env-file", options.envFile] : [],
8219
+ state.lastSessionId,
8220
+ ...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
8221
+ prompt
8222
+ ],
8223
+ { cwd }
8224
+ );
8225
+ } catch {
8226
+ process.exit(1);
8227
+ }
8228
+ const newIds = parseRunIdsFromOutput(runOutput);
8229
+ if (newIds.runId || newIds.sessionId || newIds.checkpointId) {
8230
+ await saveCookState({
8231
+ lastRunId: newIds.runId,
8232
+ lastSessionId: newIds.sessionId,
8233
+ lastCheckpointId: newIds.checkpointId
8234
+ });
8235
+ }
8236
+ await autoPullArtifact(runOutput, artifactDir);
8192
8237
  }
8193
- await autoPullArtifact(runOutput, artifactDir);
8194
- });
8238
+ );
8195
8239
  cookCmd.command("resume").description(
8196
8240
  "Resume from the last checkpoint (snapshotted conversation and artifact)"
8197
- ).argument("<prompt>", "Prompt for the resumed agent").addOption(new Option4("--debug-no-mock-claude").hideHelp()).action(async (prompt, options) => {
8198
- const state = await loadCookState();
8199
- if (!state.lastCheckpointId) {
8200
- console.error(chalk24.red("\u2717 No previous checkpoint found"));
8201
- console.error(chalk24.dim(" Run 'vm0 cook <prompt>' first"));
8202
- process.exit(1);
8203
- }
8204
- const cwd = process.cwd();
8205
- const artifactDir = path12.join(cwd, ARTIFACT_DIR);
8206
- printCommand(`vm0 run resume ${state.lastCheckpointId} "${prompt}"`);
8207
- console.log();
8208
- let runOutput;
8209
- try {
8210
- runOutput = await execVm0RunWithCapture(
8211
- [
8212
- "run",
8213
- "resume",
8214
- state.lastCheckpointId,
8215
- ...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
8216
- prompt
8217
- ],
8218
- { cwd }
8241
+ ).argument("<prompt>", "Prompt for the resumed agent").option(
8242
+ "--env-file <path>",
8243
+ "Load environment variables from file (priority: CLI flags > file > env vars)"
8244
+ ).addOption(new Option4("--debug-no-mock-claude").hideHelp()).action(
8245
+ async (prompt, options) => {
8246
+ const state = await loadCookState();
8247
+ if (!state.lastCheckpointId) {
8248
+ console.error(chalk24.red("\u2717 No previous checkpoint found"));
8249
+ console.error(chalk24.dim(" Run 'vm0 cook <prompt>' first"));
8250
+ process.exit(1);
8251
+ }
8252
+ const cwd = process.cwd();
8253
+ const artifactDir = path11.join(cwd, ARTIFACT_DIR);
8254
+ const envFileArg = options.envFile ? ` --env-file ${options.envFile}` : "";
8255
+ printCommand(
8256
+ `vm0 run resume${envFileArg} ${state.lastCheckpointId} "${prompt}"`
8219
8257
  );
8220
- } catch {
8221
- process.exit(1);
8222
- }
8223
- const newIds = parseRunIdsFromOutput(runOutput);
8224
- if (newIds.runId || newIds.sessionId || newIds.checkpointId) {
8225
- await saveCookState({
8226
- lastRunId: newIds.runId,
8227
- lastSessionId: newIds.sessionId,
8228
- lastCheckpointId: newIds.checkpointId
8229
- });
8258
+ console.log();
8259
+ let runOutput;
8260
+ try {
8261
+ runOutput = await execVm0RunWithCapture(
8262
+ [
8263
+ "run",
8264
+ "resume",
8265
+ ...options.envFile ? ["--env-file", options.envFile] : [],
8266
+ state.lastCheckpointId,
8267
+ ...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
8268
+ prompt
8269
+ ],
8270
+ { cwd }
8271
+ );
8272
+ } catch {
8273
+ process.exit(1);
8274
+ }
8275
+ const newIds = parseRunIdsFromOutput(runOutput);
8276
+ if (newIds.runId || newIds.sessionId || newIds.checkpointId) {
8277
+ await saveCookState({
8278
+ lastRunId: newIds.runId,
8279
+ lastSessionId: newIds.sessionId,
8280
+ lastCheckpointId: newIds.checkpointId
8281
+ });
8282
+ }
8283
+ await autoPullArtifact(runOutput, artifactDir);
8230
8284
  }
8231
- await autoPullArtifact(runOutput, artifactDir);
8232
- });
8285
+ );
8233
8286
  var cookCommand = cookCmd;
8234
8287
 
8235
8288
  // src/commands/logs/index.ts
@@ -8616,10 +8669,9 @@ import { Command as Command26 } from "commander";
8616
8669
  // src/commands/agent/list.ts
8617
8670
  import { Command as Command24 } from "commander";
8618
8671
  import chalk28 from "chalk";
8619
- var listCommand3 = new Command24().name("list").alias("ls").description("List all agent composes").option("-s, --scope <scope>", "Scope to list composes from").action(async (options) => {
8672
+ var listCommand3 = new Command24().name("list").alias("ls").description("List all agent composes").action(async () => {
8620
8673
  try {
8621
- const url = options.scope ? `/api/agent/composes/list?scope=${encodeURIComponent(options.scope)}` : "/api/agent/composes/list";
8622
- const response = await httpGet(url);
8674
+ const response = await httpGet("/api/agent/composes/list");
8623
8675
  if (!response.ok) {
8624
8676
  const error = await response.json();
8625
8677
  throw new Error(error.error?.message || "List failed");
@@ -8659,35 +8711,14 @@ var listCommand3 = new Command24().name("list").alias("ls").description("List al
8659
8711
  }
8660
8712
  });
8661
8713
 
8662
- // src/commands/agent/inspect.ts
8714
+ // src/commands/agent/status.ts
8663
8715
  import { Command as Command25 } from "commander";
8664
8716
  import chalk29 from "chalk";
8665
8717
 
8666
8718
  // src/lib/domain/source-derivation.ts
8667
8719
  import * as fs9 from "fs/promises";
8668
- import * as path13 from "path";
8720
+ import * as path12 from "path";
8669
8721
  import * as os7 from "os";
8670
- function extractVariableReferences2(environment) {
8671
- const secrets = [];
8672
- const vars = [];
8673
- for (const value of Object.values(environment)) {
8674
- const matches = value.matchAll(/\$\{?([A-Z_][A-Z0-9_]*)\}?/g);
8675
- for (const match of matches) {
8676
- const varName = match[1];
8677
- if (!varName) continue;
8678
- if (varName.endsWith("_KEY") || varName.endsWith("_SECRET") || varName.endsWith("_TOKEN") || varName.endsWith("_PASSWORD") || varName.includes("API_KEY") || varName.includes("SECRET")) {
8679
- if (!secrets.includes(varName)) {
8680
- secrets.push(varName);
8681
- }
8682
- } else {
8683
- if (!vars.includes(varName)) {
8684
- vars.push(varName);
8685
- }
8686
- }
8687
- }
8688
- }
8689
- return { secrets: secrets.sort(), vars: vars.sort() };
8690
- }
8691
8722
  async function fetchSkillFrontmatter(skillUrl, tempDir) {
8692
8723
  try {
8693
8724
  const parsed = parseGitHubTreeUrl2(skillUrl);
@@ -8699,23 +8730,35 @@ async function fetchSkillFrontmatter(skillUrl, tempDir) {
8699
8730
  }
8700
8731
  }
8701
8732
  async function deriveAgentVariableSources(agent, options) {
8702
- const { secrets: secretNames, vars: varNames } = agent.environment ? extractVariableReferences2(agent.environment) : { secrets: [], vars: [] };
8733
+ const refs = agent.environment ? extractVariableReferences(agent.environment) : [];
8734
+ const grouped = groupVariablesBySource(refs);
8703
8735
  const secretSources = /* @__PURE__ */ new Map();
8704
8736
  const varSources = /* @__PURE__ */ new Map();
8705
- for (const name of secretNames) {
8706
- secretSources.set(name, { name, source: "agent environment" });
8737
+ const credentialSources = /* @__PURE__ */ new Map();
8738
+ for (const ref of grouped.secrets) {
8739
+ secretSources.set(ref.name, {
8740
+ name: ref.name,
8741
+ source: "agent environment"
8742
+ });
8707
8743
  }
8708
- for (const name of varNames) {
8709
- varSources.set(name, { name, source: "agent environment" });
8744
+ for (const ref of grouped.vars) {
8745
+ varSources.set(ref.name, { name: ref.name, source: "agent environment" });
8746
+ }
8747
+ for (const ref of grouped.credentials) {
8748
+ credentialSources.set(ref.name, {
8749
+ name: ref.name,
8750
+ source: "agent environment"
8751
+ });
8710
8752
  }
8711
8753
  if (options?.skipNetwork || !agent.skills || agent.skills.length === 0) {
8712
8754
  return {
8713
8755
  secrets: Array.from(secretSources.values()),
8714
- vars: Array.from(varSources.values())
8756
+ vars: Array.from(varSources.values()),
8757
+ credentials: Array.from(credentialSources.values())
8715
8758
  };
8716
8759
  }
8717
8760
  const tempDir = await fs9.mkdtemp(
8718
- path13.join(os7.tmpdir(), "vm0-source-derivation-")
8761
+ path12.join(os7.tmpdir(), "vm0-source-derivation-")
8719
8762
  );
8720
8763
  try {
8721
8764
  const skillResults = await Promise.all(
@@ -8752,7 +8795,8 @@ async function deriveAgentVariableSources(agent, options) {
8752
8795
  }
8753
8796
  return {
8754
8797
  secrets: Array.from(secretSources.values()),
8755
- vars: Array.from(varSources.values())
8798
+ vars: Array.from(varSources.values()),
8799
+ credentials: Array.from(credentialSources.values())
8756
8800
  };
8757
8801
  }
8758
8802
  async function deriveComposeVariableSources(content, options) {
@@ -8769,156 +8813,166 @@ async function deriveComposeVariableSources(content, options) {
8769
8813
  return results;
8770
8814
  }
8771
8815
 
8772
- // src/commands/agent/inspect.ts
8816
+ // src/commands/agent/status.ts
8817
+ function formatListSection(label, items) {
8818
+ if (items.length === 0) return;
8819
+ console.log(` ${label}:`);
8820
+ for (const item of items) {
8821
+ console.log(` - ${item}`);
8822
+ }
8823
+ }
8824
+ function formatVolumes(volumes, volumeConfigs) {
8825
+ if (volumes.length === 0) return;
8826
+ console.log(` Volumes:`);
8827
+ for (const vol of volumes) {
8828
+ const volumeDef = volumeConfigs?.[vol];
8829
+ if (volumeDef) {
8830
+ console.log(` - ${vol}:${volumeDef.version.slice(0, 8)}`);
8831
+ } else {
8832
+ console.log(` - ${vol}`);
8833
+ }
8834
+ }
8835
+ }
8836
+ function formatVariableSources(sources) {
8837
+ if (sources.secrets.length > 0) {
8838
+ console.log(` Secrets:`);
8839
+ for (const secret of sources.secrets) {
8840
+ const sourceInfo = chalk29.dim(`(${secret.source})`);
8841
+ console.log(` - ${secret.name.padEnd(20)} ${sourceInfo}`);
8842
+ }
8843
+ }
8844
+ if (sources.vars.length > 0) {
8845
+ console.log(` Vars:`);
8846
+ for (const v of sources.vars) {
8847
+ const sourceInfo = chalk29.dim(`(${v.source})`);
8848
+ console.log(` - ${v.name.padEnd(20)} ${sourceInfo}`);
8849
+ }
8850
+ }
8851
+ if (sources.credentials.length > 0) {
8852
+ console.log(` Credentials:`);
8853
+ for (const cred of sources.credentials) {
8854
+ const sourceInfo = chalk29.dim(`(${cred.source})`);
8855
+ console.log(` - ${cred.name.padEnd(20)} ${sourceInfo}`);
8856
+ }
8857
+ }
8858
+ }
8859
+ function formatAgentDetails(agentName, agent, agentSources, volumeConfigs) {
8860
+ console.log(` ${chalk29.cyan(agentName)}:`);
8861
+ console.log(` Framework: ${agent.framework}`);
8862
+ if (agent.image) {
8863
+ console.log(` Image: ${agent.image}`);
8864
+ }
8865
+ formatListSection("Apps", agent.apps ?? []);
8866
+ if (agent.working_dir) {
8867
+ console.log(` Working Dir: ${agent.working_dir}`);
8868
+ }
8869
+ formatVolumes(agent.volumes ?? [], volumeConfigs);
8870
+ formatListSection("Skills", agent.skills ?? []);
8871
+ if (agentSources) {
8872
+ formatVariableSources(agentSources);
8873
+ }
8874
+ if (agent.experimental_runner) {
8875
+ console.log(` Runner: ${agent.experimental_runner.group}`);
8876
+ }
8877
+ }
8773
8878
  function formatComposeOutput(name, versionId, content, variableSources) {
8774
8879
  console.log(chalk29.bold("Name:") + ` ${name}`);
8775
8880
  console.log(chalk29.bold("Version:") + ` ${versionId}`);
8776
8881
  console.log();
8777
8882
  console.log(chalk29.bold("Agents:"));
8778
8883
  for (const [agentName, agent] of Object.entries(content.agents)) {
8779
- console.log(` ${chalk29.cyan(agentName)}:`);
8780
- console.log(` Framework: ${agent.framework}`);
8781
- if (agent.image) {
8782
- console.log(` Image: ${agent.image}`);
8783
- }
8784
- if (agent.apps && agent.apps.length > 0) {
8785
- console.log(` Apps:`);
8786
- for (const app of agent.apps) {
8787
- console.log(` - ${app}`);
8788
- }
8789
- }
8790
- if (agent.working_dir) {
8791
- console.log(` Working Dir: ${agent.working_dir}`);
8792
- }
8793
- if (agent.volumes && agent.volumes.length > 0) {
8794
- console.log(` Volumes:`);
8795
- for (const vol of agent.volumes) {
8796
- const volumeDef = content.volumes?.[vol];
8797
- if (volumeDef) {
8798
- console.log(` - ${vol}:${volumeDef.version.slice(0, 8)}`);
8799
- } else {
8800
- console.log(` - ${vol}`);
8801
- }
8802
- }
8803
- }
8804
- if (agent.skills && agent.skills.length > 0) {
8805
- console.log(` Skills:`);
8806
- for (const skill of agent.skills) {
8807
- console.log(` - ${skill}`);
8808
- }
8809
- }
8810
8884
  const agentSources = variableSources?.get(agentName);
8811
- if (agentSources) {
8812
- if (agentSources.secrets.length > 0) {
8813
- console.log(` Secrets:`);
8814
- for (const secret of agentSources.secrets) {
8815
- const sourceInfo = chalk29.dim(`(${secret.source})`);
8816
- console.log(` - ${secret.name.padEnd(20)} ${sourceInfo}`);
8817
- }
8818
- }
8819
- if (agentSources.vars.length > 0) {
8820
- console.log(` Vars:`);
8821
- for (const v of agentSources.vars) {
8822
- const sourceInfo = chalk29.dim(`(${v.source})`);
8823
- console.log(` - ${v.name.padEnd(20)} ${sourceInfo}`);
8824
- }
8825
- }
8826
- }
8827
- if (agent.experimental_runner) {
8828
- console.log(` Runner: ${agent.experimental_runner.group}`);
8829
- }
8885
+ formatAgentDetails(agentName, agent, agentSources, content.volumes);
8830
8886
  }
8831
8887
  }
8832
- var inspectCommand = new Command25().name("inspect").description("Inspect an agent compose").argument(
8888
+ var statusCommand4 = new Command25().name("status").description("Show status of agent compose").argument(
8833
8889
  "<name[:version]>",
8834
8890
  "Agent name with optional version (e.g., my-agent:latest or my-agent:a1b2c3d4)"
8835
- ).option("-s, --scope <scope>", "Scope to look up the compose from").option("--no-sources", "Skip fetching skills to determine variable sources").action(
8836
- async (argument, options) => {
8837
- try {
8838
- const colonIndex = argument.lastIndexOf(":");
8839
- let name;
8840
- let version;
8841
- if (colonIndex === -1) {
8842
- name = argument;
8843
- version = "latest";
8844
- } else {
8845
- name = argument.slice(0, colonIndex);
8846
- version = argument.slice(colonIndex + 1) || "latest";
8847
- }
8848
- const compose = await getComposeByName(name, options.scope);
8849
- if (!compose) {
8850
- console.error(chalk29.red(`\u2717 Agent compose not found: ${name}`));
8851
- console.error(chalk29.dim(" Run: vm0 agent list"));
8852
- process.exit(1);
8853
- }
8854
- let resolvedVersionId = compose.headVersionId;
8855
- if (version !== "latest" && compose.headVersionId) {
8856
- if (version.length < 64) {
8857
- try {
8858
- const versionInfo = await getComposeVersion(compose.id, version);
8859
- resolvedVersionId = versionInfo.versionId;
8860
- } catch (error) {
8861
- if (error instanceof Error && error.message.includes("not found")) {
8862
- console.error(chalk29.red(`\u2717 Version not found: ${version}`));
8863
- console.error(
8864
- chalk29.dim(
8865
- ` HEAD version: ${compose.headVersionId?.slice(0, 8)}`
8866
- )
8867
- );
8868
- process.exit(1);
8869
- }
8870
- throw error;
8871
- }
8872
- } else {
8873
- resolvedVersionId = version;
8874
- }
8875
- }
8876
- if (!resolvedVersionId || !compose.content) {
8877
- console.error(chalk29.red(`\u2717 No version found for: ${name}`));
8878
- process.exit(1);
8879
- }
8880
- const content = compose.content;
8881
- let variableSources;
8882
- if (options.sources !== false) {
8891
+ ).option("--no-sources", "Skip fetching skills to determine variable sources").action(async (argument, options) => {
8892
+ try {
8893
+ const colonIndex = argument.lastIndexOf(":");
8894
+ let name;
8895
+ let version;
8896
+ if (colonIndex === -1) {
8897
+ name = argument;
8898
+ version = "latest";
8899
+ } else {
8900
+ name = argument.slice(0, colonIndex);
8901
+ version = argument.slice(colonIndex + 1) || "latest";
8902
+ }
8903
+ const compose = await getComposeByName(name);
8904
+ if (!compose) {
8905
+ console.error(chalk29.red(`\u2717 Agent compose not found: ${name}`));
8906
+ console.error(chalk29.dim(" Run: vm0 agent list"));
8907
+ process.exit(1);
8908
+ }
8909
+ let resolvedVersionId = compose.headVersionId;
8910
+ if (version !== "latest" && compose.headVersionId) {
8911
+ if (version.length < 64) {
8883
8912
  try {
8884
- variableSources = await deriveComposeVariableSources(content);
8885
- } catch {
8886
- console.error(
8887
- chalk29.yellow(
8888
- "\u26A0 Warning: Failed to fetch skill sources, showing basic info"
8889
- )
8890
- );
8913
+ const versionInfo = await getComposeVersion(compose.id, version);
8914
+ resolvedVersionId = versionInfo.versionId;
8915
+ } catch (error) {
8916
+ if (error instanceof Error && error.message.includes("not found")) {
8917
+ console.error(chalk29.red(`\u2717 Version not found: ${version}`));
8918
+ console.error(
8919
+ chalk29.dim(
8920
+ ` HEAD version: ${compose.headVersionId?.slice(0, 8)}`
8921
+ )
8922
+ );
8923
+ process.exit(1);
8924
+ }
8925
+ throw error;
8891
8926
  }
8927
+ } else {
8928
+ resolvedVersionId = version;
8892
8929
  }
8893
- formatComposeOutput(
8894
- compose.name,
8895
- resolvedVersionId,
8896
- content,
8897
- variableSources
8930
+ }
8931
+ if (!resolvedVersionId || !compose.content) {
8932
+ console.error(chalk29.red(`\u2717 No version found for: ${name}`));
8933
+ process.exit(1);
8934
+ }
8935
+ const content = compose.content;
8936
+ let variableSources;
8937
+ try {
8938
+ variableSources = await deriveComposeVariableSources(content, {
8939
+ skipNetwork: options.sources === false
8940
+ });
8941
+ } catch {
8942
+ console.error(
8943
+ chalk29.yellow(
8944
+ "\u26A0 Warning: Failed to fetch skill sources, showing basic info"
8945
+ )
8898
8946
  );
8899
- } catch (error) {
8900
- console.error(chalk29.red("\u2717 Failed to inspect agent compose"));
8901
- if (error instanceof Error) {
8902
- if (error.message.includes("Not authenticated")) {
8903
- console.error(chalk29.dim(" Run: vm0 auth login"));
8904
- } else {
8905
- console.error(chalk29.dim(` ${error.message}`));
8906
- }
8947
+ }
8948
+ formatComposeOutput(
8949
+ compose.name,
8950
+ resolvedVersionId,
8951
+ content,
8952
+ variableSources
8953
+ );
8954
+ } catch (error) {
8955
+ console.error(chalk29.red("\u2717 Failed to get agent compose status"));
8956
+ if (error instanceof Error) {
8957
+ if (error.message.includes("Not authenticated")) {
8958
+ console.error(chalk29.dim(" Run: vm0 auth login"));
8959
+ } else {
8960
+ console.error(chalk29.dim(` ${error.message}`));
8907
8961
  }
8908
- process.exit(1);
8909
8962
  }
8963
+ process.exit(1);
8910
8964
  }
8911
- );
8965
+ });
8912
8966
 
8913
8967
  // src/commands/agent/index.ts
8914
- var agentCommand = new Command26().name("agent").description("Manage agent composes").addCommand(listCommand3).addCommand(inspectCommand);
8968
+ var agentCommand = new Command26().name("agent").description("Manage agent composes").addCommand(listCommand3).addCommand(statusCommand4);
8915
8969
 
8916
8970
  // src/commands/init.ts
8917
8971
  import { Command as Command27 } from "commander";
8918
8972
  import chalk30 from "chalk";
8919
- import path14 from "path";
8973
+ import path13 from "path";
8920
8974
  import { existsSync as existsSync9 } from "fs";
8921
- import { writeFile as writeFile7 } from "fs/promises";
8975
+ import { writeFile as writeFile6 } from "fs/promises";
8922
8976
  var VM0_YAML_FILE = "vm0.yaml";
8923
8977
  var AGENTS_MD_FILE = "AGENTS.md";
8924
8978
  function generateVm0Yaml(agentName) {
@@ -8973,7 +9027,7 @@ var initCommand3 = new Command27().name("init").description("Initialize a new VM
8973
9027
  console.error(chalk30.dim(" Usage: vm0 init --name <agent-name>"));
8974
9028
  process.exit(1);
8975
9029
  } else {
8976
- const dirName = path14.basename(process.cwd());
9030
+ const dirName = path13.basename(process.cwd());
8977
9031
  const defaultName = validateAgentName(dirName) ? dirName : void 0;
8978
9032
  const name = await promptText(
8979
9033
  "Enter agent name",
@@ -8999,10 +9053,10 @@ var initCommand3 = new Command27().name("init").description("Initialize a new VM
8999
9053
  console.log(chalk30.dim(" Must start and end with letter or number"));
9000
9054
  process.exit(1);
9001
9055
  }
9002
- await writeFile7(VM0_YAML_FILE, generateVm0Yaml(agentName));
9056
+ await writeFile6(VM0_YAML_FILE, generateVm0Yaml(agentName));
9003
9057
  const vm0Status = existingFiles.includes(VM0_YAML_FILE) ? " (overwritten)" : "";
9004
9058
  console.log(chalk30.green(`\u2713 Created ${VM0_YAML_FILE}${vm0Status}`));
9005
- await writeFile7(AGENTS_MD_FILE, generateAgentsMd());
9059
+ await writeFile6(AGENTS_MD_FILE, generateAgentsMd());
9006
9060
  const agentsStatus = existingFiles.includes(AGENTS_MD_FILE) ? " (overwritten)" : "";
9007
9061
  console.log(chalk30.green(`\u2713 Created ${AGENTS_MD_FILE}${agentsStatus}`));
9008
9062
  console.log();
@@ -9018,541 +9072,33 @@ var initCommand3 = new Command27().name("init").description("Initialize a new VM
9018
9072
  );
9019
9073
  });
9020
9074
 
9021
- // src/commands/setup-github.ts
9075
+ // src/commands/schedule/index.ts
9076
+ import { Command as Command34 } from "commander";
9077
+
9078
+ // src/commands/schedule/setup.ts
9022
9079
  import { Command as Command28 } from "commander";
9023
9080
  import chalk31 from "chalk";
9024
- import { existsSync as existsSync10 } from "fs";
9025
- import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
9026
- import { execSync, spawnSync } from "child_process";
9027
- import path15 from "path";
9081
+
9082
+ // src/lib/domain/schedule-utils.ts
9028
9083
  import { parse as parseYaml5 } from "yaml";
9029
- function isGhInstalled() {
9030
- try {
9031
- execSync("gh --version", { stdio: "ignore" });
9032
- return true;
9033
- } catch {
9034
- return false;
9035
- }
9036
- }
9037
- function isGhAuthenticated() {
9038
- try {
9039
- execSync("gh auth status", { stdio: "ignore" });
9040
- return true;
9041
- } catch {
9042
- return false;
9043
- }
9044
- }
9045
- function getGitRoot() {
9046
- try {
9047
- return execSync("git rev-parse --show-toplevel", {
9048
- encoding: "utf8"
9049
- }).trim();
9050
- } catch {
9051
- return null;
9052
- }
9053
- }
9054
- function getRelativeWorkingDir(gitRoot) {
9055
- const cwd = process.cwd();
9056
- if (cwd === gitRoot) {
9057
- return null;
9058
- }
9059
- const relativePath = path15.relative(gitRoot, cwd);
9060
- return relativePath.replace(/\\/g, "/");
9061
- }
9062
- async function checkPrerequisites() {
9063
- console.log("Checking prerequisites...");
9064
- const gitRoot = getGitRoot();
9065
- if (!gitRoot) {
9066
- console.log(chalk31.red("\u2717 Not in a git repository"));
9067
- console.log();
9068
- console.log("This command must be run from within a git repository.");
9069
- console.log();
9070
- console.log("To initialize a git repository, run:");
9071
- console.log(` ${chalk31.cyan("git init")}`);
9072
- process.exit(1);
9073
- }
9074
- console.log(chalk31.green("\u2713 Git repository detected"));
9075
- if (!isGhInstalled()) {
9076
- console.log(chalk31.red("\u2717 GitHub CLI (gh) is not installed"));
9077
- console.log();
9078
- console.log("GitHub CLI is required for this command.");
9079
- console.log();
9080
- console.log(` macOS: ${chalk31.cyan("brew install gh")}`);
9081
- console.log(` Other: ${chalk31.cyan("https://cli.github.com/")}`);
9082
- console.log();
9083
- console.log("After installation, run:");
9084
- console.log(` ${chalk31.cyan("gh auth login")}`);
9085
- console.log();
9086
- console.log("Then try again:");
9087
- console.log(` ${chalk31.cyan("vm0 setup-github")}`);
9088
- process.exit(1);
9089
- }
9090
- console.log(chalk31.green("\u2713 GitHub CLI (gh) is installed"));
9091
- if (!isGhAuthenticated()) {
9092
- console.log(chalk31.red("\u2717 GitHub CLI is not authenticated"));
9093
- console.log();
9094
- console.log("Please authenticate GitHub CLI first:");
9095
- console.log(` ${chalk31.cyan("gh auth login")}`);
9096
- console.log();
9097
- console.log("Then try again:");
9098
- console.log(` ${chalk31.cyan("vm0 setup-github")}`);
9099
- process.exit(1);
9100
- }
9101
- console.log(chalk31.green("\u2713 GitHub CLI is authenticated"));
9102
- const token = await getToken();
9103
- if (!token) {
9104
- console.log(chalk31.red("\u2717 VM0 not authenticated"));
9105
- console.log();
9106
- console.log("Please authenticate with VM0 first:");
9107
- console.log(` ${chalk31.cyan("vm0 auth login")}`);
9108
- console.log();
9109
- console.log("Then try again:");
9110
- console.log(` ${chalk31.cyan("vm0 setup-github")}`);
9111
- process.exit(1);
9112
- }
9113
- console.log(chalk31.green("\u2713 VM0 authenticated"));
9114
- if (!existsSync10("vm0.yaml")) {
9115
- console.log(chalk31.red("\u2717 vm0.yaml not found"));
9116
- console.log();
9117
- console.log("This command requires a vm0.yaml configuration file.");
9118
- console.log();
9119
- console.log("To create one, run:");
9120
- console.log(` ${chalk31.cyan("vm0 init")}`);
9121
- console.log();
9122
- console.log("Then try again:");
9123
- console.log(` ${chalk31.cyan("vm0 setup-github")}`);
9124
- process.exit(1);
9125
- }
9126
- console.log(chalk31.green("\u2713 vm0.yaml found"));
9127
- return { token, gitRoot };
9128
- }
9129
- function generatePublishYaml(workingDir) {
9130
- const pathPrefix = workingDir ? `${workingDir}/` : "";
9131
- const workingDirYaml = workingDir ? ` working-directory: ${workingDir}
9132
- ` : "";
9133
- return `name: Publish Agent
9134
-
9135
- on:
9136
- push:
9137
- branches: [main]
9138
- paths:
9139
- - '${pathPrefix}vm0.yaml'
9140
- - '${pathPrefix}AGENTS.md'
9141
-
9142
- jobs:
9143
- publish:
9144
- runs-on: ubuntu-latest
9145
- steps:
9146
- - uses: actions/checkout@v4
9147
-
9148
- - name: Publish Agent
9149
- uses: vm0-ai/compose-action@v1
9150
- id: compose
9151
- with:
9152
- vm0-token: \${{ secrets.VM0_TOKEN }}
9153
- ${workingDirYaml}
9154
- - name: Show Results
9155
- run: |
9156
- echo "Agent: \${{ steps.compose.outputs.name }}"
9157
- echo "Compose ID: \${{ steps.compose.outputs.compose-id }}"
9158
- echo "Version: \${{ steps.compose.outputs.version-id }}"
9159
- echo "Action: \${{ steps.compose.outputs.action }}"
9160
- `;
9161
- }
9162
- function generateRunYaml(agentName, secrets, vars) {
9163
- const otherSecrets = secrets.filter((s) => s !== "VM0_TOKEN");
9164
- const secretsLines = otherSecrets.map((s) => ` ${s}=\${{ secrets.${s} }}`).join("\n");
9165
- const varsLines = vars.map((v) => ` ${v}=\${{ vars.${v} }}`).join("\n");
9166
- let yaml = `name: Run Agent
9167
-
9168
- on:
9169
- # Uncomment to enable scheduled runs:
9170
- # schedule:
9171
- # - cron: '0 1 * * *' # Daily at 9:00 AM UTC+8
9172
- workflow_dispatch:
9173
- inputs:
9174
- prompt:
9175
- description: 'Prompt for the agent'
9176
- required: false
9177
- default: 'do the job'
9178
-
9179
- jobs:
9180
- run:
9181
- runs-on: ubuntu-latest
9182
- steps:
9183
- - name: Run Agent
9184
- uses: vm0-ai/run-action@v1
9185
- with:
9186
- agent: ${agentName}
9187
- prompt: \${{ github.event.inputs.prompt || 'do the job' }}
9188
- silent: true
9189
- vm0-token: \${{ secrets.VM0_TOKEN }}`;
9190
- if (secretsLines) {
9191
- yaml += `
9192
- secrets: |
9193
- ${secretsLines}`;
9194
- }
9195
- if (varsLines) {
9196
- yaml += `
9197
- vars: |
9198
- ${varsLines}`;
9199
- }
9200
- yaml += "\n";
9201
- return yaml;
9202
- }
9203
- function extractSecretsAndVars(config) {
9204
- const secrets = /* @__PURE__ */ new Set();
9205
- const vars = /* @__PURE__ */ new Set();
9206
- const refs = extractVariableReferences(config);
9207
- const grouped = groupVariablesBySource(refs);
9208
- for (const ref of grouped.secrets) {
9209
- secrets.add(ref.name);
9210
- }
9211
- for (const ref of grouped.vars) {
9212
- vars.add(ref.name);
9213
- }
9214
- secrets.add("VM0_TOKEN");
9215
- return {
9216
- secrets: Array.from(secrets).sort(),
9217
- vars: Array.from(vars).sort()
9218
- };
9219
- }
9220
- async function promptYesNo(question, defaultYes) {
9221
- const result = await promptConfirm(question, defaultYes);
9222
- return result ?? false;
9223
- }
9224
- function setGitHubSecret(name, value) {
9225
- const result = spawnSync("gh", ["secret", "set", name], {
9226
- input: value,
9227
- stdio: ["pipe", "pipe", "pipe"]
9228
- });
9229
- return result.status === 0;
9230
- }
9231
- function setGitHubVariable(name, value) {
9232
- const result = spawnSync("gh", ["variable", "set", name, "--body", value], {
9233
- stdio: ["pipe", "pipe", "pipe"]
9234
- });
9235
- return result.status === 0;
9236
- }
9237
- async function detectSecretValues(secrets, vars, vm0Token) {
9238
- const secretStatuses = secrets.map((name) => {
9239
- if (name === "VM0_TOKEN") {
9240
- return { name, found: true, source: "vm0 auth", value: vm0Token };
9241
- }
9242
- const envValue = process.env[name];
9243
- if (envValue) {
9244
- return { name, found: true, source: "environment", value: envValue };
9245
- }
9246
- return { name, found: false };
9247
- });
9248
- const varStatuses = vars.map((name) => {
9249
- const envValue = process.env[name];
9250
- if (envValue) {
9251
- return { name, found: true, source: "environment", value: envValue };
9252
- }
9253
- return { name, found: false };
9254
- });
9255
- return { secretStatuses, varStatuses };
9256
- }
9257
- function displaySecretsTable(secretStatuses, varStatuses) {
9258
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
9259
- console.log("\u2502 Detected secrets and variables: \u2502");
9260
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
9261
- if (secretStatuses.length > 0) {
9262
- console.log("\u2502 Secrets: \u2502");
9263
- for (const s of secretStatuses) {
9264
- const status = s.found ? chalk31.green("\u2713") : chalk31.red("\u2717");
9265
- const source = s.found ? `(from ${s.source})` : "not found";
9266
- const paddedName = (s.name + " ").padEnd(23, ".");
9267
- console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
9268
- }
9269
- }
9270
- if (varStatuses.length > 0) {
9271
- console.log("\u2502 Variables: \u2502");
9272
- for (const v of varStatuses) {
9273
- const status = v.found ? chalk31.green("\u2713") : chalk31.red("\u2717");
9274
- const source = v.found ? `(from ${v.source})` : "not found";
9275
- const paddedName = (v.name + " ").padEnd(23, ".");
9276
- console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
9277
- }
9278
- }
9279
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
9280
- }
9281
- function showManualSetupInstructions(secrets, vars) {
9282
- console.log("Skipped automatic setup. Configure secrets manually:");
9283
- console.log();
9284
- console.log(" Step 1: Get your VM0 token");
9285
- console.log(` ${chalk31.cyan("vm0 auth setup-token")}`);
9286
- console.log();
9287
- console.log(" Step 2: Set GitHub secrets");
9288
- for (const s of secrets) {
9289
- console.log(` ${chalk31.cyan(`gh secret set ${s}`)}`);
9290
- }
9291
- if (vars.length > 0) {
9292
- console.log();
9293
- console.log(" Step 3: Set GitHub variables");
9294
- for (const v of vars) {
9295
- console.log(` ${chalk31.cyan(`gh variable set ${v}`)}`);
9296
- }
9297
- }
9298
- }
9299
- function showSuccessMessage() {
9300
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
9301
- console.log("\u2502 \u2713 GitHub Actions setup complete! \u2502");
9302
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
9303
- console.log("\u2502 Workflows created: \u2502");
9304
- console.log("\u2502 \u2022 .github/workflows/publish.yml \u2502");
9305
- console.log("\u2502 \u2022 .github/workflows/run.yml \u2502");
9306
- console.log("\u2502 \u2502");
9307
- console.log("\u2502 Next steps: \u2502");
9308
- console.log("\u2502 1. Commit and push the workflow files \u2502");
9309
- console.log("\u2502 2. Push to main branch to trigger publish \u2502");
9310
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
9311
- }
9312
- function showPartialSuccessMessage(missingSecrets, missingVars) {
9313
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
9314
- console.log("\u2502 \u26A0 Setup partially complete \u2502");
9315
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
9316
- console.log("\u2502 Missing secrets - set them manually: \u2502");
9317
- for (const s of missingSecrets) {
9318
- console.log(`\u2502 gh secret set ${s.padEnd(40)}\u2502`);
9319
- }
9320
- for (const v of missingVars) {
9321
- console.log(`\u2502 gh variable set ${v.padEnd(38)}\u2502`);
9322
- }
9323
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
9324
- }
9325
- function showWorkflowsCreatedMessage() {
9326
- console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
9327
- console.log("\u2502 \u2713 Workflow files created! \u2502");
9328
- console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
9329
- console.log("\u2502 \u2022 .github/workflows/publish.yml \u2502");
9330
- console.log("\u2502 \u2022 .github/workflows/run.yml \u2502");
9331
- console.log("\u2502 \u2502");
9332
- console.log("\u2502 Next steps: \u2502");
9333
- console.log("\u2502 1. Set GitHub secrets (see commands above) \u2502");
9334
- console.log("\u2502 2. Commit and push the workflow files \u2502");
9335
- console.log("\u2502 3. Push to main branch to trigger publish \u2502");
9336
- console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
9337
- }
9338
- var setupGithubCommand = new Command28().name("setup-github").description("Initialize GitHub Actions workflows for agent deployment").option("-f, --force", "Overwrite existing workflow files").option("-y, --yes", "Auto-confirm all prompts").option("--skip-secrets", "Skip automatic secrets/variables setup").action(
9339
- // eslint-disable-next-line complexity -- TODO: refactor complex function
9340
- async (options) => {
9341
- const prereqs = await checkPrerequisites();
9342
- if (!prereqs) {
9343
- process.exit(1);
9344
- }
9345
- const { token: vm0Token, gitRoot } = prereqs;
9346
- const workingDir = getRelativeWorkingDir(gitRoot);
9347
- console.log();
9348
- console.log("Analyzing vm0.yaml...");
9349
- const content = await readFile8("vm0.yaml", "utf8");
9350
- const config = parseYaml5(content);
9351
- const agents = config.agents;
9352
- const agentName = Object.keys(agents)[0];
9353
- console.log(chalk31.green(`\u2713 Agent: ${agentName}`));
9354
- const { secrets, vars } = extractSecretsAndVars(config);
9355
- console.log(
9356
- chalk31.green(
9357
- `\u2713 Found ${secrets.length} secrets, ${vars.length} variables`
9358
- )
9359
- );
9360
- console.log();
9361
- const publishPath = path15.join(gitRoot, ".github/workflows/publish.yml");
9362
- const runPath = path15.join(gitRoot, ".github/workflows/run.yml");
9363
- const displayPublishPath = ".github/workflows/publish.yml";
9364
- const displayRunPath = ".github/workflows/run.yml";
9365
- const existingFiles = [];
9366
- if (existsSync10(publishPath)) existingFiles.push(displayPublishPath);
9367
- if (existsSync10(runPath)) existingFiles.push(displayRunPath);
9368
- if (existingFiles.length > 0 && !options.force) {
9369
- console.log(chalk31.yellow("\u26A0 Existing workflow files detected:"));
9370
- for (const file of existingFiles) {
9371
- console.log(` \u2022 ${file}`);
9372
- }
9373
- console.log();
9374
- if (!options.yes) {
9375
- const overwrite = await promptYesNo(
9376
- "Overwrite existing files?",
9377
- false
9378
- );
9379
- if (!overwrite) {
9380
- console.log();
9381
- console.log("Aborted. To force overwrite, run:");
9382
- console.log(` ${chalk31.cyan("vm0 setup-github --force")}`);
9383
- process.exit(0);
9384
- }
9385
- }
9386
- console.log();
9387
- }
9388
- console.log("Creating workflow files...");
9389
- await mkdir7(path15.join(gitRoot, ".github/workflows"), { recursive: true });
9390
- await writeFile8(publishPath, generatePublishYaml(workingDir));
9391
- const publishStatus = existingFiles.includes(displayPublishPath) ? "Overwrote" : "Created";
9392
- console.log(chalk31.green(`\u2713 ${publishStatus} ${displayPublishPath}`));
9393
- await writeFile8(runPath, generateRunYaml(agentName, secrets, vars));
9394
- const runStatus = existingFiles.includes(displayRunPath) ? "Overwrote" : "Created";
9395
- console.log(chalk31.green(`\u2713 ${runStatus} ${displayRunPath}`));
9396
- console.log();
9397
- if (options.skipSecrets) {
9398
- console.log(chalk31.green("\u2713 Done (secrets setup skipped)"));
9399
- return;
9400
- }
9401
- const { secretStatuses, varStatuses } = await detectSecretValues(
9402
- secrets,
9403
- vars,
9404
- vm0Token
9405
- );
9406
- displaySecretsTable(secretStatuses, varStatuses);
9407
- console.log();
9408
- const hasFoundValues = secretStatuses.some((s) => s.found) || varStatuses.some((v) => v.found);
9409
- if (!hasFoundValues) {
9410
- console.log("No secret/variable values found in environment.");
9411
- console.log();
9412
- showManualSetupInstructions(secrets, vars);
9413
- console.log();
9414
- showWorkflowsCreatedMessage();
9415
- return;
9416
- }
9417
- let shouldSetup = options.yes;
9418
- if (!shouldSetup) {
9419
- shouldSetup = await promptYesNo(
9420
- "Set up GitHub secrets/variables automatically?",
9421
- true
9422
- );
9423
- }
9424
- if (!shouldSetup) {
9425
- console.log();
9426
- showManualSetupInstructions(secrets, vars);
9427
- console.log();
9428
- showWorkflowsCreatedMessage();
9429
- return;
9430
- }
9431
- console.log();
9432
- console.log("Setting secrets...");
9433
- const failedSecrets = [];
9434
- for (const s of secretStatuses) {
9435
- if (s.found && s.value) {
9436
- const success = setGitHubSecret(s.name, s.value);
9437
- if (success) {
9438
- console.log(` ${chalk31.green("\u2713")} ${s.name}`);
9439
- } else {
9440
- console.log(` ${chalk31.red("\u2717")} ${s.name} (failed)`);
9441
- failedSecrets.push(s.name);
9442
- }
9443
- } else {
9444
- console.log(
9445
- ` ${chalk31.yellow("\u26A0")} ${s.name} (skipped - not found)`
9446
- );
9447
- }
9448
- }
9449
- const failedVars = [];
9450
- if (varStatuses.length > 0) {
9451
- console.log();
9452
- console.log("Setting variables...");
9453
- for (const v of varStatuses) {
9454
- if (v.found && v.value) {
9455
- const success = setGitHubVariable(v.name, v.value);
9456
- if (success) {
9457
- console.log(` ${chalk31.green("\u2713")} ${v.name}`);
9458
- } else {
9459
- console.log(` ${chalk31.red("\u2717")} ${v.name} (failed)`);
9460
- failedVars.push(v.name);
9461
- }
9462
- } else {
9463
- console.log(
9464
- ` ${chalk31.yellow("\u26A0")} ${v.name} (skipped - not found)`
9465
- );
9466
- }
9467
- }
9468
- }
9469
- console.log();
9470
- const missingSecrets = [
9471
- ...secretStatuses.filter((s) => !s.found).map((s) => s.name),
9472
- ...failedSecrets
9473
- ];
9474
- const missingVars = [
9475
- ...varStatuses.filter((v) => !v.found).map((v) => v.name),
9476
- ...failedVars
9477
- ];
9478
- if (missingSecrets.length === 0 && missingVars.length === 0) {
9479
- showSuccessMessage();
9480
- } else {
9481
- showPartialSuccessMessage(missingSecrets, missingVars);
9482
- }
9483
- }
9484
- );
9485
-
9486
- // src/commands/schedule/index.ts
9487
- import { Command as Command36 } from "commander";
9488
-
9489
- // src/commands/schedule/init.ts
9490
- import { Command as Command29 } from "commander";
9491
- import chalk32 from "chalk";
9492
- import { existsSync as existsSync12, writeFileSync } from "fs";
9493
- import { stringify as stringifyYaml2 } from "yaml";
9494
-
9495
- // src/lib/domain/schedule-utils.ts
9496
- import { existsSync as existsSync11, readFileSync as readFileSync2 } from "fs";
9497
- import { parse as parseYaml6 } from "yaml";
9498
- var CONFIG_FILE4 = "vm0.yaml";
9499
- var SCHEDULE_FILE = "schedule.yaml";
9500
- function loadAgentName() {
9501
- if (!existsSync11(CONFIG_FILE4)) {
9502
- return { agentName: null };
9503
- }
9504
- try {
9505
- const content = readFileSync2(CONFIG_FILE4, "utf8");
9506
- const config = parseYaml6(content);
9507
- const agentNames = Object.keys(config.agents || {});
9508
- return { agentName: agentNames[0] || null };
9509
- } catch (err) {
9510
- return {
9511
- agentName: null,
9512
- error: err instanceof Error ? err.message : "Failed to parse vm0.yaml"
9513
- };
9514
- }
9515
- }
9516
- function loadScheduleName() {
9517
- if (!existsSync11(SCHEDULE_FILE)) {
9518
- return { scheduleName: null };
9519
- }
9520
- try {
9521
- const content = readFileSync2(SCHEDULE_FILE, "utf8");
9522
- const parsed = parseYaml6(content);
9523
- if (!parsed?.schedules) {
9524
- return {
9525
- scheduleName: null,
9526
- error: "No schedules defined in schedule.yaml"
9527
- };
9528
- }
9529
- const scheduleNames = Object.keys(parsed.schedules);
9530
- return { scheduleName: scheduleNames[0] || null };
9531
- } catch (err) {
9532
- return {
9533
- scheduleName: null,
9534
- error: err instanceof Error ? err.message : "Failed to parse schedule.yaml"
9535
- };
9536
- }
9537
- }
9538
- function formatRelativeTime2(dateStr) {
9539
- if (!dateStr) return "-";
9540
- const date = new Date(dateStr);
9541
- const now = /* @__PURE__ */ new Date();
9542
- const diffMs = date.getTime() - now.getTime();
9543
- const diffAbs = Math.abs(diffMs);
9544
- const minutes = Math.floor(diffAbs / (1e3 * 60));
9545
- const hours = Math.floor(diffAbs / (1e3 * 60 * 60));
9546
- const days = Math.floor(diffAbs / (1e3 * 60 * 60 * 24));
9547
- const isPast = diffMs < 0;
9548
- if (days > 0) {
9549
- return isPast ? `${days}d ago` : `in ${days}d`;
9550
- } else if (hours > 0) {
9551
- return isPast ? `${hours}h ago` : `in ${hours}h`;
9552
- } else if (minutes > 0) {
9553
- return isPast ? `${minutes}m ago` : `in ${minutes}m`;
9554
- } else {
9555
- return isPast ? "just now" : "soon";
9084
+ function formatRelativeTime2(dateStr) {
9085
+ if (!dateStr) return "-";
9086
+ const date = new Date(dateStr);
9087
+ const now = /* @__PURE__ */ new Date();
9088
+ const diffMs = date.getTime() - now.getTime();
9089
+ const diffAbs = Math.abs(diffMs);
9090
+ const minutes = Math.floor(diffAbs / (1e3 * 60));
9091
+ const hours = Math.floor(diffAbs / (1e3 * 60 * 60));
9092
+ const days = Math.floor(diffAbs / (1e3 * 60 * 60 * 24));
9093
+ const isPast = diffMs < 0;
9094
+ if (days > 0) {
9095
+ return isPast ? `${days}d ago` : `in ${days}d`;
9096
+ } else if (hours > 0) {
9097
+ return isPast ? `${hours}h ago` : `in ${hours}h`;
9098
+ } else if (minutes > 0) {
9099
+ return isPast ? `${minutes}m ago` : `in ${minutes}m`;
9100
+ } else {
9101
+ return isPast ? "just now" : "soon";
9556
9102
  }
9557
9103
  }
9558
9104
  function formatDateTime(dateStr) {
@@ -9583,42 +9129,6 @@ function generateCronExpression(frequency, time, day) {
9583
9129
  function detectTimezone() {
9584
9130
  return Intl.DateTimeFormat().resolvedOptions().timeZone;
9585
9131
  }
9586
- function extractVarsAndSecrets() {
9587
- const result = { vars: [], secrets: [] };
9588
- if (!existsSync11(CONFIG_FILE4)) {
9589
- return result;
9590
- }
9591
- try {
9592
- const content = readFileSync2(CONFIG_FILE4, "utf8");
9593
- const config = parseYaml6(content);
9594
- const agents = Object.values(config.agents || {});
9595
- const agent = agents[0];
9596
- if (!agent) {
9597
- return result;
9598
- }
9599
- if (agent.environment) {
9600
- for (const value of Object.values(agent.environment)) {
9601
- const varsMatches = value.matchAll(/\$\{\{\s*vars\.(\w+)\s*\}\}/g);
9602
- for (const match of varsMatches) {
9603
- if (match[1] && !result.vars.includes(match[1])) {
9604
- result.vars.push(match[1]);
9605
- }
9606
- }
9607
- const secretsMatches = value.matchAll(
9608
- /\$\{\{\s*secrets\.(\w+)\s*\}\}/g
9609
- );
9610
- for (const match of secretsMatches) {
9611
- if (match[1] && !result.secrets.includes(match[1])) {
9612
- result.secrets.push(match[1]);
9613
- }
9614
- }
9615
- }
9616
- }
9617
- return result;
9618
- } catch {
9619
- return result;
9620
- }
9621
- }
9622
9132
  function validateTimeFormat(time) {
9623
9133
  const match = time.match(/^(\d{1,2}):(\d{2})$/);
9624
9134
  if (!match) {
@@ -9679,11 +9189,27 @@ function toISODateTime(dateTimeStr) {
9679
9189
  const date = new Date(isoStr);
9680
9190
  return date.toISOString();
9681
9191
  }
9682
- async function resolveScheduleByName(name) {
9192
+ function extractRequiredConfiguration(composeContent) {
9193
+ const result = {
9194
+ secrets: [],
9195
+ vars: [],
9196
+ credentials: []
9197
+ };
9198
+ if (!composeContent) {
9199
+ return result;
9200
+ }
9201
+ const refs = extractVariableReferences(composeContent);
9202
+ const grouped = groupVariablesBySource(refs);
9203
+ result.secrets = grouped.secrets.map((r) => r.name);
9204
+ result.vars = grouped.vars.map((r) => r.name);
9205
+ result.credentials = grouped.credentials.map((r) => r.name);
9206
+ return result;
9207
+ }
9208
+ async function resolveScheduleByAgent(agentName) {
9683
9209
  const { schedules } = await listSchedules();
9684
- const schedule = schedules.find((s) => s.name === name);
9210
+ const schedule = schedules.find((s) => s.composeName === agentName);
9685
9211
  if (!schedule) {
9686
- throw new Error(`Schedule "${name}" not found`);
9212
+ throw new Error(`No schedule found for agent "${agentName}"`);
9687
9213
  }
9688
9214
  return {
9689
9215
  name: schedule.name,
@@ -9692,8 +9218,7 @@ async function resolveScheduleByName(name) {
9692
9218
  };
9693
9219
  }
9694
9220
 
9695
- // src/commands/schedule/init.ts
9696
- var SCHEDULE_FILE2 = "schedule.yaml";
9221
+ // src/commands/schedule/setup.ts
9697
9222
  var FREQUENCY_CHOICES = [
9698
9223
  { title: "Daily", value: "daily", description: "Run every day" },
9699
9224
  {
@@ -9741,281 +9266,12 @@ function parseDayOption(day, frequency) {
9741
9266
  }
9742
9267
  return void 0;
9743
9268
  }
9744
- var initCommand4 = new Command29().name("init").description("Create a schedule.yaml interactively").option("-n, --name <name>", "Schedule name").option("-f, --frequency <type>", "Frequency: daily|weekly|monthly|once").option("-t, --time <HH:MM>", "Time to run (24-hour format)").option("-d, --day <day>", "Day of week (mon-sun) or day of month (1-31)").option("-z, --timezone <tz>", "IANA timezone").option("-p, --prompt <text>", "Prompt to run").option("--no-vars", "Don't include vars from vm0.yaml").option("--force", "Overwrite existing schedule.yaml").action(
9745
- // eslint-disable-next-line complexity -- TODO: refactor complex function
9746
- async (options) => {
9747
- try {
9748
- const { agentName, error } = loadAgentName();
9749
- if (error) {
9750
- console.error(chalk32.red(`\u2717 Invalid vm0.yaml: ${error}`));
9751
- process.exit(1);
9752
- }
9753
- if (!agentName) {
9754
- console.error(chalk32.red("\u2717 No vm0.yaml found"));
9755
- console.error(
9756
- chalk32.dim(" Run this command from an agent directory")
9757
- );
9758
- process.exit(1);
9759
- }
9760
- if (existsSync12(SCHEDULE_FILE2) && !options.force) {
9761
- if (!isInteractive()) {
9762
- console.error(chalk32.red("\u2717 schedule.yaml already exists"));
9763
- console.error(chalk32.dim(" Use --force to overwrite"));
9764
- process.exit(1);
9765
- }
9766
- const overwrite = await promptConfirm(
9767
- "schedule.yaml exists. Overwrite?",
9768
- false
9769
- );
9770
- if (!overwrite) {
9771
- console.log(chalk32.dim("Cancelled"));
9772
- return;
9773
- }
9774
- }
9775
- let scheduleName = options.name;
9776
- if (!scheduleName) {
9777
- if (!isInteractive()) {
9778
- console.error(
9779
- chalk32.red("\u2717 --name is required in non-interactive mode")
9780
- );
9781
- process.exit(1);
9782
- }
9783
- scheduleName = await promptText(
9784
- "Schedule name",
9785
- `${agentName}-schedule`
9786
- );
9787
- if (!scheduleName) {
9788
- console.log(chalk32.dim("Cancelled"));
9789
- return;
9790
- }
9791
- }
9792
- let frequency = options.frequency;
9793
- if (!frequency || !["daily", "weekly", "monthly", "once"].includes(frequency)) {
9794
- if (!isInteractive()) {
9795
- console.error(
9796
- chalk32.red(
9797
- "\u2717 --frequency is required (daily|weekly|monthly|once)"
9798
- )
9799
- );
9800
- process.exit(1);
9801
- }
9802
- frequency = await promptSelect(
9803
- "Schedule frequency",
9804
- FREQUENCY_CHOICES,
9805
- 0
9806
- );
9807
- if (!frequency) {
9808
- console.log(chalk32.dim("Cancelled"));
9809
- return;
9810
- }
9811
- }
9812
- let day;
9813
- if (frequency === "weekly" || frequency === "monthly") {
9814
- if (options.day) {
9815
- day = parseDayOption(options.day, frequency);
9816
- if (day === void 0) {
9817
- console.error(
9818
- chalk32.red(
9819
- `\u2717 Invalid day: ${options.day}. Use mon-sun for weekly or 1-31 for monthly.`
9820
- )
9821
- );
9822
- process.exit(1);
9823
- }
9824
- } else if (isInteractive()) {
9825
- if (frequency === "weekly") {
9826
- day = await promptSelect("Day of week", DAY_OF_WEEK_CHOICES, 0);
9827
- if (day === void 0) {
9828
- console.log(chalk32.dim("Cancelled"));
9829
- return;
9830
- }
9831
- } else {
9832
- const dayStr = await promptText("Day of month (1-31)", "1");
9833
- if (!dayStr) {
9834
- console.log(chalk32.dim("Cancelled"));
9835
- return;
9836
- }
9837
- day = parseInt(dayStr, 10);
9838
- if (isNaN(day) || day < 1 || day > 31) {
9839
- console.error(chalk32.red("\u2717 Day must be between 1 and 31"));
9840
- process.exit(1);
9841
- }
9842
- }
9843
- } else {
9844
- console.error(chalk32.red("\u2717 --day is required for weekly/monthly"));
9845
- process.exit(1);
9846
- }
9847
- }
9848
- let time = options.time;
9849
- let atTime;
9850
- if (frequency === "once") {
9851
- if (!isInteractive()) {
9852
- console.error(
9853
- chalk32.red("\u2717 One-time schedules require interactive mode")
9854
- );
9855
- console.error(
9856
- chalk32.dim(" Use cron frequency for non-interactive mode")
9857
- );
9858
- process.exit(1);
9859
- }
9860
- const tomorrowDate = getTomorrowDateLocal();
9861
- const date = await promptText(
9862
- "Date (YYYY-MM-DD, default tomorrow)",
9863
- tomorrowDate,
9864
- validateDateFormat
9865
- );
9866
- if (!date) {
9867
- console.log(chalk32.dim("Cancelled"));
9868
- return;
9869
- }
9870
- const currentTime = getCurrentTimeLocal();
9871
- time = await promptText(
9872
- "Time (HH:MM)",
9873
- currentTime,
9874
- validateTimeFormat
9875
- );
9876
- if (!time) {
9877
- console.log(chalk32.dim("Cancelled"));
9878
- return;
9879
- }
9880
- const dateStr = `${date} ${time}`;
9881
- atTime = dateStr;
9882
- } else {
9883
- if (!time) {
9884
- if (!isInteractive()) {
9885
- console.error(chalk32.red("\u2717 --time is required (HH:MM format)"));
9886
- process.exit(1);
9887
- }
9888
- time = await promptText(
9889
- "Time (HH:MM)",
9890
- "09:00",
9891
- validateTimeFormat
9892
- );
9893
- if (!time) {
9894
- console.log(chalk32.dim("Cancelled"));
9895
- return;
9896
- }
9897
- } else {
9898
- const validation = validateTimeFormat(time);
9899
- if (validation !== true) {
9900
- console.error(chalk32.red(`\u2717 Invalid time: ${validation}`));
9901
- process.exit(1);
9902
- }
9903
- }
9904
- }
9905
- const detectedTimezone = detectTimezone();
9906
- let timezone = options.timezone;
9907
- if (!timezone) {
9908
- if (isInteractive()) {
9909
- timezone = await promptText("Timezone", detectedTimezone);
9910
- if (!timezone) {
9911
- console.log(chalk32.dim("Cancelled"));
9912
- return;
9913
- }
9914
- } else {
9915
- timezone = detectedTimezone;
9916
- }
9917
- }
9918
- let promptText_ = options.prompt;
9919
- if (!promptText_) {
9920
- if (!isInteractive()) {
9921
- console.error(chalk32.red("\u2717 --prompt is required"));
9922
- process.exit(1);
9923
- }
9924
- promptText_ = await promptText(
9925
- "Prompt to run",
9926
- "let's start working."
9927
- );
9928
- if (!promptText_) {
9929
- console.log(chalk32.dim("Cancelled"));
9930
- return;
9931
- }
9932
- }
9933
- let vars;
9934
- let secrets;
9935
- if (options.vars) {
9936
- const extracted = extractVarsAndSecrets();
9937
- if (extracted.vars.length > 0 || extracted.secrets.length > 0) {
9938
- let includeVars = true;
9939
- if (isInteractive()) {
9940
- const varCount = extracted.vars.length;
9941
- const secretCount = extracted.secrets.length;
9942
- const parts = [];
9943
- if (varCount > 0) parts.push(`${varCount} variable(s)`);
9944
- if (secretCount > 0) parts.push(`${secretCount} secret(s)`);
9945
- const itemList = [
9946
- ...extracted.vars.map((v) => `vars.${v}`),
9947
- ...extracted.secrets.map((s) => `secrets.${s}`)
9948
- ];
9949
- includeVars = await promptConfirm(
9950
- `Include ${parts.join(" and ")} from vm0.yaml? (${itemList.join(", ")})`,
9951
- true
9952
- ) ?? true;
9953
- }
9954
- if (includeVars) {
9955
- if (extracted.vars.length > 0) {
9956
- vars = {};
9957
- for (const v of extracted.vars) {
9958
- vars[v] = `\${${v}}`;
9959
- }
9960
- }
9961
- if (extracted.secrets.length > 0) {
9962
- secrets = {};
9963
- for (const s of extracted.secrets) {
9964
- secrets[s] = `\${${s}}`;
9965
- }
9966
- }
9967
- }
9968
- }
9969
- }
9970
- const scheduleYaml = {
9971
- version: "1.0",
9972
- schedules: {
9973
- [scheduleName]: {
9974
- on: {
9975
- timezone
9976
- },
9977
- run: {
9978
- agent: agentName,
9979
- prompt: promptText_
9980
- }
9981
- }
9982
- }
9983
- };
9984
- if (atTime) {
9985
- scheduleYaml.schedules[scheduleName].on.at = atTime;
9986
- } else if (time && frequency !== "once") {
9987
- scheduleYaml.schedules[scheduleName].on.cron = generateCronExpression(frequency, time, day);
9988
- }
9989
- if (vars && Object.keys(vars).length > 0) {
9990
- scheduleYaml.schedules[scheduleName].run.vars = vars;
9991
- }
9992
- if (secrets && Object.keys(secrets).length > 0) {
9993
- scheduleYaml.schedules[scheduleName].run.secrets = secrets;
9994
- }
9995
- writeFileSync(SCHEDULE_FILE2, stringifyYaml2(scheduleYaml));
9996
- console.log(chalk32.green(`\u2713 Created ${SCHEDULE_FILE2}`));
9997
- console.log(chalk32.dim(" Deploy with: vm0 schedule deploy"));
9998
- } catch (error) {
9999
- console.error(chalk32.red("\u2717 Failed to create schedule.yaml"));
10000
- if (error instanceof Error) {
10001
- console.error(chalk32.dim(` ${error.message}`));
10002
- }
10003
- process.exit(1);
10004
- }
10005
- }
10006
- );
10007
-
10008
- // src/commands/schedule/deploy.ts
10009
- import { Command as Command30 } from "commander";
10010
- import chalk33 from "chalk";
10011
- import { existsSync as existsSync13, readFileSync as readFileSync3 } from "fs";
10012
- import { parse as parseYaml7 } from "yaml";
10013
9269
  function expandEnvVars(value) {
10014
9270
  return value.replace(/\$\{([^}]+)\}/g, (match, varName) => {
10015
9271
  const envValue = process.env[varName];
10016
9272
  if (envValue === void 0) {
10017
9273
  console.warn(
10018
- chalk33.yellow(` Warning: Environment variable ${varName} not set`)
9274
+ chalk31.yellow(` Warning: Environment variable ${varName} not set`)
10019
9275
  );
10020
9276
  return match;
10021
9277
  }
@@ -10044,134 +9300,465 @@ function formatInTimezone(isoDate, timezone) {
10044
9300
  const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
10045
9301
  return `${get("year")}-${get("month")}-${get("day")} ${get("hour")}:${get("minute")}`;
10046
9302
  }
10047
- var deployCommand = new Command30().name("deploy").description("Deploy a schedule from schedule.yaml (create or update)").argument("[file]", "Path to schedule.yaml", "schedule.yaml").action(async (file) => {
9303
+ function parseFrequencyFromCron(cron) {
9304
+ const parts = cron.split(" ");
9305
+ if (parts.length !== 5) return null;
9306
+ const [minute, hour, dayOfMonth, , dayOfWeek] = parts;
9307
+ const time = `${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`;
9308
+ if (dayOfMonth === "*" && dayOfWeek === "*") {
9309
+ return { frequency: "daily", time };
9310
+ } else if (dayOfMonth === "*" && dayOfWeek !== "*") {
9311
+ return { frequency: "weekly", day: parseInt(dayOfWeek, 10), time };
9312
+ } else if (dayOfMonth !== "*" && dayOfWeek === "*") {
9313
+ return { frequency: "monthly", day: parseInt(dayOfMonth, 10), time };
9314
+ }
9315
+ return null;
9316
+ }
9317
+ function collect(value, previous) {
9318
+ return previous.concat([value]);
9319
+ }
9320
+ function parseKeyValuePairs(pairs) {
9321
+ const result = {};
9322
+ for (const pair of pairs) {
9323
+ const eqIndex = pair.indexOf("=");
9324
+ if (eqIndex > 0) {
9325
+ const key = pair.slice(0, eqIndex);
9326
+ const value = pair.slice(eqIndex + 1);
9327
+ result[key] = value;
9328
+ }
9329
+ }
9330
+ return result;
9331
+ }
9332
+ function getExistingDefaults(existingSchedule) {
9333
+ const defaults = {};
9334
+ if (existingSchedule?.cronExpression) {
9335
+ const parsed = parseFrequencyFromCron(existingSchedule.cronExpression);
9336
+ if (parsed) {
9337
+ defaults.frequency = parsed.frequency;
9338
+ defaults.day = parsed.day;
9339
+ defaults.time = parsed.time;
9340
+ }
9341
+ } else if (existingSchedule?.atTime) {
9342
+ defaults.frequency = "once";
9343
+ }
9344
+ return defaults;
9345
+ }
9346
+ async function gatherFrequency(optionFrequency, existingFrequency) {
9347
+ let frequency = optionFrequency;
9348
+ if (frequency && ["daily", "weekly", "monthly", "once"].includes(frequency)) {
9349
+ return frequency;
9350
+ }
9351
+ if (!isInteractive()) {
9352
+ console.error(
9353
+ chalk31.red("\u2717 --frequency is required (daily|weekly|monthly|once)")
9354
+ );
9355
+ process.exit(1);
9356
+ }
9357
+ const defaultIndex = existingFrequency ? FREQUENCY_CHOICES.findIndex((c19) => c19.value === existingFrequency) : 0;
9358
+ frequency = await promptSelect(
9359
+ "Schedule frequency",
9360
+ FREQUENCY_CHOICES,
9361
+ defaultIndex >= 0 ? defaultIndex : 0
9362
+ );
9363
+ return frequency || null;
9364
+ }
9365
+ async function gatherDay(frequency, optionDay, existingDay) {
9366
+ if (frequency !== "weekly" && frequency !== "monthly") {
9367
+ return null;
9368
+ }
9369
+ if (optionDay) {
9370
+ const day2 = parseDayOption(optionDay, frequency);
9371
+ if (day2 === void 0) {
9372
+ console.error(
9373
+ chalk31.red(
9374
+ `\u2717 Invalid day: ${optionDay}. Use mon-sun for weekly or 1-31 for monthly.`
9375
+ )
9376
+ );
9377
+ process.exit(1);
9378
+ }
9379
+ return day2;
9380
+ }
9381
+ if (!isInteractive()) {
9382
+ console.error(chalk31.red("\u2717 --day is required for weekly/monthly"));
9383
+ process.exit(1);
9384
+ }
9385
+ if (frequency === "weekly") {
9386
+ const defaultDayIndex = existingDay !== void 0 ? DAY_OF_WEEK_CHOICES.findIndex((c19) => c19.value === existingDay) : 0;
9387
+ const day2 = await promptSelect(
9388
+ "Day of week",
9389
+ DAY_OF_WEEK_CHOICES,
9390
+ defaultDayIndex >= 0 ? defaultDayIndex : 0
9391
+ );
9392
+ return day2 ?? null;
9393
+ }
9394
+ const dayStr = await promptText(
9395
+ "Day of month (1-31)",
9396
+ existingDay?.toString() || "1"
9397
+ );
9398
+ if (!dayStr) return null;
9399
+ const day = parseInt(dayStr, 10);
9400
+ if (isNaN(day) || day < 1 || day > 31) {
9401
+ console.error(chalk31.red("\u2717 Day must be between 1 and 31"));
9402
+ process.exit(1);
9403
+ }
9404
+ return day;
9405
+ }
9406
+ async function gatherRecurringTime(optionTime, existingTime) {
9407
+ if (optionTime) {
9408
+ const validation = validateTimeFormat(optionTime);
9409
+ if (validation !== true) {
9410
+ console.error(chalk31.red(`\u2717 Invalid time: ${validation}`));
9411
+ process.exit(1);
9412
+ }
9413
+ return optionTime;
9414
+ }
9415
+ if (!isInteractive()) {
9416
+ console.error(chalk31.red("\u2717 --time is required (HH:MM format)"));
9417
+ process.exit(1);
9418
+ }
9419
+ return await promptText(
9420
+ "Time (HH:MM)",
9421
+ existingTime || "09:00",
9422
+ validateTimeFormat
9423
+ );
9424
+ }
9425
+ async function gatherOneTimeSchedule(optionDay, optionTime, existingTime) {
9426
+ if (optionDay && optionTime) {
9427
+ if (!validateDateFormat(optionDay)) {
9428
+ console.error(
9429
+ chalk31.red(
9430
+ `\u2717 Invalid date format: ${optionDay}. Use YYYY-MM-DD format.`
9431
+ )
9432
+ );
9433
+ process.exit(1);
9434
+ }
9435
+ if (!validateTimeFormat(optionTime)) {
9436
+ console.error(
9437
+ chalk31.red(`\u2717 Invalid time format: ${optionTime}. Use HH:MM format.`)
9438
+ );
9439
+ process.exit(1);
9440
+ }
9441
+ return `${optionDay} ${optionTime}`;
9442
+ }
9443
+ if (!isInteractive()) {
9444
+ console.error(chalk31.red("\u2717 One-time schedules require interactive mode"));
9445
+ console.error(
9446
+ chalk31.dim(" Or provide --day (YYYY-MM-DD) and --time (HH:MM) flags")
9447
+ );
9448
+ process.exit(1);
9449
+ }
9450
+ const tomorrowDate = getTomorrowDateLocal();
9451
+ const date = await promptText(
9452
+ "Date (YYYY-MM-DD, default tomorrow)",
9453
+ tomorrowDate,
9454
+ validateDateFormat
9455
+ );
9456
+ if (!date) return null;
9457
+ const currentTime = getCurrentTimeLocal();
9458
+ const time = await promptText(
9459
+ "Time (HH:MM)",
9460
+ existingTime || currentTime,
9461
+ validateTimeFormat
9462
+ );
9463
+ if (!time) return null;
9464
+ return `${date} ${time}`;
9465
+ }
9466
+ async function gatherTimezone(optionTimezone, existingTimezone) {
9467
+ if (optionTimezone) return optionTimezone;
9468
+ const detectedTimezone = detectTimezone();
9469
+ if (!isInteractive()) {
9470
+ return detectedTimezone;
9471
+ }
9472
+ return await promptText("Timezone", existingTimezone || detectedTimezone);
9473
+ }
9474
+ async function gatherPromptText(optionPrompt, existingPrompt) {
9475
+ if (optionPrompt) return optionPrompt;
9476
+ if (!isInteractive()) {
9477
+ console.error(chalk31.red("\u2717 --prompt is required"));
9478
+ process.exit(1);
9479
+ }
9480
+ return await promptText(
9481
+ "Prompt to run",
9482
+ existingPrompt || "let's start working."
9483
+ );
9484
+ }
9485
+ async function gatherVars(optionVars, existingVars) {
9486
+ if (optionVars.length > 0) {
9487
+ return parseKeyValuePairs(optionVars);
9488
+ }
9489
+ if (isInteractive() && existingVars) {
9490
+ const keepVars = await promptConfirm(
9491
+ `Keep existing variables? (${Object.keys(existingVars).join(", ")})`,
9492
+ true
9493
+ );
9494
+ if (keepVars) {
9495
+ return existingVars;
9496
+ }
9497
+ }
9498
+ return void 0;
9499
+ }
9500
+ async function gatherSecrets(optionSecrets, existingSecretNames) {
9501
+ if (optionSecrets.length > 0) {
9502
+ return parseKeyValuePairs(optionSecrets);
9503
+ }
9504
+ if (isInteractive() && existingSecretNames && existingSecretNames.length > 0) {
9505
+ const keepSecrets = await promptConfirm(
9506
+ `Keep existing secrets? (${existingSecretNames.join(", ")})`,
9507
+ true
9508
+ );
9509
+ if (!keepSecrets) {
9510
+ console.log(
9511
+ chalk31.dim(" Note: You'll need to provide new secret values")
9512
+ );
9513
+ }
9514
+ }
9515
+ return void 0;
9516
+ }
9517
+ async function gatherMissingConfiguration(required, providedSecrets, providedVars, existingSecretNames) {
9518
+ const secrets = { ...providedSecrets };
9519
+ const vars = { ...providedVars };
9520
+ const providedSecretNames = Object.keys(providedSecrets);
9521
+ const existingNames = existingSecretNames ?? [];
9522
+ const missingSecrets = required.secrets.filter(
9523
+ (name) => !providedSecretNames.includes(name) && !existingNames.includes(name)
9524
+ );
9525
+ const providedVarNames = Object.keys(providedVars);
9526
+ const missingVars = required.vars.filter(
9527
+ (name) => !providedVarNames.includes(name)
9528
+ );
9529
+ if (missingSecrets.length === 0 && missingVars.length === 0) {
9530
+ return { secrets, vars };
9531
+ }
9532
+ if (!isInteractive()) {
9533
+ return { secrets, vars };
9534
+ }
9535
+ if (missingSecrets.length > 0 || missingVars.length > 0) {
9536
+ console.log(chalk31.yellow("\nAgent requires the following configuration:"));
9537
+ if (missingSecrets.length > 0) {
9538
+ console.log(chalk31.dim(" Secrets:"));
9539
+ for (const name of missingSecrets) {
9540
+ console.log(chalk31.dim(` ${name}`));
9541
+ }
9542
+ }
9543
+ if (missingVars.length > 0) {
9544
+ console.log(chalk31.dim(" Vars:"));
9545
+ for (const name of missingVars) {
9546
+ console.log(chalk31.dim(` ${name}`));
9547
+ }
9548
+ }
9549
+ console.log("");
9550
+ }
9551
+ for (const name of missingSecrets) {
9552
+ const value = await promptPassword(
9553
+ `Enter value for secret ${chalk31.cyan(name)}`
9554
+ );
9555
+ if (value) {
9556
+ secrets[name] = value;
9557
+ }
9558
+ }
9559
+ for (const name of missingVars) {
9560
+ const value = await promptText(
9561
+ `Enter value for var ${chalk31.cyan(name)}`,
9562
+ ""
9563
+ );
9564
+ if (value) {
9565
+ vars[name] = value;
9566
+ }
9567
+ }
9568
+ return { secrets, vars };
9569
+ }
9570
+ async function resolveAgent(agentName) {
9571
+ const compose = await getComposeByName(agentName);
9572
+ if (!compose) {
9573
+ console.error(chalk31.red(`\u2717 Agent not found: ${agentName}`));
9574
+ console.error(chalk31.dim(" Make sure the agent is composed first"));
9575
+ process.exit(1);
9576
+ }
9577
+ return {
9578
+ composeId: compose.id,
9579
+ scheduleName: `${agentName}-schedule`,
9580
+ composeContent: compose.content
9581
+ };
9582
+ }
9583
+ async function gatherTiming(frequency, options, defaults) {
9584
+ if (frequency === "once") {
9585
+ const result = await gatherOneTimeSchedule(
9586
+ options.day,
9587
+ options.time,
9588
+ defaults.time
9589
+ );
9590
+ if (!result) return null;
9591
+ return { day: void 0, time: void 0, atTime: result };
9592
+ }
9593
+ const day = await gatherDay(frequency, options.day, defaults.day) ?? void 0;
9594
+ if (day === null && (frequency === "weekly" || frequency === "monthly")) {
9595
+ return null;
9596
+ }
9597
+ const time = await gatherRecurringTime(options.time, defaults.time);
9598
+ if (!time) return null;
9599
+ return { day, time, atTime: void 0 };
9600
+ }
9601
+ async function findExistingSchedule(agentName) {
9602
+ const { schedules } = await listSchedules();
9603
+ return schedules.find((s) => s.composeName === agentName);
9604
+ }
9605
+ async function buildAndDeploy(params) {
9606
+ let cronExpression;
9607
+ let atTimeISO;
9608
+ if (params.atTime) {
9609
+ atTimeISO = toISODateTime(params.atTime);
9610
+ } else if (params.time && params.frequency !== "once") {
9611
+ cronExpression = generateCronExpression(
9612
+ params.frequency,
9613
+ params.time,
9614
+ params.day
9615
+ );
9616
+ }
9617
+ const expandedVars = expandEnvVarsInObject(params.vars);
9618
+ const expandedSecrets = expandEnvVarsInObject(params.secrets);
9619
+ console.log(
9620
+ `
9621
+ Deploying schedule for agent ${chalk31.cyan(params.agentName)}...`
9622
+ );
9623
+ const deployResult = await deploySchedule({
9624
+ name: params.scheduleName,
9625
+ composeId: params.composeId,
9626
+ cronExpression,
9627
+ atTime: atTimeISO,
9628
+ timezone: params.timezone,
9629
+ prompt: params.prompt,
9630
+ vars: expandedVars,
9631
+ secrets: expandedSecrets,
9632
+ artifactName: params.artifactName
9633
+ });
9634
+ displayDeployResult(params.agentName, deployResult);
9635
+ }
9636
+ function handleSetupError(error) {
9637
+ console.error(chalk31.red("\u2717 Failed to setup schedule"));
9638
+ if (error instanceof Error) {
9639
+ if (error.message.includes("Not authenticated")) {
9640
+ console.error(chalk31.dim(" Run: vm0 auth login"));
9641
+ } else {
9642
+ console.error(chalk31.dim(` ${error.message}`));
9643
+ }
9644
+ }
9645
+ process.exit(1);
9646
+ }
9647
+ function displayDeployResult(agentName, deployResult) {
9648
+ if (deployResult.created) {
9649
+ console.log(
9650
+ chalk31.green(`\u2713 Created schedule for agent ${chalk31.cyan(agentName)}`)
9651
+ );
9652
+ } else {
9653
+ console.log(
9654
+ chalk31.green(`\u2713 Updated schedule for agent ${chalk31.cyan(agentName)}`)
9655
+ );
9656
+ }
9657
+ console.log(chalk31.dim(` Timezone: ${deployResult.schedule.timezone}`));
9658
+ if (deployResult.schedule.cronExpression) {
9659
+ console.log(chalk31.dim(` Cron: ${deployResult.schedule.cronExpression}`));
9660
+ if (deployResult.schedule.nextRunAt) {
9661
+ const nextRun = formatInTimezone(
9662
+ deployResult.schedule.nextRunAt,
9663
+ deployResult.schedule.timezone
9664
+ );
9665
+ console.log(chalk31.dim(` Next run: ${nextRun}`));
9666
+ }
9667
+ } else if (deployResult.schedule.atTime) {
9668
+ const atTimeFormatted = formatInTimezone(
9669
+ deployResult.schedule.atTime,
9670
+ deployResult.schedule.timezone
9671
+ );
9672
+ console.log(chalk31.dim(` At: ${atTimeFormatted}`));
9673
+ }
9674
+ }
9675
+ var setupCommand = new Command28().name("setup").description("Create or edit a schedule for an agent").argument("<agent-name>", "Agent name to configure schedule for").option("-f, --frequency <type>", "Frequency: daily|weekly|monthly|once").option("-t, --time <HH:MM>", "Time to run (24-hour format)").option("-d, --day <day>", "Day of week (mon-sun) or day of month (1-31)").option("-z, --timezone <tz>", "IANA timezone").option("-p, --prompt <text>", "Prompt to run").option("--var <name=value>", "Variable (can be repeated)", collect, []).option("--secret <name=value>", "Secret (can be repeated)", collect, []).option("--artifact-name <name>", "Artifact name", "artifact").action(async (agentName, options) => {
10048
9676
  try {
10049
- if (!existsSync13(file)) {
10050
- console.error(chalk33.red(`\u2717 File not found: ${file}`));
10051
- console.error(chalk33.dim(" Create a schedule.yaml file first"));
10052
- process.exit(1);
10053
- }
10054
- const content = readFileSync3(file, "utf-8");
10055
- let parsed;
10056
- try {
10057
- parsed = parseYaml7(content);
10058
- } catch (err) {
10059
- console.error(chalk33.red("\u2717 Invalid YAML syntax"));
10060
- if (err instanceof Error) {
10061
- console.error(chalk33.dim(` ${err.message}`));
10062
- }
10063
- process.exit(1);
10064
- }
10065
- const result = scheduleYamlSchema.safeParse(parsed);
10066
- if (!result.success) {
10067
- console.error(chalk33.red("\u2717 Invalid schedule.yaml format"));
10068
- for (const issue of result.error.issues) {
10069
- console.error(
10070
- chalk33.dim(` ${issue.path.join(".")}: ${issue.message}`)
10071
- );
10072
- }
10073
- process.exit(1);
9677
+ const { composeId, scheduleName, composeContent } = await resolveAgent(agentName);
9678
+ const requiredConfig = extractRequiredConfiguration(composeContent);
9679
+ const existingSchedule = await findExistingSchedule(agentName);
9680
+ console.log(
9681
+ chalk31.dim(
9682
+ existingSchedule ? `Editing existing schedule for agent ${agentName}` : `Creating new schedule for agent ${agentName}`
9683
+ )
9684
+ );
9685
+ const defaults = getExistingDefaults(existingSchedule);
9686
+ const frequency = await gatherFrequency(
9687
+ options.frequency,
9688
+ defaults.frequency
9689
+ );
9690
+ if (!frequency) {
9691
+ console.log(chalk31.dim("Cancelled"));
9692
+ return;
10074
9693
  }
10075
- const scheduleYaml = result.data;
10076
- const scheduleEntries = Object.entries(scheduleYaml.schedules);
10077
- if (scheduleEntries.length === 0) {
10078
- console.error(chalk33.red("\u2717 No schedules defined in file"));
10079
- process.exit(1);
9694
+ const timing = await gatherTiming(frequency, options, defaults);
9695
+ if (!timing) {
9696
+ console.log(chalk31.dim("Cancelled"));
9697
+ return;
10080
9698
  }
10081
- if (scheduleEntries.length > 1) {
10082
- console.error(
10083
- chalk33.red("\u2717 Multiple schedules per file not supported yet")
10084
- );
10085
- console.error(chalk33.dim(" Please use one schedule per file"));
10086
- process.exit(1);
9699
+ const { day, time, atTime } = timing;
9700
+ const timezone = await gatherTimezone(
9701
+ options.timezone,
9702
+ existingSchedule?.timezone
9703
+ );
9704
+ if (!timezone) {
9705
+ console.log(chalk31.dim("Cancelled"));
9706
+ return;
10087
9707
  }
10088
- const [scheduleName, schedule] = scheduleEntries[0];
10089
- console.log(`Deploying schedule ${chalk33.cyan(scheduleName)}...`);
10090
- const agentRef = schedule.run.agent;
10091
- const namePart = agentRef.includes("/") ? agentRef.split("/").pop() : agentRef;
10092
- const agentName = namePart.includes(":") ? namePart.split(":")[0] : namePart;
10093
- const compose = await getComposeByName(agentName);
10094
- if (!compose) {
10095
- console.error(chalk33.red(`\u2717 Agent not found: ${agentRef}`));
10096
- console.error(chalk33.dim(" Make sure the agent is pushed first"));
10097
- process.exit(1);
9708
+ const promptText_ = await gatherPromptText(
9709
+ options.prompt,
9710
+ existingSchedule?.prompt
9711
+ );
9712
+ if (!promptText_) {
9713
+ console.log(chalk31.dim("Cancelled"));
9714
+ return;
10098
9715
  }
10099
- const composeId = compose.id;
10100
- const expandedVars = expandEnvVarsInObject(schedule.run.vars);
10101
- const expandedSecrets = expandEnvVarsInObject(schedule.run.secrets);
10102
- const atTime = schedule.on.at ? toISODateTime(schedule.on.at) : void 0;
10103
- const body = {
10104
- name: scheduleName,
9716
+ const initialVars = await gatherVars(
9717
+ options.var || [],
9718
+ existingSchedule?.vars
9719
+ );
9720
+ const initialSecrets = await gatherSecrets(
9721
+ options.secret || [],
9722
+ existingSchedule?.secretNames
9723
+ );
9724
+ const { secrets, vars } = await gatherMissingConfiguration(
9725
+ requiredConfig,
9726
+ initialSecrets ?? {},
9727
+ initialVars ?? {},
9728
+ existingSchedule?.secretNames
9729
+ );
9730
+ await buildAndDeploy({
9731
+ scheduleName,
10105
9732
  composeId,
10106
- cronExpression: schedule.on.cron,
9733
+ agentName,
9734
+ frequency,
9735
+ time,
9736
+ day,
10107
9737
  atTime,
10108
- timezone: schedule.on.timezone || "UTC",
10109
- prompt: schedule.run.prompt,
10110
- vars: expandedVars,
10111
- secrets: expandedSecrets,
10112
- artifactName: schedule.run.artifactName,
10113
- artifactVersion: schedule.run.artifactVersion,
10114
- volumeVersions: schedule.run.volumeVersions
10115
- };
10116
- const deployResult = await deploySchedule(body);
10117
- if (deployResult.created) {
10118
- console.log(
10119
- chalk33.green(`\u2713 Created schedule ${chalk33.cyan(scheduleName)}`)
10120
- );
10121
- } else {
10122
- console.log(
10123
- chalk33.green(`\u2713 Updated schedule ${chalk33.cyan(scheduleName)}`)
10124
- );
10125
- }
10126
- console.log(chalk33.dim(` Timezone: ${deployResult.schedule.timezone}`));
10127
- if (deployResult.schedule.cronExpression) {
10128
- console.log(
10129
- chalk33.dim(` Cron: ${deployResult.schedule.cronExpression}`)
10130
- );
10131
- if (deployResult.schedule.nextRunAt) {
10132
- const nextRun = formatInTimezone(
10133
- deployResult.schedule.nextRunAt,
10134
- deployResult.schedule.timezone
10135
- );
10136
- console.log(chalk33.dim(` Next run: ${nextRun}`));
10137
- }
10138
- } else if (deployResult.schedule.atTime) {
10139
- const atTime2 = formatInTimezone(
10140
- deployResult.schedule.atTime,
10141
- deployResult.schedule.timezone
10142
- );
10143
- console.log(chalk33.dim(` At: ${atTime2}`));
10144
- }
9738
+ timezone,
9739
+ prompt: promptText_,
9740
+ vars: Object.keys(vars).length > 0 ? vars : void 0,
9741
+ secrets: Object.keys(secrets).length > 0 ? secrets : void 0,
9742
+ artifactName: options.artifactName
9743
+ });
10145
9744
  } catch (error) {
10146
- console.error(chalk33.red("\u2717 Failed to deploy schedule"));
10147
- if (error instanceof Error) {
10148
- if (error.message.includes("Not authenticated")) {
10149
- console.error(chalk33.dim(" Run: vm0 auth login"));
10150
- } else {
10151
- console.error(chalk33.dim(` ${error.message}`));
10152
- }
10153
- }
10154
- process.exit(1);
9745
+ handleSetupError(error);
10155
9746
  }
10156
9747
  });
10157
9748
 
10158
9749
  // src/commands/schedule/list.ts
10159
- import { Command as Command31 } from "commander";
10160
- import chalk34 from "chalk";
10161
- var listCommand4 = new Command31().name("list").alias("ls").description("List all schedules").action(async () => {
9750
+ import { Command as Command29 } from "commander";
9751
+ import chalk32 from "chalk";
9752
+ var listCommand4 = new Command29().name("list").alias("ls").description("List all schedules").action(async () => {
10162
9753
  try {
10163
9754
  const result = await listSchedules();
10164
9755
  if (result.schedules.length === 0) {
10165
- console.log(chalk34.dim("No schedules found"));
9756
+ console.log(chalk32.dim("No schedules found"));
10166
9757
  console.log(
10167
- chalk34.dim(" Create one with: vm0 schedule deploy schedule.yaml")
9758
+ chalk32.dim(" Create one with: vm0 schedule setup <agent-name>")
10168
9759
  );
10169
9760
  return;
10170
9761
  }
10171
- const nameWidth = Math.max(
10172
- 4,
10173
- ...result.schedules.map((s) => s.name.length)
10174
- );
10175
9762
  const agentWidth = Math.max(
10176
9763
  5,
10177
9764
  ...result.schedules.map((s) => s.composeName.length)
@@ -10183,19 +9770,17 @@ var listCommand4 = new Command31().name("list").alias("ls").description("List al
10183
9770
  )
10184
9771
  );
10185
9772
  const header = [
10186
- "NAME".padEnd(nameWidth),
10187
9773
  "AGENT".padEnd(agentWidth),
10188
9774
  "TRIGGER".padEnd(triggerWidth),
10189
9775
  "STATUS".padEnd(8),
10190
9776
  "NEXT RUN"
10191
9777
  ].join(" ");
10192
- console.log(chalk34.dim(header));
9778
+ console.log(chalk32.dim(header));
10193
9779
  for (const schedule of result.schedules) {
10194
9780
  const trigger = schedule.cronExpression ? `${schedule.cronExpression} (${schedule.timezone})` : schedule.atTime || "-";
10195
- const status = schedule.enabled ? chalk34.green("enabled") : chalk34.yellow("disabled");
9781
+ const status = schedule.enabled ? chalk32.green("enabled") : chalk32.yellow("disabled");
10196
9782
  const nextRun = schedule.enabled ? formatRelativeTime2(schedule.nextRunAt) : "-";
10197
9783
  const row = [
10198
- schedule.name.padEnd(nameWidth),
10199
9784
  schedule.composeName.padEnd(agentWidth),
10200
9785
  trigger.padEnd(triggerWidth),
10201
9786
  status.padEnd(8 + (schedule.enabled ? 0 : 2)),
@@ -10205,12 +9790,12 @@ var listCommand4 = new Command31().name("list").alias("ls").description("List al
10205
9790
  console.log(row);
10206
9791
  }
10207
9792
  } catch (error) {
10208
- console.error(chalk34.red("\u2717 Failed to list schedules"));
9793
+ console.error(chalk32.red("\u2717 Failed to list schedules"));
10209
9794
  if (error instanceof Error) {
10210
9795
  if (error.message.includes("Not authenticated")) {
10211
- console.error(chalk34.dim(" Run: vm0 auth login"));
9796
+ console.error(chalk32.dim(" Run: vm0 auth login"));
10212
9797
  } else {
10213
- console.error(chalk34.dim(` ${error.message}`));
9798
+ console.error(chalk32.dim(` ${error.message}`));
10214
9799
  }
10215
9800
  }
10216
9801
  process.exit(1);
@@ -10218,213 +9803,181 @@ var listCommand4 = new Command31().name("list").alias("ls").description("List al
10218
9803
  });
10219
9804
 
10220
9805
  // src/commands/schedule/status.ts
10221
- import { Command as Command32 } from "commander";
10222
- import chalk35 from "chalk";
9806
+ import { Command as Command30 } from "commander";
9807
+ import chalk33 from "chalk";
10223
9808
  function formatDateTimeStyled(dateStr) {
10224
- if (!dateStr) return chalk35.dim("-");
9809
+ if (!dateStr) return chalk33.dim("-");
10225
9810
  const formatted = formatDateTime(dateStr);
10226
- return formatted.replace(/\(([^)]+)\)$/, chalk35.dim("($1)"));
9811
+ return formatted.replace(/\(([^)]+)\)$/, chalk33.dim("($1)"));
10227
9812
  }
10228
9813
  function formatTrigger(schedule) {
10229
9814
  if (schedule.cronExpression) {
10230
9815
  return schedule.cronExpression;
10231
9816
  }
10232
9817
  if (schedule.atTime) {
10233
- return `${schedule.atTime} ${chalk35.dim("(one-time)")}`;
9818
+ return `${schedule.atTime} ${chalk33.dim("(one-time)")}`;
10234
9819
  }
10235
- return chalk35.dim("-");
9820
+ return chalk33.dim("-");
10236
9821
  }
10237
9822
  function formatRunStatus(status) {
10238
9823
  switch (status) {
10239
9824
  case "completed":
10240
- return chalk35.green(status);
9825
+ return chalk33.green(status);
10241
9826
  case "failed":
10242
9827
  case "timeout":
10243
- return chalk35.red(status);
9828
+ return chalk33.red(status);
10244
9829
  case "running":
10245
- return chalk35.blue(status);
9830
+ return chalk33.blue(status);
10246
9831
  case "pending":
10247
- return chalk35.yellow(status);
9832
+ return chalk33.yellow(status);
10248
9833
  default:
10249
9834
  return status;
10250
9835
  }
10251
9836
  }
10252
- var statusCommand4 = new Command32().name("status").description("Show detailed status of a schedule").argument(
10253
- "[name]",
10254
- "Schedule name (auto-detected from schedule.yaml if omitted)"
10255
- ).option(
10256
- "-l, --limit <number>",
10257
- "Number of recent runs to show (0 to hide)",
10258
- "5"
10259
- ).action(async (nameArg, options) => {
10260
- try {
10261
- let name = nameArg;
10262
- if (!name) {
10263
- const scheduleResult = loadScheduleName();
10264
- if (scheduleResult.error) {
10265
- console.error(chalk35.red(`\u2717 ${scheduleResult.error}`));
10266
- process.exit(1);
10267
- }
10268
- if (!scheduleResult.scheduleName) {
10269
- console.error(chalk35.red("\u2717 Schedule name required"));
10270
- console.error(
10271
- chalk35.dim(
10272
- " Provide name or run from directory with schedule.yaml"
10273
- )
10274
- );
10275
- process.exit(1);
10276
- }
10277
- name = scheduleResult.scheduleName;
10278
- }
10279
- const resolved = await resolveScheduleByName(name);
10280
- const composeId = resolved.composeId;
10281
- const schedule = await getScheduleByName({ name, composeId });
10282
- console.log();
10283
- console.log(`Schedule: ${chalk35.cyan(schedule.name)}`);
10284
- console.log(chalk35.dim("\u2501".repeat(50)));
10285
- const statusText = schedule.enabled ? chalk35.green("enabled") : chalk35.yellow("disabled");
10286
- console.log(`${"Status:".padEnd(16)}${statusText}`);
9837
+ function printRunConfiguration(schedule) {
9838
+ const statusText = schedule.enabled ? chalk33.green("enabled") : chalk33.yellow("disabled");
9839
+ console.log(`${"Status:".padEnd(16)}${statusText}`);
9840
+ console.log(
9841
+ `${"Agent:".padEnd(16)}${schedule.composeName} ${chalk33.dim(`(${schedule.scopeSlug})`)}`
9842
+ );
9843
+ const promptPreview = schedule.prompt.length > 60 ? schedule.prompt.slice(0, 57) + "..." : schedule.prompt;
9844
+ console.log(`${"Prompt:".padEnd(16)}${chalk33.dim(promptPreview)}`);
9845
+ if (schedule.vars && Object.keys(schedule.vars).length > 0) {
10287
9846
  console.log(
10288
- `${"Agent:".padEnd(16)}${schedule.composeName} ${chalk35.dim(`(${schedule.scopeSlug})`)}`
9847
+ `${"Variables:".padEnd(16)}${Object.keys(schedule.vars).join(", ")}`
10289
9848
  );
10290
- const promptPreview = schedule.prompt.length > 60 ? schedule.prompt.slice(0, 57) + "..." : schedule.prompt;
10291
- console.log(`${"Prompt:".padEnd(16)}${chalk35.dim(promptPreview)}`);
10292
- if (schedule.vars && Object.keys(schedule.vars).length > 0) {
10293
- console.log(
10294
- `${"Variables:".padEnd(16)}${Object.keys(schedule.vars).join(", ")}`
10295
- );
10296
- }
10297
- if (schedule.secretNames && schedule.secretNames.length > 0) {
10298
- console.log(
10299
- `${"Secrets:".padEnd(16)}${schedule.secretNames.join(", ")}`
10300
- );
10301
- }
10302
- if (schedule.artifactName) {
10303
- const artifactInfo = schedule.artifactVersion ? `${schedule.artifactName}:${schedule.artifactVersion}` : schedule.artifactName;
10304
- console.log(`${"Artifact:".padEnd(16)}${artifactInfo}`);
10305
- }
10306
- if (schedule.volumeVersions && Object.keys(schedule.volumeVersions).length > 0) {
9849
+ }
9850
+ if (schedule.secretNames && schedule.secretNames.length > 0) {
9851
+ console.log(`${"Secrets:".padEnd(16)}${schedule.secretNames.join(", ")}`);
9852
+ }
9853
+ if (schedule.artifactName) {
9854
+ const artifactInfo = schedule.artifactVersion ? `${schedule.artifactName}:${schedule.artifactVersion}` : schedule.artifactName;
9855
+ console.log(`${"Artifact:".padEnd(16)}${artifactInfo}`);
9856
+ }
9857
+ if (schedule.volumeVersions && Object.keys(schedule.volumeVersions).length > 0) {
9858
+ console.log(
9859
+ `${"Volumes:".padEnd(16)}${Object.keys(schedule.volumeVersions).join(", ")}`
9860
+ );
9861
+ }
9862
+ }
9863
+ function printTimeSchedule(schedule) {
9864
+ console.log();
9865
+ console.log(`${"Trigger:".padEnd(16)}${formatTrigger(schedule)}`);
9866
+ console.log(`${"Timezone:".padEnd(16)}${detectTimezone()}`);
9867
+ if (schedule.enabled) {
9868
+ console.log(
9869
+ `${"Next Run:".padEnd(16)}${formatDateTimeStyled(schedule.nextRunAt)}`
9870
+ );
9871
+ }
9872
+ }
9873
+ async function printRecentRuns(name, composeId, limit) {
9874
+ if (limit <= 0) return;
9875
+ try {
9876
+ const { runs } = await listScheduleRuns({ name, composeId, limit });
9877
+ if (runs.length > 0) {
9878
+ console.log();
9879
+ console.log("Recent Runs:");
10307
9880
  console.log(
10308
- `${"Volumes:".padEnd(16)}${Object.keys(schedule.volumeVersions).join(", ")}`
9881
+ chalk33.dim("RUN ID STATUS CREATED")
10309
9882
  );
9883
+ for (const run of runs) {
9884
+ const id = run.id;
9885
+ const status = formatRunStatus(run.status).padEnd(10);
9886
+ const created = formatDateTimeStyled(run.createdAt);
9887
+ console.log(`${id} ${status} ${created}`);
9888
+ }
10310
9889
  }
9890
+ } catch {
10311
9891
  console.log();
10312
- console.log(`${"Trigger:".padEnd(16)}${formatTrigger(schedule)}`);
10313
- console.log(`${"Timezone:".padEnd(16)}${detectTimezone()}`);
10314
- if (schedule.enabled) {
10315
- console.log(
10316
- `${"Next Run:".padEnd(16)}${formatDateTimeStyled(schedule.nextRunAt)}`
10317
- );
9892
+ console.log(chalk33.dim("Recent Runs: (unable to fetch)"));
9893
+ }
9894
+ }
9895
+ function handleStatusError(error, agentName) {
9896
+ console.error(chalk33.red("\u2717 Failed to get schedule status"));
9897
+ if (error instanceof Error) {
9898
+ if (error.message.includes("Not authenticated")) {
9899
+ console.error(chalk33.dim(" Run: vm0 auth login"));
9900
+ } else if (error.message.includes("not found") || error.message.includes("Not found") || error.message.includes("No schedule found")) {
9901
+ console.error(chalk33.dim(` No schedule found for agent "${agentName}"`));
9902
+ console.error(chalk33.dim(" Run: vm0 schedule list"));
9903
+ } else {
9904
+ console.error(chalk33.dim(` ${error.message}`));
10318
9905
  }
9906
+ }
9907
+ process.exit(1);
9908
+ }
9909
+ var statusCommand5 = new Command30().name("status").description("Show detailed status of a schedule").argument("<agent-name>", "Agent name").option(
9910
+ "-l, --limit <number>",
9911
+ "Number of recent runs to show (0 to hide)",
9912
+ "5"
9913
+ ).action(async (agentName, options) => {
9914
+ try {
9915
+ const resolved = await resolveScheduleByAgent(agentName);
9916
+ const { name, composeId } = resolved;
9917
+ const schedule = await getScheduleByName({ name, composeId });
9918
+ console.log();
9919
+ console.log(`Schedule for agent: ${chalk33.cyan(agentName)}`);
9920
+ console.log(chalk33.dim("\u2501".repeat(50)));
9921
+ printRunConfiguration(schedule);
9922
+ printTimeSchedule(schedule);
10319
9923
  const limit = Math.min(
10320
9924
  Math.max(0, parseInt(options.limit, 10) || 5),
10321
9925
  100
10322
9926
  );
10323
- if (limit > 0) {
10324
- try {
10325
- const { runs } = await listScheduleRuns({
10326
- name,
10327
- composeId,
10328
- limit
10329
- });
10330
- if (runs.length > 0) {
10331
- console.log();
10332
- console.log("Recent Runs:");
10333
- console.log(
10334
- chalk35.dim(
10335
- "RUN ID STATUS CREATED"
10336
- )
10337
- );
10338
- for (const run of runs) {
10339
- const id = run.id;
10340
- const status = formatRunStatus(run.status).padEnd(10);
10341
- const created = formatDateTimeStyled(run.createdAt);
10342
- console.log(`${id} ${status} ${created}`);
10343
- }
10344
- }
10345
- } catch {
10346
- console.log();
10347
- console.log(chalk35.dim("Recent Runs: (unable to fetch)"));
10348
- }
10349
- }
9927
+ await printRecentRuns(name, composeId, limit);
10350
9928
  console.log();
10351
9929
  } catch (error) {
10352
- console.error(chalk35.red("\u2717 Failed to get schedule status"));
10353
- if (error instanceof Error) {
10354
- if (error.message.includes("Not authenticated")) {
10355
- console.error(chalk35.dim(" Run: vm0 auth login"));
10356
- } else if (error.message.includes("not found") || error.message.includes("Not found")) {
10357
- console.error(
10358
- chalk35.dim(` Schedule "${nameArg ?? "unknown"}" not found`)
10359
- );
10360
- console.error(chalk35.dim(" Run: vm0 schedule list"));
10361
- } else {
10362
- console.error(chalk35.dim(` ${error.message}`));
10363
- }
10364
- }
10365
- process.exit(1);
9930
+ handleStatusError(error, agentName);
10366
9931
  }
10367
9932
  });
10368
9933
 
10369
9934
  // src/commands/schedule/delete.ts
10370
- import { Command as Command33 } from "commander";
10371
- import chalk36 from "chalk";
9935
+ import { Command as Command31 } from "commander";
9936
+ import chalk34 from "chalk";
10372
9937
  import * as readline from "readline";
10373
9938
  async function confirm(message) {
10374
9939
  const rl = readline.createInterface({
10375
9940
  input: process.stdin,
10376
9941
  output: process.stdout
10377
9942
  });
10378
- return new Promise((resolve2) => {
9943
+ return new Promise((resolve) => {
10379
9944
  rl.question(`${message} (y/N) `, (answer) => {
10380
9945
  rl.close();
10381
- resolve2(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
9946
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
10382
9947
  });
10383
9948
  });
10384
9949
  }
10385
- var deleteCommand = new Command33().name("delete").alias("rm").description("Delete a schedule").argument(
10386
- "[name]",
10387
- "Schedule name (auto-detected from schedule.yaml if omitted)"
10388
- ).option("-f, --force", "Skip confirmation prompt").action(async (nameArg, options) => {
10389
- let name = nameArg;
9950
+ var deleteCommand = new Command31().name("delete").alias("rm").description("Delete a schedule").argument("<agent-name>", "Agent name").option("-f, --force", "Skip confirmation prompt").action(async (agentName, options) => {
10390
9951
  try {
10391
- if (!name) {
10392
- const scheduleResult = loadScheduleName();
10393
- if (scheduleResult.error) {
10394
- console.error(chalk36.red(`\u2717 ${scheduleResult.error}`));
10395
- process.exit(1);
10396
- }
10397
- if (!scheduleResult.scheduleName) {
10398
- console.error(chalk36.red("\u2717 Schedule name required"));
10399
- console.error(
10400
- chalk36.dim(
10401
- " Provide name or run from directory with schedule.yaml"
10402
- )
10403
- );
10404
- process.exit(1);
10405
- }
10406
- name = scheduleResult.scheduleName;
10407
- }
10408
- const resolved = await resolveScheduleByName(name);
9952
+ const resolved = await resolveScheduleByAgent(agentName);
10409
9953
  if (!options.force) {
10410
- const confirmed = await confirm(`Delete schedule ${chalk36.cyan(name)}?`);
9954
+ const confirmed = await confirm(
9955
+ `Delete schedule for agent ${chalk34.cyan(agentName)}?`
9956
+ );
10411
9957
  if (!confirmed) {
10412
- console.log(chalk36.dim("Cancelled"));
9958
+ console.log(chalk34.dim("Cancelled"));
10413
9959
  return;
10414
9960
  }
10415
9961
  }
10416
- await deleteSchedule({ name, composeId: resolved.composeId });
10417
- console.log(chalk36.green(`\u2713 Deleted schedule ${chalk36.cyan(name)}`));
9962
+ await deleteSchedule({
9963
+ name: resolved.name,
9964
+ composeId: resolved.composeId
9965
+ });
9966
+ console.log(
9967
+ chalk34.green(`\u2713 Deleted schedule for agent ${chalk34.cyan(agentName)}`)
9968
+ );
10418
9969
  } catch (error) {
10419
- console.error(chalk36.red("\u2717 Failed to delete schedule"));
9970
+ console.error(chalk34.red("\u2717 Failed to delete schedule"));
10420
9971
  if (error instanceof Error) {
10421
9972
  if (error.message.includes("Not authenticated")) {
10422
- console.error(chalk36.dim(" Run: vm0 auth login"));
10423
- } else if (error.message.toLowerCase().includes("not found")) {
10424
- console.error(chalk36.dim(` Schedule "${name}" not found`));
10425
- console.error(chalk36.dim(" Run: vm0 schedule list"));
9973
+ console.error(chalk34.dim(" Run: vm0 auth login"));
9974
+ } else if (error.message.toLowerCase().includes("not found") || error.message.includes("No schedule found")) {
9975
+ console.error(
9976
+ chalk34.dim(` No schedule found for agent "${agentName}"`)
9977
+ );
9978
+ console.error(chalk34.dim(" Run: vm0 schedule list"));
10426
9979
  } else {
10427
- console.error(chalk36.dim(` ${error.message}`));
9980
+ console.error(chalk34.dim(` ${error.message}`));
10428
9981
  }
10429
9982
  }
10430
9983
  process.exit(1);
@@ -10432,44 +9985,30 @@ var deleteCommand = new Command33().name("delete").alias("rm").description("Dele
10432
9985
  });
10433
9986
 
10434
9987
  // src/commands/schedule/enable.ts
10435
- import { Command as Command34 } from "commander";
10436
- import chalk37 from "chalk";
10437
- var enableCommand = new Command34().name("enable").description("Enable a schedule").argument(
10438
- "[name]",
10439
- "Schedule name (auto-detected from schedule.yaml if omitted)"
10440
- ).action(async (nameArg) => {
9988
+ import { Command as Command32 } from "commander";
9989
+ import chalk35 from "chalk";
9990
+ var enableCommand = new Command32().name("enable").description("Enable a schedule").argument("<agent-name>", "Agent name").action(async (agentName) => {
10441
9991
  try {
10442
- let name = nameArg;
10443
- if (!name) {
10444
- const scheduleResult = loadScheduleName();
10445
- if (scheduleResult.error) {
10446
- console.error(chalk37.red(`\u2717 ${scheduleResult.error}`));
10447
- process.exit(1);
10448
- }
10449
- if (!scheduleResult.scheduleName) {
10450
- console.error(chalk37.red("\u2717 Schedule name required"));
10451
- console.error(
10452
- chalk37.dim(
10453
- " Provide name or run from directory with schedule.yaml"
10454
- )
10455
- );
10456
- process.exit(1);
10457
- }
10458
- name = scheduleResult.scheduleName;
10459
- }
10460
- const resolved = await resolveScheduleByName(name);
10461
- await enableSchedule({ name, composeId: resolved.composeId });
10462
- console.log(chalk37.green(`\u2713 Enabled schedule ${chalk37.cyan(name)}`));
9992
+ const resolved = await resolveScheduleByAgent(agentName);
9993
+ await enableSchedule({
9994
+ name: resolved.name,
9995
+ composeId: resolved.composeId
9996
+ });
9997
+ console.log(
9998
+ chalk35.green(`\u2713 Enabled schedule for agent ${chalk35.cyan(agentName)}`)
9999
+ );
10463
10000
  } catch (error) {
10464
- console.error(chalk37.red("\u2717 Failed to enable schedule"));
10001
+ console.error(chalk35.red("\u2717 Failed to enable schedule"));
10465
10002
  if (error instanceof Error) {
10466
10003
  if (error.message.includes("Not authenticated")) {
10467
- console.error(chalk37.dim(" Run: vm0 auth login"));
10468
- } else if (error.message.toLowerCase().includes("not found")) {
10469
- console.error(chalk37.dim(` Schedule "${nameArg}" not found`));
10470
- console.error(chalk37.dim(" Run: vm0 schedule list"));
10004
+ console.error(chalk35.dim(" Run: vm0 auth login"));
10005
+ } else if (error.message.toLowerCase().includes("not found") || error.message.includes("No schedule found")) {
10006
+ console.error(
10007
+ chalk35.dim(` No schedule found for agent "${agentName}"`)
10008
+ );
10009
+ console.error(chalk35.dim(" Run: vm0 schedule list"));
10471
10010
  } else {
10472
- console.error(chalk37.dim(` ${error.message}`));
10011
+ console.error(chalk35.dim(` ${error.message}`));
10473
10012
  }
10474
10013
  }
10475
10014
  process.exit(1);
@@ -10477,44 +10016,30 @@ var enableCommand = new Command34().name("enable").description("Enable a schedul
10477
10016
  });
10478
10017
 
10479
10018
  // src/commands/schedule/disable.ts
10480
- import { Command as Command35 } from "commander";
10481
- import chalk38 from "chalk";
10482
- var disableCommand = new Command35().name("disable").description("Disable a schedule").argument(
10483
- "[name]",
10484
- "Schedule name (auto-detected from schedule.yaml if omitted)"
10485
- ).action(async (nameArg) => {
10019
+ import { Command as Command33 } from "commander";
10020
+ import chalk36 from "chalk";
10021
+ var disableCommand = new Command33().name("disable").description("Disable a schedule").argument("<agent-name>", "Agent name").action(async (agentName) => {
10486
10022
  try {
10487
- let name = nameArg;
10488
- if (!name) {
10489
- const scheduleResult = loadScheduleName();
10490
- if (scheduleResult.error) {
10491
- console.error(chalk38.red(`\u2717 ${scheduleResult.error}`));
10492
- process.exit(1);
10493
- }
10494
- if (!scheduleResult.scheduleName) {
10495
- console.error(chalk38.red("\u2717 Schedule name required"));
10496
- console.error(
10497
- chalk38.dim(
10498
- " Provide name or run from directory with schedule.yaml"
10499
- )
10500
- );
10501
- process.exit(1);
10502
- }
10503
- name = scheduleResult.scheduleName;
10504
- }
10505
- const resolved = await resolveScheduleByName(name);
10506
- await disableSchedule({ name, composeId: resolved.composeId });
10507
- console.log(chalk38.green(`\u2713 Disabled schedule ${chalk38.cyan(name)}`));
10023
+ const resolved = await resolveScheduleByAgent(agentName);
10024
+ await disableSchedule({
10025
+ name: resolved.name,
10026
+ composeId: resolved.composeId
10027
+ });
10028
+ console.log(
10029
+ chalk36.green(`\u2713 Disabled schedule for agent ${chalk36.cyan(agentName)}`)
10030
+ );
10508
10031
  } catch (error) {
10509
- console.error(chalk38.red("\u2717 Failed to disable schedule"));
10032
+ console.error(chalk36.red("\u2717 Failed to disable schedule"));
10510
10033
  if (error instanceof Error) {
10511
10034
  if (error.message.includes("Not authenticated")) {
10512
- console.error(chalk38.dim(" Run: vm0 auth login"));
10513
- } else if (error.message.toLowerCase().includes("not found")) {
10514
- console.error(chalk38.dim(` Schedule "${nameArg}" not found`));
10515
- console.error(chalk38.dim(" Run: vm0 schedule list"));
10035
+ console.error(chalk36.dim(" Run: vm0 auth login"));
10036
+ } else if (error.message.toLowerCase().includes("not found") || error.message.includes("No schedule found")) {
10037
+ console.error(
10038
+ chalk36.dim(` No schedule found for agent "${agentName}"`)
10039
+ );
10040
+ console.error(chalk36.dim(" Run: vm0 schedule list"));
10516
10041
  } else {
10517
- console.error(chalk38.dim(` ${error.message}`));
10042
+ console.error(chalk36.dim(` ${error.message}`));
10518
10043
  }
10519
10044
  }
10520
10045
  process.exit(1);
@@ -10522,11 +10047,11 @@ var disableCommand = new Command35().name("disable").description("Disable a sche
10522
10047
  });
10523
10048
 
10524
10049
  // src/commands/schedule/index.ts
10525
- var scheduleCommand = new Command36().name("schedule").description("Manage agent schedules").addCommand(initCommand4).addCommand(deployCommand).addCommand(listCommand4).addCommand(statusCommand4).addCommand(deleteCommand).addCommand(enableCommand).addCommand(disableCommand);
10050
+ var scheduleCommand = new Command34().name("schedule").description("Manage agent schedules").addCommand(setupCommand).addCommand(listCommand4).addCommand(statusCommand5).addCommand(deleteCommand).addCommand(enableCommand).addCommand(disableCommand);
10526
10051
 
10527
10052
  // src/commands/usage.ts
10528
- import { Command as Command37 } from "commander";
10529
- import chalk39 from "chalk";
10053
+ import { Command as Command35 } from "commander";
10054
+ import chalk37 from "chalk";
10530
10055
 
10531
10056
  // src/lib/utils/duration-formatter.ts
10532
10057
  function formatDuration(ms) {
@@ -10599,7 +10124,7 @@ function fillMissingDates(daily, startDate, endDate) {
10599
10124
  result.sort((a, b) => b.date.localeCompare(a.date));
10600
10125
  return result;
10601
10126
  }
10602
- var usageCommand = new Command37().name("usage").description("View usage statistics").option("--since <date>", "Start date (ISO format or relative: 7d, 30d)").option(
10127
+ var usageCommand = new Command35().name("usage").description("View usage statistics").option("--since <date>", "Start date (ISO format or relative: 7d, 30d)").option(
10603
10128
  "--until <date>",
10604
10129
  "End date (ISO format or relative, defaults to now)"
10605
10130
  ).action(async (options) => {
@@ -10613,7 +10138,7 @@ var usageCommand = new Command37().name("usage").description("View usage statist
10613
10138
  endDate = new Date(untilMs);
10614
10139
  } catch {
10615
10140
  console.error(
10616
- chalk39.red(
10141
+ chalk37.red(
10617
10142
  "Error: Invalid --until format. Use ISO (2026-01-01) or relative (7d, 30d)"
10618
10143
  )
10619
10144
  );
@@ -10628,7 +10153,7 @@ var usageCommand = new Command37().name("usage").description("View usage statist
10628
10153
  startDate = new Date(sinceMs);
10629
10154
  } catch {
10630
10155
  console.error(
10631
- chalk39.red(
10156
+ chalk37.red(
10632
10157
  "Error: Invalid --since format. Use ISO (2026-01-01) or relative (7d, 30d)"
10633
10158
  )
10634
10159
  );
@@ -10638,13 +10163,13 @@ var usageCommand = new Command37().name("usage").description("View usage statist
10638
10163
  startDate = new Date(endDate.getTime() - DEFAULT_RANGE_MS);
10639
10164
  }
10640
10165
  if (startDate >= endDate) {
10641
- console.error(chalk39.red("Error: --since must be before --until"));
10166
+ console.error(chalk37.red("Error: --since must be before --until"));
10642
10167
  process.exit(1);
10643
10168
  }
10644
10169
  const rangeMs = endDate.getTime() - startDate.getTime();
10645
10170
  if (rangeMs > MAX_RANGE_MS) {
10646
10171
  console.error(
10647
- chalk39.red(
10172
+ chalk37.red(
10648
10173
  "Error: Time range exceeds maximum of 30 days. Use --until to specify an end date."
10649
10174
  )
10650
10175
  );
@@ -10661,19 +10186,19 @@ var usageCommand = new Command37().name("usage").description("View usage statist
10661
10186
  );
10662
10187
  console.log();
10663
10188
  console.log(
10664
- chalk39.bold(
10189
+ chalk37.bold(
10665
10190
  `Usage Summary (${formatDateRange(usage.period.start, usage.period.end)})`
10666
10191
  )
10667
10192
  );
10668
10193
  console.log();
10669
- console.log(chalk39.dim("DATE RUNS RUN TIME"));
10194
+ console.log(chalk37.dim("DATE RUNS RUN TIME"));
10670
10195
  for (const day of filledDaily) {
10671
10196
  const dateDisplay = formatDateDisplay(day.date).padEnd(10);
10672
10197
  const runsDisplay = String(day.run_count).padStart(6);
10673
10198
  const timeDisplay = formatDuration(day.run_time_ms);
10674
10199
  console.log(`${dateDisplay}${runsDisplay} ${timeDisplay}`);
10675
10200
  }
10676
- console.log(chalk39.dim("\u2500".repeat(29)));
10201
+ console.log(chalk37.dim("\u2500".repeat(29)));
10677
10202
  const totalRunsDisplay = String(usage.summary.total_runs).padStart(6);
10678
10203
  const totalTimeDisplay = formatDuration(usage.summary.total_run_time_ms);
10679
10204
  console.log(
@@ -10684,68 +10209,68 @@ var usageCommand = new Command37().name("usage").description("View usage statist
10684
10209
  if (error instanceof Error) {
10685
10210
  if (error.message.includes("Not authenticated")) {
10686
10211
  console.error(
10687
- chalk39.red("Error: Not authenticated. Run: vm0 auth login")
10212
+ chalk37.red("Error: Not authenticated. Run: vm0 auth login")
10688
10213
  );
10689
10214
  } else {
10690
- console.error(chalk39.red(`Error: ${error.message}`));
10215
+ console.error(chalk37.red(`Error: ${error.message}`));
10691
10216
  }
10692
10217
  } else {
10693
- console.error(chalk39.red("Error: An unexpected error occurred"));
10218
+ console.error(chalk37.red("Error: An unexpected error occurred"));
10694
10219
  }
10695
10220
  process.exit(1);
10696
10221
  }
10697
10222
  });
10698
10223
 
10699
10224
  // src/commands/credential/index.ts
10700
- import { Command as Command41 } from "commander";
10225
+ import { Command as Command39 } from "commander";
10701
10226
 
10702
10227
  // src/commands/credential/list.ts
10703
- import { Command as Command38 } from "commander";
10704
- import chalk40 from "chalk";
10705
- var listCommand5 = new Command38().name("list").alias("ls").description("List all credentials").action(async () => {
10228
+ import { Command as Command36 } from "commander";
10229
+ import chalk38 from "chalk";
10230
+ var listCommand5 = new Command36().name("list").alias("ls").description("List all credentials").action(async () => {
10706
10231
  try {
10707
10232
  const result = await listCredentials();
10708
10233
  if (result.credentials.length === 0) {
10709
- console.log(chalk40.dim("No credentials found."));
10234
+ console.log(chalk38.dim("No credentials found."));
10710
10235
  console.log();
10711
10236
  console.log("To add a credential:");
10712
- console.log(chalk40.cyan(" vm0 credential set MY_API_KEY <value>"));
10237
+ console.log(chalk38.cyan(" vm0 credential set MY_API_KEY <value>"));
10713
10238
  return;
10714
10239
  }
10715
- console.log(chalk40.bold("Credentials:"));
10240
+ console.log(chalk38.bold("Credentials:"));
10716
10241
  console.log();
10717
10242
  for (const credential of result.credentials) {
10718
- const typeIndicator = credential.type === "model-provider" ? chalk40.dim(" [model-provider]") : "";
10719
- console.log(` ${chalk40.cyan(credential.name)}${typeIndicator}`);
10243
+ const typeIndicator = credential.type === "model-provider" ? chalk38.dim(" [model-provider]") : "";
10244
+ console.log(` ${chalk38.cyan(credential.name)}${typeIndicator}`);
10720
10245
  if (credential.description) {
10721
- console.log(` ${chalk40.dim(credential.description)}`);
10246
+ console.log(` ${chalk38.dim(credential.description)}`);
10722
10247
  }
10723
10248
  console.log(
10724
- ` ${chalk40.dim(`Updated: ${new Date(credential.updatedAt).toLocaleString()}`)}`
10249
+ ` ${chalk38.dim(`Updated: ${new Date(credential.updatedAt).toLocaleString()}`)}`
10725
10250
  );
10726
10251
  console.log();
10727
10252
  }
10728
10253
  console.log(
10729
- chalk40.dim(`Total: ${result.credentials.length} credential(s)`)
10254
+ chalk38.dim(`Total: ${result.credentials.length} credential(s)`)
10730
10255
  );
10731
10256
  } catch (error) {
10732
10257
  if (error instanceof Error) {
10733
10258
  if (error.message.includes("Not authenticated")) {
10734
- console.error(chalk40.red("\u2717 Not authenticated. Run: vm0 auth login"));
10259
+ console.error(chalk38.red("\u2717 Not authenticated. Run: vm0 auth login"));
10735
10260
  } else {
10736
- console.error(chalk40.red(`\u2717 ${error.message}`));
10261
+ console.error(chalk38.red(`\u2717 ${error.message}`));
10737
10262
  }
10738
10263
  } else {
10739
- console.error(chalk40.red("\u2717 An unexpected error occurred"));
10264
+ console.error(chalk38.red("\u2717 An unexpected error occurred"));
10740
10265
  }
10741
10266
  process.exit(1);
10742
10267
  }
10743
10268
  });
10744
10269
 
10745
10270
  // src/commands/credential/set.ts
10746
- import { Command as Command39 } from "commander";
10747
- import chalk41 from "chalk";
10748
- var setCommand2 = new Command39().name("set").description("Create or update a credential").argument("<name>", "Credential name (uppercase, e.g., MY_API_KEY)").argument("<value>", "Credential value").option("-d, --description <description>", "Optional description").action(
10271
+ import { Command as Command37 } from "commander";
10272
+ import chalk39 from "chalk";
10273
+ var setCommand2 = new Command37().name("set").description("Create or update a credential").argument("<name>", "Credential name (uppercase, e.g., MY_API_KEY)").argument("<value>", "Credential value").option("-d, --description <description>", "Optional description").action(
10749
10274
  async (name, value, options) => {
10750
10275
  try {
10751
10276
  const credential = await setCredential({
@@ -10753,29 +10278,29 @@ var setCommand2 = new Command39().name("set").description("Create or update a cr
10753
10278
  value,
10754
10279
  description: options.description
10755
10280
  });
10756
- console.log(chalk41.green(`\u2713 Credential "${credential.name}" saved`));
10281
+ console.log(chalk39.green(`\u2713 Credential "${credential.name}" saved`));
10757
10282
  console.log();
10758
10283
  console.log("Use in vm0.yaml:");
10759
- console.log(chalk41.cyan(` environment:`));
10760
- console.log(chalk41.cyan(` ${name}: \${{ credentials.${name} }}`));
10284
+ console.log(chalk39.cyan(` environment:`));
10285
+ console.log(chalk39.cyan(` ${name}: \${{ credentials.${name} }}`));
10761
10286
  } catch (error) {
10762
10287
  if (error instanceof Error) {
10763
10288
  if (error.message.includes("Not authenticated")) {
10764
10289
  console.error(
10765
- chalk41.red("\u2717 Not authenticated. Run: vm0 auth login")
10290
+ chalk39.red("\u2717 Not authenticated. Run: vm0 auth login")
10766
10291
  );
10767
10292
  } else if (error.message.includes("must contain only uppercase")) {
10768
- console.error(chalk41.red(`\u2717 ${error.message}`));
10293
+ console.error(chalk39.red(`\u2717 ${error.message}`));
10769
10294
  console.log();
10770
10295
  console.log("Examples of valid credential names:");
10771
- console.log(chalk41.dim(" MY_API_KEY"));
10772
- console.log(chalk41.dim(" GITHUB_TOKEN"));
10773
- console.log(chalk41.dim(" AWS_ACCESS_KEY_ID"));
10296
+ console.log(chalk39.dim(" MY_API_KEY"));
10297
+ console.log(chalk39.dim(" GITHUB_TOKEN"));
10298
+ console.log(chalk39.dim(" AWS_ACCESS_KEY_ID"));
10774
10299
  } else {
10775
- console.error(chalk41.red(`\u2717 ${error.message}`));
10300
+ console.error(chalk39.red(`\u2717 ${error.message}`));
10776
10301
  }
10777
10302
  } else {
10778
- console.error(chalk41.red("\u2717 An unexpected error occurred"));
10303
+ console.error(chalk39.red("\u2717 An unexpected error occurred"));
10779
10304
  }
10780
10305
  process.exit(1);
10781
10306
  }
@@ -10783,14 +10308,14 @@ var setCommand2 = new Command39().name("set").description("Create or update a cr
10783
10308
  );
10784
10309
 
10785
10310
  // src/commands/credential/delete.ts
10786
- import { Command as Command40 } from "commander";
10787
- import chalk42 from "chalk";
10788
- var deleteCommand2 = new Command40().name("delete").description("Delete a credential").argument("<name>", "Credential name to delete").option("-y, --yes", "Skip confirmation prompt").action(async (name, options) => {
10311
+ import { Command as Command38 } from "commander";
10312
+ import chalk40 from "chalk";
10313
+ var deleteCommand2 = new Command38().name("delete").description("Delete a credential").argument("<name>", "Credential name to delete").option("-y, --yes", "Skip confirmation prompt").action(async (name, options) => {
10789
10314
  try {
10790
10315
  try {
10791
10316
  await getCredential(name);
10792
10317
  } catch {
10793
- console.error(chalk42.red(`\u2717 Credential "${name}" not found`));
10318
+ console.error(chalk40.red(`\u2717 Credential "${name}" not found`));
10794
10319
  process.exit(1);
10795
10320
  }
10796
10321
  if (!options.yes) {
@@ -10799,55 +10324,55 @@ var deleteCommand2 = new Command40().name("delete").description("Delete a creden
10799
10324
  input: process.stdin,
10800
10325
  output: process.stdout
10801
10326
  });
10802
- const confirmed = await new Promise((resolve2) => {
10327
+ const confirmed = await new Promise((resolve) => {
10803
10328
  rl.question(
10804
- chalk42.yellow(
10329
+ chalk40.yellow(
10805
10330
  `Are you sure you want to delete credential "${name}"? (y/N) `
10806
10331
  ),
10807
10332
  (answer) => {
10808
10333
  rl.close();
10809
- resolve2(answer.toLowerCase() === "y");
10334
+ resolve(answer.toLowerCase() === "y");
10810
10335
  }
10811
10336
  );
10812
10337
  });
10813
10338
  if (!confirmed) {
10814
- console.log(chalk42.dim("Cancelled."));
10339
+ console.log(chalk40.dim("Cancelled."));
10815
10340
  return;
10816
10341
  }
10817
10342
  }
10818
10343
  await deleteCredential(name);
10819
- console.log(chalk42.green(`\u2713 Credential "${name}" deleted`));
10344
+ console.log(chalk40.green(`\u2713 Credential "${name}" deleted`));
10820
10345
  } catch (error) {
10821
10346
  if (error instanceof Error) {
10822
10347
  if (error.message.includes("Not authenticated")) {
10823
- console.error(chalk42.red("\u2717 Not authenticated. Run: vm0 auth login"));
10348
+ console.error(chalk40.red("\u2717 Not authenticated. Run: vm0 auth login"));
10824
10349
  } else {
10825
- console.error(chalk42.red(`\u2717 ${error.message}`));
10350
+ console.error(chalk40.red(`\u2717 ${error.message}`));
10826
10351
  }
10827
10352
  } else {
10828
- console.error(chalk42.red("\u2717 An unexpected error occurred"));
10353
+ console.error(chalk40.red("\u2717 An unexpected error occurred"));
10829
10354
  }
10830
10355
  process.exit(1);
10831
10356
  }
10832
10357
  });
10833
10358
 
10834
10359
  // src/commands/credential/index.ts
10835
- var credentialCommand = new Command41().name("credential").description("Manage stored credentials for agent runs").addCommand(listCommand5).addCommand(setCommand2).addCommand(deleteCommand2);
10360
+ var credentialCommand = new Command39().name("credential").description("Manage stored credentials for agent runs").addCommand(listCommand5).addCommand(setCommand2).addCommand(deleteCommand2);
10836
10361
 
10837
10362
  // src/commands/model-provider/index.ts
10838
- import { Command as Command46 } from "commander";
10363
+ import { Command as Command44 } from "commander";
10839
10364
 
10840
10365
  // src/commands/model-provider/list.ts
10841
- import { Command as Command42 } from "commander";
10842
- import chalk43 from "chalk";
10843
- var listCommand6 = new Command42().name("list").alias("ls").description("List all model providers").action(async () => {
10366
+ import { Command as Command40 } from "commander";
10367
+ import chalk41 from "chalk";
10368
+ var listCommand6 = new Command40().name("list").alias("ls").description("List all model providers").action(async () => {
10844
10369
  try {
10845
10370
  const result = await listModelProviders();
10846
10371
  if (result.modelProviders.length === 0) {
10847
- console.log(chalk43.dim("No model providers configured."));
10372
+ console.log(chalk41.dim("No model providers configured."));
10848
10373
  console.log();
10849
10374
  console.log("To add a model provider:");
10850
- console.log(chalk43.cyan(" vm0 model-provider setup"));
10375
+ console.log(chalk41.cyan(" vm0 model-provider setup"));
10851
10376
  return;
10852
10377
  }
10853
10378
  const byFramework = result.modelProviders.reduce(
@@ -10861,15 +10386,15 @@ var listCommand6 = new Command42().name("list").alias("ls").description("List al
10861
10386
  },
10862
10387
  {}
10863
10388
  );
10864
- console.log(chalk43.bold("Model Providers:"));
10389
+ console.log(chalk41.bold("Model Providers:"));
10865
10390
  console.log();
10866
10391
  for (const [framework, providers] of Object.entries(byFramework)) {
10867
- console.log(` ${chalk43.cyan(framework)}:`);
10392
+ console.log(` ${chalk41.cyan(framework)}:`);
10868
10393
  for (const provider of providers) {
10869
- const defaultTag = provider.isDefault ? chalk43.green(" (default)") : "";
10394
+ const defaultTag = provider.isDefault ? chalk41.green(" (default)") : "";
10870
10395
  console.log(` ${provider.type}${defaultTag}`);
10871
10396
  console.log(
10872
- chalk43.dim(
10397
+ chalk41.dim(
10873
10398
  ` Updated: ${new Date(provider.updatedAt).toLocaleString()}`
10874
10399
  )
10875
10400
  );
@@ -10877,25 +10402,25 @@ var listCommand6 = new Command42().name("list").alias("ls").description("List al
10877
10402
  console.log();
10878
10403
  }
10879
10404
  console.log(
10880
- chalk43.dim(`Total: ${result.modelProviders.length} provider(s)`)
10405
+ chalk41.dim(`Total: ${result.modelProviders.length} provider(s)`)
10881
10406
  );
10882
10407
  } catch (error) {
10883
10408
  if (error instanceof Error) {
10884
10409
  if (error.message.includes("Not authenticated")) {
10885
- console.error(chalk43.red("x Not authenticated. Run: vm0 auth login"));
10410
+ console.error(chalk41.red("x Not authenticated. Run: vm0 auth login"));
10886
10411
  } else {
10887
- console.error(chalk43.red(`x ${error.message}`));
10412
+ console.error(chalk41.red(`x ${error.message}`));
10888
10413
  }
10889
10414
  } else {
10890
- console.error(chalk43.red("x An unexpected error occurred"));
10415
+ console.error(chalk41.red("x An unexpected error occurred"));
10891
10416
  }
10892
10417
  process.exit(1);
10893
10418
  }
10894
10419
  });
10895
10420
 
10896
10421
  // src/commands/model-provider/setup.ts
10897
- import { Command as Command43 } from "commander";
10898
- import chalk44 from "chalk";
10422
+ import { Command as Command41 } from "commander";
10423
+ import chalk42 from "chalk";
10899
10424
  import prompts3 from "prompts";
10900
10425
  var providerChoices = Object.entries(MODEL_PROVIDER_TYPES).map(
10901
10426
  ([type, config]) => ({
@@ -10903,7 +10428,7 @@ var providerChoices = Object.entries(MODEL_PROVIDER_TYPES).map(
10903
10428
  value: type
10904
10429
  })
10905
10430
  );
10906
- var setupCommand = new Command43().name("setup").description("Configure a model provider").option("-t, --type <type>", "Provider type (for non-interactive mode)").option(
10431
+ var setupCommand2 = new Command41().name("setup").description("Configure a model provider").option("-t, --type <type>", "Provider type (for non-interactive mode)").option(
10907
10432
  "-c, --credential <credential>",
10908
10433
  "Credential value (for non-interactive mode)"
10909
10434
  ).option("--convert", "Convert existing user credential to model provider").action(
@@ -10914,11 +10439,11 @@ var setupCommand = new Command43().name("setup").description("Configure a model
10914
10439
  const shouldConvert = options.convert ?? false;
10915
10440
  if (options.type && options.credential) {
10916
10441
  if (!Object.keys(MODEL_PROVIDER_TYPES).includes(options.type)) {
10917
- console.error(chalk44.red(`x Invalid type "${options.type}"`));
10442
+ console.error(chalk42.red(`x Invalid type "${options.type}"`));
10918
10443
  console.log();
10919
10444
  console.log("Valid types:");
10920
10445
  for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
10921
- console.log(` ${chalk44.cyan(t)} - ${config.label}`);
10446
+ console.log(` ${chalk42.cyan(t)} - ${config.label}`);
10922
10447
  }
10923
10448
  process.exit(1);
10924
10449
  }
@@ -10926,16 +10451,16 @@ var setupCommand = new Command43().name("setup").description("Configure a model
10926
10451
  credential = options.credential;
10927
10452
  } else if (options.type || options.credential) {
10928
10453
  console.error(
10929
- chalk44.red("x Both --type and --credential are required")
10454
+ chalk42.red("x Both --type and --credential are required")
10930
10455
  );
10931
10456
  process.exit(1);
10932
10457
  } else {
10933
10458
  if (!isInteractive()) {
10934
- console.error(chalk44.red("x Interactive mode requires a TTY"));
10459
+ console.error(chalk42.red("x Interactive mode requires a TTY"));
10935
10460
  console.log();
10936
10461
  console.log("Use non-interactive mode:");
10937
10462
  console.log(
10938
- chalk44.cyan(
10463
+ chalk42.cyan(
10939
10464
  ' vm0 model-provider setup --type <type> --credential "<value>"'
10940
10465
  )
10941
10466
  );
@@ -10966,19 +10491,19 @@ var setupCommand = new Command43().name("setup").description("Configure a model
10966
10491
  const provider2 = await convertModelProviderCredential(type);
10967
10492
  const defaultNote2 = provider2.isDefault ? ` (default for ${provider2.framework})` : "";
10968
10493
  console.log(
10969
- chalk44.green(
10494
+ chalk42.green(
10970
10495
  `Done Converted "${checkResult.credentialName}" to model provider${defaultNote2}`
10971
10496
  )
10972
10497
  );
10973
10498
  return;
10974
10499
  } else {
10975
- console.log(chalk44.dim("Aborted."));
10500
+ console.log(chalk42.dim("Aborted."));
10976
10501
  process.exit(0);
10977
10502
  }
10978
10503
  }
10979
10504
  const config = MODEL_PROVIDER_TYPES[type];
10980
10505
  console.log();
10981
- console.log(chalk44.dim(config.helpText));
10506
+ console.log(chalk42.dim(config.helpText));
10982
10507
  console.log();
10983
10508
  const credentialResponse = await prompts3(
10984
10509
  {
@@ -10999,24 +10524,24 @@ var setupCommand = new Command43().name("setup").description("Configure a model
10999
10524
  const action = created ? "created" : "updated";
11000
10525
  const defaultNote = provider.isDefault ? ` (default for ${provider.framework})` : "";
11001
10526
  console.log(
11002
- chalk44.green(`Done Model provider "${type}" ${action}${defaultNote}`)
10527
+ chalk42.green(`Done Model provider "${type}" ${action}${defaultNote}`)
11003
10528
  );
11004
10529
  } catch (error) {
11005
10530
  if (error instanceof Error) {
11006
10531
  if (error.message.includes("already exists")) {
11007
- console.error(chalk44.red(`x ${error.message}`));
10532
+ console.error(chalk42.red(`x ${error.message}`));
11008
10533
  console.log();
11009
10534
  console.log("To convert the existing credential, run:");
11010
- console.log(chalk44.cyan(" vm0 model-provider setup --convert"));
10535
+ console.log(chalk42.cyan(" vm0 model-provider setup --convert"));
11011
10536
  } else if (error.message.includes("Not authenticated")) {
11012
10537
  console.error(
11013
- chalk44.red("x Not authenticated. Run: vm0 auth login")
10538
+ chalk42.red("x Not authenticated. Run: vm0 auth login")
11014
10539
  );
11015
10540
  } else {
11016
- console.error(chalk44.red(`x ${error.message}`));
10541
+ console.error(chalk42.red(`x ${error.message}`));
11017
10542
  }
11018
10543
  } else {
11019
- console.error(chalk44.red("x An unexpected error occurred"));
10544
+ console.error(chalk42.red("x An unexpected error occurred"));
11020
10545
  }
11021
10546
  process.exit(1);
11022
10547
  }
@@ -11024,81 +10549,81 @@ var setupCommand = new Command43().name("setup").description("Configure a model
11024
10549
  );
11025
10550
 
11026
10551
  // src/commands/model-provider/delete.ts
11027
- import { Command as Command44 } from "commander";
11028
- import chalk45 from "chalk";
11029
- var deleteCommand3 = new Command44().name("delete").description("Delete a model provider").argument("<type>", "Model provider type to delete").action(async (type) => {
10552
+ import { Command as Command42 } from "commander";
10553
+ import chalk43 from "chalk";
10554
+ var deleteCommand3 = new Command42().name("delete").description("Delete a model provider").argument("<type>", "Model provider type to delete").action(async (type) => {
11030
10555
  try {
11031
10556
  if (!Object.keys(MODEL_PROVIDER_TYPES).includes(type)) {
11032
- console.error(chalk45.red(`x Invalid type "${type}"`));
10557
+ console.error(chalk43.red(`x Invalid type "${type}"`));
11033
10558
  console.log();
11034
10559
  console.log("Valid types:");
11035
10560
  for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
11036
- console.log(` ${chalk45.cyan(t)} - ${config.label}`);
10561
+ console.log(` ${chalk43.cyan(t)} - ${config.label}`);
11037
10562
  }
11038
10563
  process.exit(1);
11039
10564
  }
11040
10565
  await deleteModelProvider(type);
11041
- console.log(chalk45.green(`Done Model provider "${type}" deleted`));
10566
+ console.log(chalk43.green(`Done Model provider "${type}" deleted`));
11042
10567
  } catch (error) {
11043
10568
  if (error instanceof Error) {
11044
10569
  if (error.message.includes("not found")) {
11045
- console.error(chalk45.red(`x Model provider "${type}" not found`));
10570
+ console.error(chalk43.red(`x Model provider "${type}" not found`));
11046
10571
  } else if (error.message.includes("Not authenticated")) {
11047
- console.error(chalk45.red("x Not authenticated. Run: vm0 auth login"));
10572
+ console.error(chalk43.red("x Not authenticated. Run: vm0 auth login"));
11048
10573
  } else {
11049
- console.error(chalk45.red(`x ${error.message}`));
10574
+ console.error(chalk43.red(`x ${error.message}`));
11050
10575
  }
11051
10576
  } else {
11052
- console.error(chalk45.red("x An unexpected error occurred"));
10577
+ console.error(chalk43.red("x An unexpected error occurred"));
11053
10578
  }
11054
10579
  process.exit(1);
11055
10580
  }
11056
10581
  });
11057
10582
 
11058
10583
  // src/commands/model-provider/set-default.ts
11059
- import { Command as Command45 } from "commander";
11060
- import chalk46 from "chalk";
11061
- var setDefaultCommand = new Command45().name("set-default").description("Set a model provider as default for its framework").argument("<type>", "Model provider type to set as default").action(async (type) => {
10584
+ import { Command as Command43 } from "commander";
10585
+ import chalk44 from "chalk";
10586
+ var setDefaultCommand = new Command43().name("set-default").description("Set a model provider as default for its framework").argument("<type>", "Model provider type to set as default").action(async (type) => {
11062
10587
  try {
11063
10588
  if (!Object.keys(MODEL_PROVIDER_TYPES).includes(type)) {
11064
- console.error(chalk46.red(`x Invalid type "${type}"`));
10589
+ console.error(chalk44.red(`x Invalid type "${type}"`));
11065
10590
  console.log();
11066
10591
  console.log("Valid types:");
11067
10592
  for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
11068
- console.log(` ${chalk46.cyan(t)} - ${config.label}`);
10593
+ console.log(` ${chalk44.cyan(t)} - ${config.label}`);
11069
10594
  }
11070
10595
  process.exit(1);
11071
10596
  }
11072
10597
  const provider = await setModelProviderDefault(type);
11073
10598
  console.log(
11074
- chalk46.green(
10599
+ chalk44.green(
11075
10600
  `Done Default for ${provider.framework} set to "${provider.type}"`
11076
10601
  )
11077
10602
  );
11078
10603
  } catch (error) {
11079
10604
  if (error instanceof Error) {
11080
10605
  if (error.message.includes("not found")) {
11081
- console.error(chalk46.red(`x Model provider "${type}" not found`));
10606
+ console.error(chalk44.red(`x Model provider "${type}" not found`));
11082
10607
  } else if (error.message.includes("Not authenticated")) {
11083
- console.error(chalk46.red("x Not authenticated. Run: vm0 auth login"));
10608
+ console.error(chalk44.red("x Not authenticated. Run: vm0 auth login"));
11084
10609
  } else {
11085
- console.error(chalk46.red(`x ${error.message}`));
10610
+ console.error(chalk44.red(`x ${error.message}`));
11086
10611
  }
11087
10612
  } else {
11088
- console.error(chalk46.red("x An unexpected error occurred"));
10613
+ console.error(chalk44.red("x An unexpected error occurred"));
11089
10614
  }
11090
10615
  process.exit(1);
11091
10616
  }
11092
10617
  });
11093
10618
 
11094
10619
  // src/commands/model-provider/index.ts
11095
- var modelProviderCommand = new Command46().name("model-provider").description("Manage model providers for agent runs").addCommand(listCommand6).addCommand(setupCommand).addCommand(deleteCommand3).addCommand(setDefaultCommand);
10620
+ var modelProviderCommand = new Command44().name("model-provider").description("Manage model providers for agent runs").addCommand(listCommand6).addCommand(setupCommand2).addCommand(deleteCommand3).addCommand(setDefaultCommand);
11096
10621
 
11097
10622
  // src/index.ts
11098
- var program = new Command47();
11099
- program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("7.1.1");
10623
+ var program = new Command45();
10624
+ program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("8.0.1");
11100
10625
  program.command("info").description("Display environment information").action(async () => {
11101
- console.log(chalk47.bold("System Information:"));
10626
+ console.log(chalk45.bold("System Information:"));
11102
10627
  console.log(`Node Version: ${process.version}`);
11103
10628
  console.log(`Platform: ${process.platform}`);
11104
10629
  console.log(`Architecture: ${process.arch}`);
@@ -11127,7 +10652,6 @@ program.addCommand(logsCommand);
11127
10652
  program.addCommand(scopeCommand);
11128
10653
  program.addCommand(agentCommand);
11129
10654
  program.addCommand(initCommand3);
11130
- program.addCommand(setupGithubCommand);
11131
10655
  program.addCommand(scheduleCommand);
11132
10656
  program.addCommand(usageCommand);
11133
10657
  program.addCommand(credentialCommand);