@vm0/cli 8.0.0 → 8.0.2

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 +242 -253
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -432,11 +432,6 @@ var appStringSchema = z4.string().superRefine((val, ctx) => {
432
432
  });
433
433
  var agentDefinitionSchema = z4.object({
434
434
  description: z4.string().optional(),
435
- /**
436
- * @deprecated Use `apps` field instead for pre-installed tools.
437
- * This field will be removed in a future version.
438
- */
439
- image: z4.string().optional(),
440
435
  framework: z4.string().min(1, "Framework is required"),
441
436
  /**
442
437
  * Array of pre-installed apps/tools for the agent environment.
@@ -446,8 +441,6 @@ var agentDefinitionSchema = z4.object({
446
441
  */
447
442
  apps: z4.array(appStringSchema).optional(),
448
443
  volumes: z4.array(z4.string()).optional(),
449
- working_dir: z4.string().optional(),
450
- // Optional when provider supports auto-config
451
444
  environment: z4.record(z4.string(), z4.string()).optional(),
452
445
  /**
453
446
  * Path to instructions file (e.g., AGENTS.md).
@@ -474,7 +467,17 @@ var agentDefinitionSchema = z4.object({
474
467
  * Requires experimental_runner to be configured.
475
468
  * When enabled, filters outbound traffic by domain/IP rules.
476
469
  */
477
- experimental_firewall: experimentalFirewallSchema.optional()
470
+ experimental_firewall: experimentalFirewallSchema.optional(),
471
+ /**
472
+ * @deprecated Server-resolved field. User input is ignored.
473
+ * @internal
474
+ */
475
+ image: z4.string().optional(),
476
+ /**
477
+ * @deprecated Server-resolved field. User input is ignored.
478
+ * @internal
479
+ */
480
+ working_dir: z4.string().optional()
478
481
  });
