@vm0/cli 4.27.0 → 4.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +505 -25
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -6,8 +6,8 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // src/index.ts
9
- import { Command as Command24 } from "commander";
10
- import chalk25 from "chalk";
9
+ import { Command as Command25 } from "commander";
10
+ import chalk26 from "chalk";
11
11
 
12
12
  // src/lib/auth.ts
13
13
  import chalk from "chalk";
@@ -12404,14 +12404,16 @@ var createComposeResponseSchema = external_exports.object({
12404
12404
  });
12405
12405
  var composesMainContract = c2.router({
12406
12406
  /**
12407
- * GET /api/agent/composes?name={name}
12407
+ * GET /api/agent/composes?name={name}&scope={scope}
12408
12408
  * Get agent compose by name with HEAD version content
12409
+ * If scope is not provided, uses the authenticated user's default scope
12409
12410
  */
12410
12411
  getByName: {
12411
12412
  method: "GET",
12412
12413
  path: "/api/agent/composes",
12413
12414
  query: external_exports.object({
12414
- name: external_exports.string().min(1, "Missing name query parameter")
12415
+ name: external_exports.string().min(1, "Missing name query parameter"),
12416
+ scope: external_exports.string().optional()
12415
12417
  }),
12416
12418
  responses: {
12417
12419
  200: composeResponseSchema,
@@ -13521,11 +13523,15 @@ var ApiClient = class {
13521
13523
  }
13522
13524
  return apiUrl;
13523
13525
  }
13524
- async getComposeByName(name) {
13526
+ async getComposeByName(name, scope) {
13525
13527
  const baseUrl = await this.getBaseUrl();
13526
13528
  const headers = await this.getHeaders();
13529
+ const params = new URLSearchParams({ name });
13530
+ if (scope) {
13531
+ params.append("scope", scope);
13532
+ }
13527
13533
  const response = await fetch(
13528
- `${baseUrl}/api/agent/composes?name=${encodeURIComponent(name)}`,
13534
+ `${baseUrl}/api/agent/composes?${params.toString()}`,
13529
13535
  {
13530
13536
  method: "GET",
13531
13537
  headers
@@ -14664,19 +14670,20 @@ var composeCommand = new Command().name("compose").description("Create or update
14664
14670
  const response = await apiClient.createOrUpdateCompose({
14665
14671
  content: config2
14666
14672
  });
14673
+ const scopeResponse = await apiClient.getScope();
14667
14674
  const shortVersionId = response.versionId.slice(0, 8);
14675
+ const displayName = `${scopeResponse.slug}/${response.name}`;
14668
14676
  if (response.action === "created") {
14669
- console.log(chalk2.green(`\u2713 Compose created: ${response.name}`));
14677
+ console.log(chalk2.green(`\u2713 Compose created: ${displayName}`));
14670
14678
  } else {
14671
- console.log(chalk2.green(`\u2713 Compose version exists: ${response.name}`));
14679
+ console.log(chalk2.green(`\u2713 Compose version exists: ${displayName}`));
14672
14680
  }
14673
- console.log(chalk2.dim(` Compose ID: ${response.composeId}`));
14674
- console.log(chalk2.dim(` Version: ${shortVersionId}`));
14681
+ console.log(chalk2.dim(` Version: ${shortVersionId}`));
14675
14682
  console.log();
14676
14683
  console.log(" Run your agent:");
14677
14684
  console.log(
14678
14685
  chalk2.cyan(
14679
- ` vm0 run ${response.name} --artifact-name <artifact> "your prompt"`
14686
+ ` vm0 run ${displayName}:${shortVersionId} --artifact-name <artifact> "your prompt"`
14680
14687
  )
14681
14688
  );
14682
14689
  } catch (error43) {
@@ -15390,14 +15397,22 @@ function parseIdentifier(identifier) {
15390
15397
  if (isUUID(identifier)) {
15391
15398
  return { name: identifier };
15392
15399
  }
15393
- const colonIndex = identifier.lastIndexOf(":");
15394
- if (colonIndex > 0 && colonIndex < identifier.length - 1) {
15400
+ let scope;
15401
+ let rest = identifier;
15402
+ const slashIndex = identifier.indexOf("/");
15403
+ if (slashIndex > 0) {
15404
+ scope = identifier.slice(0, slashIndex);
15405
+ rest = identifier.slice(slashIndex + 1);
15406
+ }
15407
+ const colonIndex = rest.indexOf(":");
15408
+ if (colonIndex > 0 && colonIndex < rest.length - 1) {
15395
15409
  return {
15396
- name: identifier.slice(0, colonIndex),
15397
- version: identifier.slice(colonIndex + 1)
15410
+ scope,
15411
+ name: rest.slice(0, colonIndex),
15412
+ version: rest.slice(colonIndex + 1)
15398
15413
  };
15399
15414
  }
15400
- return { name: identifier };
15415
+ return { scope, name: rest };
15401
15416
  }
15402
15417
  async function pollEvents(runId, options) {
15403
15418
  let nextSequence = 0;
@@ -15494,7 +15509,7 @@ function showNextSteps(result) {
15494
15509
  }
15495
15510
  var runCmd = new Command2().name("run").description("Execute an agent").argument(
15496
15511
  "<identifier>",
15497
- "Agent name, config ID, or name:version (e.g., 'my-agent', 'my-agent:abc123', 'my-agent:latest')"
15512
+ "Agent reference: [scope/]name[:version] (e.g., 'my-agent', 'lancy/my-agent:abc123', 'my-agent:latest')"
15498
15513
  ).argument("<prompt>", "Prompt for the agent").option(
15499
15514
  "--vars <KEY=value>",
15500
15515
  "Variables for ${{ vars.xxx }} (repeatable, falls back to env vars and .env)",
@@ -15521,7 +15536,7 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
15521
15536
  const startTimestamp = /* @__PURE__ */ new Date();
15522
15537
  const verbose = options.verbose;
15523
15538
  try {
15524
- const { name, version: version2 } = parseIdentifier(identifier);
15539
+ const { scope, name, version: version2 } = parseIdentifier(identifier);
15525
15540
  let composeId;
15526
15541
  let composeContent;
15527
15542
  if (isUUID(name)) {
@@ -15540,10 +15555,11 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
15540
15555
  }
15541
15556
  } else {
15542
15557
  if (verbose) {
15543
- console.log(chalk5.dim(` Resolving agent name: ${name}`));
15558
+ const displayRef = scope ? `${scope}/${name}` : name;
15559
+ console.log(chalk5.dim(` Resolving agent: ${displayRef}`));
15544
15560
  }
15545
15561
  try {
15546
- const compose = await apiClient.getComposeByName(name);
15562
+ const compose = await apiClient.getComposeByName(name, scope);
15547
15563
  composeId = compose.id;
15548
15564
  composeContent = compose.content;
15549
15565
  if (verbose) {
@@ -15551,7 +15567,8 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
15551
15567
  }
15552
15568
  } catch (error43) {
15553
15569
  if (error43 instanceof Error) {
15554
- console.error(chalk5.red(`\u2717 Agent not found: ${name}`));
15570
+ const displayRef = scope ? `${scope}/${name}` : name;
15571
+ console.error(chalk5.red(`\u2717 Agent not found: ${displayRef}`));
15555
15572
  console.error(
15556
15573
  chalk5.dim(
15557
15574
  " Make sure you've composed the agent with: vm0 compose"
@@ -16797,7 +16814,7 @@ async function autoPullArtifact(runOutput, artifactDir) {
16797
16814
  }
16798
16815
  var cookCmd = new Command13().name("cook").description("One-click agent preparation and execution from vm0.yaml");
16799
16816
  cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
16800
- const shouldExit = await checkAndUpgrade("4.27.0", prompt);
16817
+ const shouldExit = await checkAndUpgrade("4.29.0", prompt);
16801
16818
  if (shouldExit) {
16802
16819
  process.exit(0);
16803
16820
  }
@@ -17935,11 +17952,473 @@ var initCommand3 = new Command23().name("init").description("Initialize a new VM
17935
17952
  console.log(` 3. Run your agent: ${chalk24.cyan('vm0 cook "your prompt"')}`);
17936
17953
  });
17937
17954
 
17955
+ // src/commands/setup-github.ts
17956
+ import { Command as Command24 } from "commander";
17957
+ import chalk25 from "chalk";
17958
+ import * as readline3 from "readline";
17959
+ import { existsSync as existsSync10 } from "fs";
17960
+ import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
17961
+ import { execSync, spawnSync } from "child_process";
17962
+ import { parse as parseYaml4 } from "yaml";
17963
+ function isGhInstalled() {
17964
+ try {
17965
+ execSync("gh --version", { stdio: "ignore" });
17966
+ return true;
17967
+ } catch {
17968
+ return false;
17969
+ }
17970
+ }
17971
+ function isGhAuthenticated() {
17972
+ try {
17973
+ execSync("gh auth status", { stdio: "ignore" });
17974
+ return true;
17975
+ } catch {
17976
+ return false;
17977
+ }
17978
+ }
17979
+ async function checkPrerequisites() {
17980
+ console.log("Checking prerequisites...");
17981
+ if (!isGhInstalled()) {
17982
+ console.log(chalk25.red("\u2717 GitHub CLI (gh) is not installed"));
17983
+ console.log();
17984
+ console.log("GitHub CLI is required for this command.");
17985
+ console.log();
17986
+ console.log(` macOS: ${chalk25.cyan("brew install gh")}`);
17987
+ console.log(` Other: ${chalk25.cyan("https://cli.github.com/")}`);
17988
+ console.log();
17989
+ console.log("After installation, run:");
17990
+ console.log(` ${chalk25.cyan("gh auth login")}`);
17991
+ console.log();
17992
+ console.log("Then try again:");
17993
+ console.log(` ${chalk25.cyan("vm0 setup-github")}`);
17994
+ process.exit(1);
17995
+ }
17996
+ console.log(chalk25.green("\u2713 GitHub CLI (gh) is installed"));
17997
+ if (!isGhAuthenticated()) {
17998
+ console.log(chalk25.red("\u2717 GitHub CLI is not authenticated"));
17999
+ console.log();
18000
+ console.log("Please authenticate GitHub CLI first:");
18001
+ console.log(` ${chalk25.cyan("gh auth login")}`);
18002
+ console.log();
18003
+ console.log("Then try again:");
18004
+ console.log(` ${chalk25.cyan("vm0 setup-github")}`);
18005
+ process.exit(1);
18006
+ }
18007
+ console.log(chalk25.green("\u2713 GitHub CLI is authenticated"));
18008
+ const token = await getToken();
18009
+ if (!token) {
18010
+ console.log(chalk25.red("\u2717 VM0 not authenticated"));
18011
+ console.log();
18012
+ console.log("Please authenticate with VM0 first:");
18013
+ console.log(` ${chalk25.cyan("vm0 auth login")}`);
18014
+ console.log();
18015
+ console.log("Then try again:");
18016
+ console.log(` ${chalk25.cyan("vm0 setup-github")}`);
18017
+ process.exit(1);
18018
+ }
18019
+ console.log(chalk25.green("\u2713 VM0 authenticated"));
18020
+ if (!existsSync10("vm0.yaml")) {
18021
+ console.log(chalk25.red("\u2717 vm0.yaml not found"));
18022
+ console.log();
18023
+ console.log("This command requires a vm0.yaml configuration file.");
18024
+ console.log();
18025
+ console.log("To create one, run:");
18026
+ console.log(` ${chalk25.cyan("vm0 init")}`);
18027
+ console.log();
18028
+ console.log("Then try again:");
18029
+ console.log(` ${chalk25.cyan("vm0 setup-github")}`);
18030
+ process.exit(1);
18031
+ }
18032
+ console.log(chalk25.green("\u2713 vm0.yaml found"));
18033
+ return token;
18034
+ }
18035
+ function generatePublishYaml() {
18036
+ return `name: Publish Agent
18037
+
18038
+ on:
18039
+ push:
18040
+ branches: [main]
18041
+ paths:
18042
+ - 'vm0.yaml'
18043
+ - 'AGENTS.md'
18044
+
18045
+ jobs:
18046
+ publish:
18047
+ runs-on: ubuntu-latest
18048
+ steps:
18049
+ - uses: actions/checkout@v4
18050
+
18051
+ - name: Publish Agent
18052
+ uses: vm0-ai/compose-action@v1
18053
+ id: compose
18054
+ with:
18055
+ vm0-token: \${{ secrets.VM0_TOKEN }}
18056
+
18057
+ - name: Show Results
18058
+ run: |
18059
+ echo "Agent: \${{ steps.compose.outputs.name }}"
18060
+ echo "Compose ID: \${{ steps.compose.outputs.compose-id }}"
18061
+ echo "Version: \${{ steps.compose.outputs.version-id }}"
18062
+ echo "Action: \${{ steps.compose.outputs.action }}"
18063
+ `;
18064
+ }
18065
+ function generateRunYaml(agentName, secrets, vars) {
18066
+ const otherSecrets = secrets.filter((s) => s !== "VM0_TOKEN");
18067
+ const secretsLines = otherSecrets.map((s) => ` ${s}=\${{ secrets.${s} }}`).join("\n");
18068
+ const varsLines = vars.map((v) => ` ${v}=\${{ vars.${v} }}`).join("\n");
18069
+ let yaml = `name: Run Agent
18070
+
18071
+ on:
18072
+ # Uncomment to enable scheduled runs:
18073
+ # schedule:
18074
+ # - cron: '0 1 * * *' # Daily at 9:00 AM UTC+8
18075
+ workflow_dispatch:
18076
+ inputs:
18077
+ prompt:
18078
+ description: 'Prompt for the agent'
18079
+ required: false
18080
+ default: 'do the job'
18081
+
18082
+ jobs:
18083
+ run:
18084
+ runs-on: ubuntu-latest
18085
+ steps:
18086
+ - name: Run Agent
18087
+ uses: vm0-ai/run-action@v1
18088
+ with:
18089
+ agent: ${agentName}
18090
+ prompt: \${{ github.event.inputs.prompt || 'do the job' }}
18091
+ silent: true
18092
+ vm0-token: \${{ secrets.VM0_TOKEN }}`;
18093
+ if (secretsLines) {
18094
+ yaml += `
18095
+ secrets: |
18096
+ ${secretsLines}`;
18097
+ }
18098
+ if (varsLines) {
18099
+ yaml += `
18100
+ vars: |
18101
+ ${varsLines}`;
18102
+ }
18103
+ yaml += "\n";
18104
+ return yaml;
18105
+ }
18106
+ function extractSecretsAndVars(config2) {
18107
+ const secrets = /* @__PURE__ */ new Set();
18108
+ const vars = /* @__PURE__ */ new Set();
18109
+ const refs = extractVariableReferences(config2);
18110
+ const grouped = groupVariablesBySource(refs);
18111
+ for (const ref of grouped.secrets) {
18112
+ secrets.add(ref.name);
18113
+ }
18114
+ for (const ref of grouped.vars) {
18115
+ vars.add(ref.name);
18116
+ }
18117
+ const cfg = config2;
18118
+ const agents = cfg.agents;
18119
+ if (agents) {
18120
+ const agentConfig = Object.values(agents)[0];
18121
+ if (agentConfig) {
18122
+ const expSecrets = agentConfig.experimental_secrets;
18123
+ const expVars = agentConfig.experimental_vars;
18124
+ if (expSecrets) {
18125
+ for (const s of expSecrets) {
18126
+ secrets.add(s);
18127
+ }
18128
+ }
18129
+ if (expVars) {
18130
+ for (const v of expVars) {
18131
+ vars.add(v);
18132
+ }
18133
+ }
18134
+ }
18135
+ }
18136
+ secrets.add("VM0_TOKEN");
18137
+ return {
18138
+ secrets: Array.from(secrets).sort(),
18139
+ vars: Array.from(vars).sort()
18140
+ };
18141
+ }
18142
+ async function promptYesNo(question, defaultYes) {
18143
+ const hint = defaultYes ? "(Y/n)" : "(y/N)";
18144
+ const rl = readline3.createInterface({
18145
+ input: process.stdin,
18146
+ output: process.stdout
18147
+ });
18148
+ return new Promise((resolve2) => {
18149
+ rl.question(chalk25.cyan(`? ${question} ${hint} `), (answer) => {
18150
+ rl.close();
18151
+ const normalized = answer.trim().toLowerCase();
18152
+ if (normalized === "") {
18153
+ resolve2(defaultYes);
18154
+ } else {
18155
+ resolve2(normalized === "y" || normalized === "yes");
18156
+ }
18157
+ });
18158
+ });
18159
+ }
18160
+ function setGitHubSecret(name, value) {
18161
+ const result = spawnSync("gh", ["secret", "set", name], {
18162
+ input: value,
18163
+ stdio: ["pipe", "pipe", "pipe"]
18164
+ });
18165
+ return result.status === 0;
18166
+ }
18167
+ function setGitHubVariable(name, value) {
18168
+ const result = spawnSync("gh", ["variable", "set", name, "--body", value], {
18169
+ stdio: ["pipe", "pipe", "pipe"]
18170
+ });
18171
+ return result.status === 0;
18172
+ }
18173
+ async function detectSecretValues(secrets, vars, vm0Token) {
18174
+ const secretStatuses = secrets.map((name) => {
18175
+ if (name === "VM0_TOKEN") {
18176
+ return { name, found: true, source: "vm0 auth", value: vm0Token };
18177
+ }
18178
+ const envValue = process.env[name];
18179
+ if (envValue) {
18180
+ return { name, found: true, source: "environment", value: envValue };
18181
+ }
18182
+ return { name, found: false };
18183
+ });
18184
+ const varStatuses = vars.map((name) => {
18185
+ const envValue = process.env[name];
18186
+ if (envValue) {
18187
+ return { name, found: true, source: "environment", value: envValue };
18188
+ }
18189
+ return { name, found: false };
18190
+ });
18191
+ return { secretStatuses, varStatuses };
18192
+ }
18193
+ function displaySecretsTable(secretStatuses, varStatuses) {
18194
+ 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");
18195
+ console.log("\u2502 Detected secrets and variables: \u2502");
18196
+ 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");
18197
+ if (secretStatuses.length > 0) {
18198
+ console.log("\u2502 Secrets: \u2502");
18199
+ for (const s of secretStatuses) {
18200
+ const status = s.found ? chalk25.green("\u2713") : chalk25.red("\u2717");
18201
+ const source = s.found ? `(from ${s.source})` : "not found";
18202
+ const paddedName = (s.name + " ").padEnd(23, ".");
18203
+ console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
18204
+ }
18205
+ }
18206
+ if (varStatuses.length > 0) {
18207
+ console.log("\u2502 Variables: \u2502");
18208
+ for (const v of varStatuses) {
18209
+ const status = v.found ? chalk25.green("\u2713") : chalk25.red("\u2717");
18210
+ const source = v.found ? `(from ${v.source})` : "not found";
18211
+ const paddedName = (v.name + " ").padEnd(23, ".");
18212
+ console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
18213
+ }
18214
+ }
18215
+ 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");
18216
+ }
18217
+ function showManualSetupInstructions(secrets, vars) {
18218
+ console.log("Skipped automatic setup. Configure secrets manually:");
18219
+ console.log();
18220
+ console.log(" Step 1: Get your VM0 token");
18221
+ console.log(` ${chalk25.cyan("vm0 auth setup-token")}`);
18222
+ console.log();
18223
+ console.log(" Step 2: Set GitHub secrets");
18224
+ for (const s of secrets) {
18225
+ console.log(` ${chalk25.cyan(`gh secret set ${s}`)}`);
18226
+ }
18227
+ if (vars.length > 0) {
18228
+ console.log();
18229
+ console.log(" Step 3: Set GitHub variables");
18230
+ for (const v of vars) {
18231
+ console.log(` ${chalk25.cyan(`gh variable set ${v}`)}`);
18232
+ }
18233
+ }
18234
+ }
18235
+ function showSuccessMessage() {
18236
+ 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");
18237
+ console.log("\u2502 \u2713 GitHub Actions setup complete! \u2502");
18238
+ 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");
18239
+ console.log("\u2502 Workflows created: \u2502");
18240
+ console.log("\u2502 \u2022 .github/workflows/publish.yml \u2502");
18241
+ console.log("\u2502 \u2022 .github/workflows/run.yml \u2502");
18242
+ console.log("\u2502 \u2502");
18243
+ console.log("\u2502 Next steps: \u2502");
18244
+ console.log("\u2502 1. Commit and push the workflow files \u2502");
18245
+ console.log("\u2502 2. Push to main branch to trigger publish \u2502");
18246
+ 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");
18247
+ }
18248
+ function showPartialSuccessMessage(missingSecrets, missingVars) {
18249
+ 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");
18250
+ console.log("\u2502 \u26A0 Setup partially complete \u2502");
18251
+ 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");
18252
+ console.log("\u2502 Missing secrets - set them manually: \u2502");
18253
+ for (const s of missingSecrets) {
18254
+ console.log(`\u2502 gh secret set ${s.padEnd(40)}\u2502`);
18255
+ }
18256
+ for (const v of missingVars) {
18257
+ console.log(`\u2502 gh variable set ${v.padEnd(38)}\u2502`);
18258
+ }
18259
+ 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");
18260
+ }
18261
+ function showWorkflowsCreatedMessage() {
18262
+ 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");
18263
+ console.log("\u2502 \u2713 Workflow files created! \u2502");
18264
+ 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");
18265
+ console.log("\u2502 \u2022 .github/workflows/publish.yml \u2502");
18266
+ console.log("\u2502 \u2022 .github/workflows/run.yml \u2502");
18267
+ console.log("\u2502 \u2502");
18268
+ console.log("\u2502 Next steps: \u2502");
18269
+ console.log("\u2502 1. Set GitHub secrets (see commands above) \u2502");
18270
+ console.log("\u2502 2. Commit and push the workflow files \u2502");
18271
+ console.log("\u2502 3. Push to main branch to trigger publish \u2502");
18272
+ 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");
18273
+ }
18274
+ var setupGithubCommand = new Command24().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(
18275
+ async (options) => {
18276
+ const vm0Token = await checkPrerequisites();
18277
+ if (!vm0Token) {
18278
+ process.exit(1);
18279
+ }
18280
+ console.log();
18281
+ console.log("Analyzing vm0.yaml...");
18282
+ const content = await readFile8("vm0.yaml", "utf8");
18283
+ const config2 = parseYaml4(content);
18284
+ const agents = config2.agents;
18285
+ const agentName = Object.keys(agents)[0];
18286
+ console.log(chalk25.green(`\u2713 Agent: ${agentName}`));
18287
+ const { secrets, vars } = extractSecretsAndVars(config2);
18288
+ console.log(
18289
+ chalk25.green(
18290
+ `\u2713 Found ${secrets.length} secrets, ${vars.length} variables`
18291
+ )
18292
+ );
18293
+ console.log();
18294
+ const publishPath = ".github/workflows/publish.yml";
18295
+ const runPath = ".github/workflows/run.yml";
18296
+ const existingFiles = [];
18297
+ if (existsSync10(publishPath)) existingFiles.push(publishPath);
18298
+ if (existsSync10(runPath)) existingFiles.push(runPath);
18299
+ if (existingFiles.length > 0 && !options.force) {
18300
+ console.log(chalk25.yellow("\u26A0 Existing workflow files detected:"));
18301
+ for (const file2 of existingFiles) {
18302
+ console.log(` \u2022 ${file2}`);
18303
+ }
18304
+ console.log();
18305
+ if (!options.yes) {
18306
+ const overwrite = await promptYesNo(
18307
+ "Overwrite existing files?",
18308
+ false
18309
+ );
18310
+ if (!overwrite) {
18311
+ console.log();
18312
+ console.log("Aborted. To force overwrite, run:");
18313
+ console.log(` ${chalk25.cyan("vm0 setup-github --force")}`);
18314
+ process.exit(0);
18315
+ }
18316
+ }
18317
+ console.log();
18318
+ }
18319
+ console.log("Creating workflow files...");
18320
+ await mkdir7(".github/workflows", { recursive: true });
18321
+ await writeFile8(publishPath, generatePublishYaml());
18322
+ const publishStatus = existingFiles.includes(publishPath) ? "Overwrote" : "Created";
18323
+ console.log(chalk25.green(`\u2713 ${publishStatus} ${publishPath}`));
18324
+ await writeFile8(runPath, generateRunYaml(agentName, secrets, vars));
18325
+ const runStatus = existingFiles.includes(runPath) ? "Overwrote" : "Created";
18326
+ console.log(chalk25.green(`\u2713 ${runStatus} ${runPath}`));
18327
+ console.log();
18328
+ if (options.skipSecrets) {
18329
+ console.log(chalk25.green("\u2713 Done (secrets setup skipped)"));
18330
+ return;
18331
+ }
18332
+ const { secretStatuses, varStatuses } = await detectSecretValues(
18333
+ secrets,
18334
+ vars,
18335
+ vm0Token
18336
+ );
18337
+ displaySecretsTable(secretStatuses, varStatuses);
18338
+ console.log();
18339
+ const hasFoundValues = secretStatuses.some((s) => s.found) || varStatuses.some((v) => v.found);
18340
+ if (!hasFoundValues) {
18341
+ console.log("No secret/variable values found in environment.");
18342
+ console.log();
18343
+ showManualSetupInstructions(secrets, vars);
18344
+ console.log();
18345
+ showWorkflowsCreatedMessage();
18346
+ return;
18347
+ }
18348
+ let shouldSetup = options.yes;
18349
+ if (!shouldSetup) {
18350
+ shouldSetup = await promptYesNo(
18351
+ "Set up GitHub secrets/variables automatically?",
18352
+ true
18353
+ );
18354
+ }
18355
+ if (!shouldSetup) {
18356
+ console.log();
18357
+ showManualSetupInstructions(secrets, vars);
18358
+ console.log();
18359
+ showWorkflowsCreatedMessage();
18360
+ return;
18361
+ }
18362
+ console.log();
18363
+ console.log("Setting secrets...");
18364
+ const failedSecrets = [];
18365
+ for (const s of secretStatuses) {
18366
+ if (s.found && s.value) {
18367
+ const success2 = setGitHubSecret(s.name, s.value);
18368
+ if (success2) {
18369
+ console.log(` ${chalk25.green("\u2713")} ${s.name}`);
18370
+ } else {
18371
+ console.log(` ${chalk25.red("\u2717")} ${s.name} (failed)`);
18372
+ failedSecrets.push(s.name);
18373
+ }
18374
+ } else {
18375
+ console.log(
18376
+ ` ${chalk25.yellow("\u26A0")} ${s.name} (skipped - not found)`
18377
+ );
18378
+ }
18379
+ }
18380
+ const failedVars = [];
18381
+ if (varStatuses.length > 0) {
18382
+ console.log();
18383
+ console.log("Setting variables...");
18384
+ for (const v of varStatuses) {
18385
+ if (v.found && v.value) {
18386
+ const success2 = setGitHubVariable(v.name, v.value);
18387
+ if (success2) {
18388
+ console.log(` ${chalk25.green("\u2713")} ${v.name}`);
18389
+ } else {
18390
+ console.log(` ${chalk25.red("\u2717")} ${v.name} (failed)`);
18391
+ failedVars.push(v.name);
18392
+ }
18393
+ } else {
18394
+ console.log(
18395
+ ` ${chalk25.yellow("\u26A0")} ${v.name} (skipped - not found)`
18396
+ );
18397
+ }
18398
+ }
18399
+ }
18400
+ console.log();
18401
+ const missingSecrets = [
18402
+ ...secretStatuses.filter((s) => !s.found).map((s) => s.name),
18403
+ ...failedSecrets
18404
+ ];
18405
+ const missingVars = [
18406
+ ...varStatuses.filter((v) => !v.found).map((v) => v.name),
18407
+ ...failedVars
18408
+ ];
18409
+ if (missingSecrets.length === 0 && missingVars.length === 0) {
18410
+ showSuccessMessage();
18411
+ } else {
18412
+ showPartialSuccessMessage(missingSecrets, missingVars);
18413
+ }
18414
+ }
18415
+ );
18416
+
17938
18417
  // src/index.ts
17939
- var program = new Command24();
17940
- program.name("vm0").description("VM0 CLI - A modern build tool").version("4.27.0");
18418
+ var program = new Command25();
18419
+ program.name("vm0").description("VM0 CLI - A modern build tool").version("4.29.0");
17941
18420
  program.command("info").description("Display environment information").action(async () => {
17942
- console.log(chalk25.bold("System Information:"));
18421
+ console.log(chalk26.bold("System Information:"));
17943
18422
  console.log(`Node Version: ${process.version}`);
17944
18423
  console.log(`Platform: ${process.platform}`);
17945
18424
  console.log(`Architecture: ${process.arch}`);
@@ -17968,6 +18447,7 @@ program.addCommand(imageCommand);
17968
18447
  program.addCommand(logsCommand);
17969
18448
  program.addCommand(scopeCommand);
17970
18449
  program.addCommand(initCommand3);
18450
+ program.addCommand(setupGithubCommand);
17971
18451
  if (process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("vm0")) {
17972
18452
  program.parse();
17973
18453
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "4.27.0",
3
+ "version": "4.29.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",