479
482
  var agentComposeContentSchema = z4.object({
480
483
  version: z4.string().min(1, "Version is required"),
@@ -2950,10 +2953,6 @@ var FEATURE_SWITCHES = {
2950
2953
  maintainer: "ethan@vm0.ai",
2951
2954
  enabled: true
2952
2955
  },
2953
- ["platformOnboarding" /* PlatformOnboarding */]: {
2954
- maintainer: "ethan@vm0.ai",
2955
- enabled: false
2956
- },
2957
2956
  ["platformAgents" /* PlatformAgents */]: {
2958
2957
  maintainer: "ethan@vm0.ai",
2959
2958
  enabled: false
@@ -3425,72 +3424,6 @@ async function getUsage(options) {
3425
3424
 
3426
3425
  // src/lib/domain/yaml-validator.ts
3427
3426
  import { z as z23 } from "zod";
3428
-
3429
- // src/lib/domain/framework-config.ts
3430
- var FRAMEWORK_DEFAULTS = {
3431
- "claude-code": {
3432
- workingDir: "/home/user/workspace",
3433
- image: {
3434
- production: "vm0/claude-code:latest",
3435
- development: "vm0/claude-code:dev"
3436
- }
3437
- },
3438
- codex: {
3439
- workingDir: "/home/user/workspace",
3440
- image: {
3441
- production: "vm0/codex:latest",
3442
- development: "vm0/codex:dev"
3443
- }
3444
- }
3445
- };
3446
- function getFrameworkDefaults(framework) {
3447
- return FRAMEWORK_DEFAULTS[framework];
3448
- }
3449
- function isFrameworkSupported(framework) {
3450
- return framework in FRAMEWORK_DEFAULTS;
3451
- }
3452
- var FRAMEWORK_APPS_IMAGES = {
3453
- "claude-code": {
3454
- github: {
3455
- production: "vm0/claude-code-github:latest",
3456
- development: "vm0/claude-code-github:dev"
3457
- }
3458
- },
3459
- codex: {
3460
- github: {
3461
- production: "vm0/codex-github:latest",
3462
- development: "vm0/codex-github:dev"
3463
- }
3464
- }
3465
- };
3466
- function parseAppString(appString) {
3467
- const [app, tag] = appString.split(":");
3468
- return {
3469
- app: app ?? appString,
3470
- tag: tag === "dev" ? "dev" : "latest"
3471
- };
3472
- }
3473
- function getDefaultImageWithApps(framework, apps) {
3474
- const defaults = FRAMEWORK_DEFAULTS[framework];
3475
- if (!defaults) return void 0;
3476
- if (apps && apps.length > 0) {
3477
- const frameworkApps = FRAMEWORK_APPS_IMAGES[framework];
3478
- if (frameworkApps) {
3479
- const firstApp = apps[0];
3480
- if (firstApp) {
3481
- const { app, tag } = parseAppString(firstApp);
3482
- const appImage = frameworkApps[app];
3483
- if (appImage) {
3484
- return tag === "dev" ? appImage.development : appImage.production;
3485
- }
3486
- }
3487
- }
3488
- }
3489
- const isDevelopment = process.env.NODE_ENV === "development" || process.env.NODE_ENV === "test";
3490
- return isDevelopment ? defaults.image.development : defaults.image.production;
3491
- }
3492
-
3493
- // src/lib/domain/yaml-validator.ts
3494
3427
  var cliAgentNameSchema = z23.string().min(3, "Agent name must be at least 3 characters").max(64, "Agent name must be 64 characters or less").regex(
3495
3428
  /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,62}[a-zA-Z0-9])?$/,
3496
3429
  "Agent name must start and end with letter or number, and contain only letters, numbers, and hyphens"
@@ -3501,21 +3434,6 @@ function validateGitHubTreeUrl(url) {
3501
3434
  }
3502
3435
  var cliAgentDefinitionSchema = agentDefinitionSchema.superRefine(
3503
3436
  (agent, ctx) => {
3504
- const frameworkSupported = isFrameworkSupported(agent.framework);
3505
- if (!agent.image && !frameworkSupported) {
3506
- ctx.addIssue({
3507
- code: z23.ZodIssueCode.custom,
3508
- message: "Missing agent.image (required when framework is not auto-configured)",
3509
- path: ["image"]
3510
- });
3511
- }
3512
- if (!agent.working_dir && !frameworkSupported) {
3513
- ctx.addIssue({
3514
- code: z23.ZodIssueCode.custom,
3515
- message: "Missing agent.working_dir (required when framework is not auto-configured)",
3516
- path: ["working_dir"]
3517
- });
3518
- }
3519
3437
  if (agent.skills) {
3520
3438
  for (let i = 0; i < agent.skills.length; i++) {
3521
3439
  const skillUrl = agent.skills[i];
@@ -4175,24 +4093,6 @@ var composeCommand = new Command().name("compose").description("Create or update
4175
4093
  const agentName = Object.keys(agents)[0];
4176
4094
  const agent = agents[agentName];
4177
4095
  const basePath = dirname2(configFile);
4178
- if (agent.framework) {
4179
- const defaults = getFrameworkDefaults(agent.framework);
4180
- if (defaults) {
4181
- if (!agent.image) {
4182
- const apps = agent.apps;
4183
- const defaultImage = getDefaultImageWithApps(
4184
- agent.framework,
4185
- apps
4186
- );
4187
- if (defaultImage) {
4188
- agent.image = defaultImage;
4189
- }
4190
- }
4191
- if (!agent.working_dir) {
4192
- agent.working_dir = defaults.workingDir;
4193
- }
4194
- }
4195
- }
4196
4096
  if (agent.instructions) {
4197
4097
  const instructionsPath = agent.instructions;
4198
4098
  const framework = agent.framework;
@@ -6758,6 +6658,24 @@ async function promptSelect(message, choices, initial) {
6758
6658
  );
6759
6659
  return response.value;
6760
6660
  }
6661
+ async function promptPassword(message) {
6662
+ if (!isInteractive()) {
6663
+ return void 0;
6664
+ }
6665
+ const response = await prompts2(
6666
+ {
6667
+ type: "password",
6668
+ name: "value",
6669
+ message
6670
+ },
6671
+ {
6672
+ onCancel: () => {
6673
+ return false;
6674
+ }
6675
+ }
6676
+ );
6677
+ return response.value;
6678
+ }
6761
6679
 
6762
6680
  // src/commands/volume/init.ts
6763
6681
  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) => {
@@ -7945,7 +7863,7 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option(
7945
7863
  // eslint-disable-next-line complexity -- TODO: refactor complex function
7946
7864
  async (prompt, options) => {
7947
7865
  if (!options.noAutoUpdate) {
7948
- const shouldExit = await checkAndUpgrade("8.0.0", prompt);
7866
+ const shouldExit = await checkAndUpgrade("8.0.2", prompt);
7949
7867
  if (shouldExit) {
7950
7868
  process.exit(0);
7951
7869
  }
@@ -8655,10 +8573,9 @@ import { Command as Command26 } from "commander";
8655
8573
  // src/commands/agent/list.ts
8656
8574
  import { Command as Command24 } from "commander";
8657
8575
  import chalk28 from "chalk";
8658
- 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) => {
8576
+ var listCommand3 = new Command24().name("list").alias("ls").description("List all agent composes").action(async () => {
8659
8577
  try {
8660
- const url = options.scope ? `/api/agent/composes/list?scope=${encodeURIComponent(options.scope)}` : "/api/agent/composes/list";
8661
- const response = await httpGet(url);
8578
+ const response = await httpGet("/api/agent/composes/list");
8662
8579
  if (!response.ok) {
8663
8580
  const error = await response.json();
8664
8581
  throw new Error(error.error?.message || "List failed");
@@ -8706,27 +8623,6 @@ import chalk29 from "chalk";
8706
8623
  import * as fs9 from "fs/promises";
8707
8624
  import * as path12 from "path";
8708
8625
  import * as os7 from "os";
8709
- function extractVariableReferences2(environment) {
8710
- const secrets = [];
8711
- const vars = [];
8712
- for (const value of Object.values(environment)) {
8713
- const matches = value.matchAll(/\$\{?([A-Z_][A-Z0-9_]*)\}?/g);
8714
- for (const match of matches) {
8715
- const varName = match[1];
8716
- if (!varName) continue;
8717
- if (varName.endsWith("_KEY") || varName.endsWith("_SECRET") || varName.endsWith("_TOKEN") || varName.endsWith("_PASSWORD") || varName.includes("API_KEY") || varName.includes("SECRET")) {
8718
- if (!secrets.includes(varName)) {
8719
- secrets.push(varName);
8720
- }
8721
- } else {
8722
- if (!vars.includes(varName)) {
8723
- vars.push(varName);
8724
- }
8725
- }
8726
- }
8727
- }
8728
- return { secrets: secrets.sort(), vars: vars.sort() };
8729
- }
8730
8626
  async function fetchSkillFrontmatter(skillUrl, tempDir) {
8731
8627
  try {
8732
8628
  const parsed = parseGitHubTreeUrl2(skillUrl);
@@ -8738,19 +8634,31 @@ async function fetchSkillFrontmatter(skillUrl, tempDir) {
8738
8634
  }
8739
8635
  }
8740
8636
  async function deriveAgentVariableSources(agent, options) {
8741
- const { secrets: secretNames, vars: varNames } = agent.environment ? extractVariableReferences2(agent.environment) : { secrets: [], vars: [] };
8637
+ const refs = agent.environment ? extractVariableReferences(agent.environment) : [];
8638
+ const grouped = groupVariablesBySource(refs);
8742
8639
  const secretSources = /* @__PURE__ */ new Map();
8743
8640
  const varSources = /* @__PURE__ */ new Map();
8744
- for (const name of secretNames) {
8745
- secretSources.set(name, { name, source: "agent environment" });
8641
+ const credentialSources = /* @__PURE__ */ new Map();
8642
+ for (const ref of grouped.secrets) {
8643
+ secretSources.set(ref.name, {
8644
+ name: ref.name,
8645
+ source: "agent environment"
8646
+ });
8746
8647
  }
8747
- for (const name of varNames) {
8748
- varSources.set(name, { name, source: "agent environment" });
8648
+ for (const ref of grouped.vars) {
8649
+ varSources.set(ref.name, { name: ref.name, source: "agent environment" });
8650
+ }
8651
+ for (const ref of grouped.credentials) {
8652
+ credentialSources.set(ref.name, {
8653
+ name: ref.name,
8654
+ source: "agent environment"
8655
+ });
8749
8656
  }
8750
8657
  if (options?.skipNetwork || !agent.skills || agent.skills.length === 0) {
8751
8658
  return {
8752
8659
  secrets: Array.from(secretSources.values()),
8753
- vars: Array.from(varSources.values())
8660
+ vars: Array.from(varSources.values()),
8661
+ credentials: Array.from(credentialSources.values())
8754
8662
  };
8755
8663
  }
8756
8664
  const tempDir = await fs9.mkdtemp(
@@ -8791,7 +8699,8 @@ async function deriveAgentVariableSources(agent, options) {
8791
8699
  }
8792
8700
  return {
8793
8701
  secrets: Array.from(secretSources.values()),
8794
- vars: Array.from(varSources.values())
8702
+ vars: Array.from(varSources.values()),
8703
+ credentials: Array.from(credentialSources.values())
8795
8704
  };
8796
8705
  }
8797
8706
  async function deriveComposeVariableSources(content, options) {
@@ -8843,6 +8752,13 @@ function formatVariableSources(sources) {
8843
8752
  console.log(` - ${v.name.padEnd(20)} ${sourceInfo}`);
8844
8753
  }
8845
8754
  }
8755
+ if (sources.credentials.length > 0) {
8756
+ console.log(` Credentials:`);
8757
+ for (const cred of sources.credentials) {
8758
+ const sourceInfo = chalk29.dim(`(${cred.source})`);
8759
+ console.log(` - ${cred.name.padEnd(20)} ${sourceInfo}`);
8760
+ }
8761
+ }
8846
8762
  }
8847
8763
  function formatAgentDetails(agentName, agent, agentSources, volumeConfigs) {
8848
8764
  console.log(` ${chalk29.cyan(agentName)}:`);
@@ -8876,83 +8792,81 @@ function formatComposeOutput(name, versionId, content, variableSources) {
8876
8792
  var statusCommand4 = new Command25().name("status").description("Show status of agent compose").argument(
8877
8793
  "<name[:version]>",
8878
8794
  "Agent name with optional version (e.g., my-agent:latest or my-agent:a1b2c3d4)"
8879
- ).option("-s, --scope <scope>", "Scope to look up the compose from").option("--no-sources", "Skip fetching skills to determine variable sources").action(
8880
- async (argument, options) => {
8881
- try {
8882
- const colonIndex = argument.lastIndexOf(":");
8883
- let name;
8884
- let version;
8885
- if (colonIndex === -1) {
8886
- name = argument;
8887
- version = "latest";
8888
- } else {
8889
- name = argument.slice(0, colonIndex);
8890
- version = argument.slice(colonIndex + 1) || "latest";
8891
- }
8892
- const compose = await getComposeByName(name, options.scope);
8893
- if (!compose) {
8894
- console.error(chalk29.red(`\u2717 Agent compose not found: ${name}`));
8895
- console.error(chalk29.dim(" Run: vm0 agent list"));
8896
- process.exit(1);
8897
- }
8898
- let resolvedVersionId = compose.headVersionId;
8899
- if (version !== "latest" && compose.headVersionId) {
8900
- if (version.length < 64) {
8901
- try {
8902
- const versionInfo = await getComposeVersion(compose.id, version);
8903
- resolvedVersionId = versionInfo.versionId;
8904
- } catch (error) {
8905
- if (error instanceof Error && error.message.includes("not found")) {
8906
- console.error(chalk29.red(`\u2717 Version not found: ${version}`));
8907
- console.error(
8908
- chalk29.dim(
8909
- ` HEAD version: ${compose.headVersionId?.slice(0, 8)}`
8910
- )
8911
- );
8912
- process.exit(1);
8913
- }
8914
- throw error;
8915
- }
8916
- } else {
8917
- resolvedVersionId = version;
8918
- }
8919
- }
8920
- if (!resolvedVersionId || !compose.content) {
8921
- console.error(chalk29.red(`\u2717 No version found for: ${name}`));
8922
- process.exit(1);
8923
- }
8924
- const content = compose.content;
8925
- let variableSources;
8926
- if (options.sources !== false) {
8795
+ ).option("--no-sources", "Skip fetching skills to determine variable sources").action(async (argument, options) => {
8796
+ try {
8797
+ const colonIndex = argument.lastIndexOf(":");
8798
+ let name;
8799
+ let version;
8800
+ if (colonIndex === -1) {
8801
+ name = argument;
8802
+ version = "latest";
8803
+ } else {
8804
+ name = argument.slice(0, colonIndex);
8805
+ version = argument.slice(colonIndex + 1) || "latest";
8806
+ }
8807
+ const compose = await getComposeByName(name);
8808
+ if (!compose) {
8809
+ console.error(chalk29.red(`\u2717 Agent compose not found: ${name}`));
8810
+ console.error(chalk29.dim(" Run: vm0 agent list"));
8811
+ process.exit(1);
8812
+ }
8813
+ let resolvedVersionId = compose.headVersionId;
8814
+ if (version !== "latest" && compose.headVersionId) {
8815
+ if (version.length < 64) {
8927
8816
  try {
8928
- variableSources = await deriveComposeVariableSources(content);
8929
- } catch {
8930
- console.error(
8931
- chalk29.yellow(
8932
- "\u26A0 Warning: Failed to fetch skill sources, showing basic info"
8933
- )
8934
- );
8817
+ const versionInfo = await getComposeVersion(compose.id, version);
8818
+ resolvedVersionId = versionInfo.versionId;
8819
+ } catch (error) {
8820
+ if (error instanceof Error && error.message.includes("not found")) {
8821
+ console.error(chalk29.red(`\u2717 Version not found: ${version}`));
8822
+ console.error(
8823
+ chalk29.dim(
8824
+ ` HEAD version: ${compose.headVersionId?.slice(0, 8)}`
8825
+ )
8826
+ );
8827
+ process.exit(1);
8828
+ }
8829
+ throw error;
8935
8830
  }
8831
+ } else {
8832
+ resolvedVersionId = version;
8936
8833
  }
8937
- formatComposeOutput(
8938
- compose.name,
8939
- resolvedVersionId,
8940
- content,
8941
- variableSources
8834
+ }
8835
+ if (!resolvedVersionId || !compose.content) {
8836
+ console.error(chalk29.red(`\u2717 No version found for: ${name}`));
8837
+ process.exit(1);
8838
+ }
8839
+ const content = compose.content;
8840
+ let variableSources;
8841
+ try {
8842
+ variableSources = await deriveComposeVariableSources(content, {
8843
+ skipNetwork: options.sources === false
8844
+ });
8845
+ } catch {
8846
+ console.error(
8847
+ chalk29.yellow(
8848
+ "\u26A0 Warning: Failed to fetch skill sources, showing basic info"
8849
+ )
8942
8850
  );
8943
- } catch (error) {
8944
- console.error(chalk29.red("\u2717 Failed to get agent compose status"));
8945
- if (error instanceof Error) {
8946
- if (error.message.includes("Not authenticated")) {
8947
- console.error(chalk29.dim(" Run: vm0 auth login"));
8948
- } else {
8949
- console.error(chalk29.dim(` ${error.message}`));
8950
- }
8851
+ }
8852
+ formatComposeOutput(
8853
+ compose.name,
8854
+ resolvedVersionId,
8855
+ content,
8856
+ variableSources
8857
+ );
8858
+ } catch (error) {
8859
+ console.error(chalk29.red("\u2717 Failed to get agent compose status"));
8860
+ if (error instanceof Error) {
8861
+ if (error.message.includes("Not authenticated")) {
8862
+ console.error(chalk29.dim(" Run: vm0 auth login"));
8863
+ } else {
8864
+ console.error(chalk29.dim(` ${error.message}`));
8951
8865
  }
8952
- process.exit(1);
8953
8866
  }
8867
+ process.exit(1);
8954
8868
  }
8955
- );
8869
+ });
8956
8870
 
8957
8871
  // src/commands/agent/index.ts
8958
8872
  var agentCommand = new Command26().name("agent").description("Manage agent composes").addCommand(listCommand3).addCommand(statusCommand4);
@@ -9179,6 +9093,22 @@ function toISODateTime(dateTimeStr) {
9179
9093
  const date = new Date(isoStr);
9180
9094
  return date.toISOString();
9181
9095
  }
9096
+ function extractRequiredConfiguration(composeContent) {
9097
+ const result = {
9098
+ secrets: [],
9099
+ vars: [],
9100
+ credentials: []
9101
+ };
9102
+ if (!composeContent) {
9103
+ return result;
9104
+ }
9105
+ const refs = extractVariableReferences(composeContent);
9106
+ const grouped = groupVariablesBySource(refs);
9107
+ result.secrets = grouped.secrets.map((r) => r.name);
9108
+ result.vars = grouped.vars.map((r) => r.name);
9109
+ result.credentials = grouped.credentials.map((r) => r.name);
9110
+ return result;
9111
+ }
9182
9112
  async function resolveScheduleByAgent(agentName) {
9183
9113
  const { schedules } = await listSchedules();
9184
9114
  const schedule = schedules.find((s) => s.composeName === agentName);
@@ -9480,14 +9410,67 @@ async function gatherSecrets(optionSecrets, existingSecretNames) {
9480
9410
  `Keep existing secrets? (${existingSecretNames.join(", ")})`,
9481
9411
  true
9482
9412
  );
9483
- if (!keepSecrets) {
9484
- console.log(
9485
- chalk31.dim(" Note: You'll need to provide new secret values")
9486
- );
9413
+ if (keepSecrets) {
9414
+ return void 0;
9487
9415
  }
9416
+ console.log(chalk31.dim(" Note: You'll need to provide new secret values"));
9417
+ return {};
9488
9418
  }
9489
9419
  return void 0;
9490
9420
  }
9421
+ async function gatherMissingConfiguration(required, providedSecrets, providedVars, existingSecretNames) {
9422
+ const secrets = { ...providedSecrets };
9423
+ const vars = { ...providedVars };
9424
+ const providedSecretNames = Object.keys(providedSecrets);
9425
+ const existingNames = existingSecretNames ?? [];
9426
+ const missingSecrets = required.secrets.filter(
9427
+ (name) => !providedSecretNames.includes(name) && !existingNames.includes(name)
9428
+ );
9429
+ const providedVarNames = Object.keys(providedVars);
9430
+ const missingVars = required.vars.filter(
9431
+ (name) => !providedVarNames.includes(name)
9432
+ );
9433
+ if (missingSecrets.length === 0 && missingVars.length === 0) {
9434
+ return { secrets, vars };
9435
+ }
9436
+ if (!isInteractive()) {
9437
+ return { secrets, vars };
9438
+ }
9439
+ if (missingSecrets.length > 0 || missingVars.length > 0) {
9440
+ console.log(chalk31.yellow("\nAgent requires the following configuration:"));
9441
+ if (missingSecrets.length > 0) {
9442
+ console.log(chalk31.dim(" Secrets:"));
9443
+ for (const name of missingSecrets) {
9444
+ console.log(chalk31.dim(` ${name}`));
9445
+ }
9446
+ }
9447
+ if (missingVars.length > 0) {
9448
+ console.log(chalk31.dim(" Vars:"));
9449
+ for (const name of missingVars) {
9450
+ console.log(chalk31.dim(` ${name}`));
9451
+ }
9452
+ }
9453
+ console.log("");
9454
+ }
9455
+ for (const name of missingSecrets) {
9456
+ const value = await promptPassword(
9457
+ `Enter value for secret ${chalk31.cyan(name)}`
9458
+ );
9459
+ if (value) {
9460
+ secrets[name] = value;
9461
+ }
9462
+ }
9463
+ for (const name of missingVars) {
9464
+ const value = await promptText(
9465
+ `Enter value for var ${chalk31.cyan(name)}`,
9466
+ ""
9467
+ );
9468
+ if (value) {
9469
+ vars[name] = value;
9470
+ }
9471
+ }
9472
+ return { secrets, vars };
9473
+ }
9491
9474
  async function resolveAgent(agentName) {
9492
9475
  const compose = await getComposeByName(agentName);
9493
9476
  if (!compose) {
@@ -9497,9 +9480,28 @@ async function resolveAgent(agentName) {
9497
9480
  }
9498
9481
  return {
9499
9482
  composeId: compose.id,
9500
- scheduleName: `${agentName}-schedule`
9483
+ scheduleName: `${agentName}-schedule`,
9484
+ composeContent: compose.content
9501
9485
  };
9502
9486
  }
9487
+ async function gatherTiming(frequency, options, defaults) {
9488
+ if (frequency === "once") {
9489
+ const result = await gatherOneTimeSchedule(
9490
+ options.day,
9491
+ options.time,
9492
+ defaults.time
9493
+ );
9494
+ if (!result) return null;
9495
+ return { day: void 0, time: void 0, atTime: result };
9496
+ }
9497
+ const day = await gatherDay(frequency, options.day, defaults.day) ?? void 0;
9498
+ if (day === null && (frequency === "weekly" || frequency === "monthly")) {
9499
+ return null;
9500
+ }
9501
+ const time = await gatherRecurringTime(options.time, defaults.time);
9502
+ if (!time) return null;
9503
+ return { day, time, atTime: void 0 };
9504
+ }
9503
9505
  async function findExistingSchedule(agentName) {
9504
9506
  const { schedules } = await listSchedules();
9505
9507
  return schedules.find((s) => s.composeName === agentName);
@@ -9576,7 +9578,8 @@ function displayDeployResult(agentName, deployResult) {
9576
9578
  }
9577
9579
  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) => {
9578
9580
  try {
9579
- const { composeId, scheduleName } = await resolveAgent(agentName);
9581
+ const { composeId, scheduleName, composeContent } = await resolveAgent(agentName);
9582
+ const requiredConfig = extractRequiredConfiguration(composeContent);
9580
9583
  const existingSchedule = await findExistingSchedule(agentName);
9581
9584
  console.log(
9582
9585
  chalk31.dim(
@@ -9592,36 +9595,12 @@ var setupCommand = new Command28().name("setup").description("Create or edit a s
9592
9595
  console.log(chalk31.dim("Cancelled"));
9593
9596
  return;
9594
9597
  }
9595
- let day;
9596
- let time;
9597
- let atTime;
9598
- if (frequency === "once") {
9599
- const result = await gatherOneTimeSchedule(
9600
- options.day,
9601
- options.time,
9602
- defaults.time
9603
- );
9604
- if (!result) {
9605
- console.log(chalk31.dim("Cancelled"));
9606
- return;
9607
- }
9608
- atTime = result;
9609
- } else {
9610
- day = await gatherDay(frequency, options.day, defaults.day) ?? void 0;
9611
- if (day === null && (frequency === "weekly" || frequency === "monthly")) {
9612
- console.log(chalk31.dim("Cancelled"));
9613
- return;
9614
- }
9615
- const timeResult = await gatherRecurringTime(
9616
- options.time,
9617
- defaults.time
9618
- );
9619
- if (!timeResult) {
9620
- console.log(chalk31.dim("Cancelled"));
9621
- return;
9622
- }
9623
- time = timeResult;
9598
+ const timing = await gatherTiming(frequency, options, defaults);
9599
+ if (!timing) {
9600
+ console.log(chalk31.dim("Cancelled"));
9601
+ return;
9624
9602
  }
9603
+ const { day, time, atTime } = timing;
9625
9604
  const timezone = await gatherTimezone(
9626
9605
  options.timezone,
9627
9606
  existingSchedule?.timezone
@@ -9638,11 +9617,21 @@ var setupCommand = new Command28().name("setup").description("Create or edit a s
9638
9617
  console.log(chalk31.dim("Cancelled"));
9639
9618
  return;
9640
9619
  }
9641
- const vars = await gatherVars(options.var || [], existingSchedule?.vars);
9642
- const secrets = await gatherSecrets(
9620
+ const initialVars = await gatherVars(
9621
+ options.var || [],
9622
+ existingSchedule?.vars
9623
+ );
9624
+ const initialSecrets = await gatherSecrets(
9643
9625
  options.secret || [],
9644
9626
  existingSchedule?.secretNames
9645
9627
  );
9628
+ const keepExistingSecrets = initialSecrets === void 0;
9629
+ const { secrets, vars } = await gatherMissingConfiguration(
9630
+ requiredConfig,
9631
+ initialSecrets ?? {},
9632
+ initialVars ?? {},
9633
+ existingSchedule?.secretNames
9634
+ );
9646
9635
  await buildAndDeploy({
9647
9636
  scheduleName,
9648
9637
  composeId,
@@ -9653,8 +9642,8 @@ var setupCommand = new Command28().name("setup").description("Create or edit a s
9653
9642
  atTime,
9654
9643
  timezone,
9655
9644
  prompt: promptText_,
9656
- vars,
9657
- secrets,
9645
+ vars: Object.keys(vars).length > 0 ? vars : void 0,
9646
+ secrets: keepExistingSecrets ? void 0 : Object.keys(secrets).length > 0 ? secrets : void 0,
9658
9647
  artifactName: options.artifactName
9659
9648
  });
9660
9649
  } catch (error) {
@@ -10537,7 +10526,7 @@ var modelProviderCommand = new Command44().name("model-provider").description("M
10537
10526
 
10538
10527
  // src/index.ts
10539
10528
  var program = new Command45();
10540
- program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("8.0.0");
10529
+ program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("8.0.2");
10541
10530
  program.command("info").description("Display environment information").action(async () => {
10542
10531
  console.log(chalk45.bold("System Information:"));
10543
10532
  console.log(`Node Version: ${process.version}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "8.0.0",
3
+ "version": "8.0.2",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",