@vm0/cli 3.4.0 → 3.5.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 +172 -82
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -12147,8 +12147,8 @@ var helloContract = c.router({
12147
12147
  var FOO = "hello";
12148
12148
 
12149
12149
  // src/index.ts
12150
- import { Command as Command11 } from "commander";
12151
- import chalk11 from "chalk";
12150
+ import { Command as Command15 } from "commander";
12151
+ import chalk14 from "chalk";
12152
12152
 
12153
12153
  // src/lib/auth.ts
12154
12154
  import chalk from "chalk";
@@ -12352,6 +12352,19 @@ var ApiClient = class {
12352
12352
  }
12353
12353
  return await response.json();
12354
12354
  }
12355
+ async getComposeById(id) {
12356
+ const baseUrl = await this.getBaseUrl();
12357
+ const headers = await this.getHeaders();
12358
+ const response = await fetch(`${baseUrl}/api/agent/composes/${id}`, {
12359
+ method: "GET",
12360
+ headers
12361
+ });
12362
+ if (!response.ok) {
12363
+ const error43 = await response.json();
12364
+ throw new Error(error43.error?.message || `Compose not found: ${id}`);
12365
+ }
12366
+ return await response.json();
12367
+ }
12355
12368
  /**
12356
12369
  * Resolve a version specifier to a full version ID
12357
12370
  * Supports: "latest", full hash (64 chars), or hash prefix (8+ chars)
@@ -12389,6 +12402,7 @@ var ApiClient = class {
12389
12402
  /**
12390
12403
  * Create a run with unified request format
12391
12404
  * Supports new runs, checkpoint resume, and session continue
12405
+ * Note: Environment variables are expanded server-side from templateVars
12392
12406
  */
12393
12407
  async createRun(body) {
12394
12408
  const baseUrl = await this.getBaseUrl();
@@ -12479,6 +12493,27 @@ var ApiClient = class {
12479
12493
  body: options?.body
12480
12494
  });
12481
12495
  }
12496
+ /**
12497
+ * Generic DELETE request
12498
+ */
12499
+ async delete(path9) {
12500
+ const baseUrl = await this.getBaseUrl();
12501
+ const token = await getToken();
12502
+ if (!token) {
12503
+ throw new Error("Not authenticated. Run: vm0 auth login");
12504
+ }
12505
+ const headers = {
12506
+ Authorization: `Bearer ${token}`
12507
+ };
12508
+ const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
12509
+ if (bypassSecret) {
12510
+ headers["x-vercel-protection-bypass"] = bypassSecret;
12511
+ }
12512
+ return fetch(`${baseUrl}${path9}`, {
12513
+ method: "DELETE",
12514
+ headers
12515
+ });
12516
+ }
12482
12517
  };
12483
12518
  var apiClient = new ApiClient();
12484
12519
 
@@ -12560,6 +12595,23 @@ function validateAgentCompose(config2) {
12560
12595
  error: "Missing or invalid agent.provider (must be a string)"
12561
12596
  };
12562
12597
  }
12598
+ if (agent.environment !== void 0) {
12599
+ if (agent.environment === null || typeof agent.environment !== "object" || Array.isArray(agent.environment)) {
12600
+ return {
12601
+ valid: false,
12602
+ error: "agent.environment must be an object with string keys and values"
12603
+ };
12604
+ }
12605
+ const env = agent.environment;
12606
+ for (const [key, value] of Object.entries(env)) {
12607
+ if (typeof value !== "string") {
12608
+ return {
12609
+ valid: false,
12610
+ error: `agent.environment.${key} must be a string`
12611
+ };
12612
+ }
12613
+ }
12614
+ }
12563
12615
  const agentVolumes = agent.volumes;
12564
12616
  if (agentVolumes && Array.isArray(agentVolumes) && agentVolumes.length > 0) {
12565
12617
  const volumesSection = cfg.volumes;
@@ -12600,62 +12652,6 @@ function validateAgentCompose(config2) {
12600
12652
  return { valid: true };
12601
12653
  }
12602
12654
 
12603
- // src/lib/env-expander.ts
12604
- function expandEnvVars(value) {
12605
- return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
12606
- return process.env[varName] ?? "";
12607
- });
12608
- }
12609
- function extractEnvVarReferences(obj) {
12610
- const varNames = /* @__PURE__ */ new Set();
12611
- function scan(value) {
12612
- if (typeof value === "string") {
12613
- const matches = value.matchAll(/\$\{([^}]+)\}/g);
12614
- for (const match of matches) {
12615
- const varName = match[1];
12616
- if (varName) {
12617
- varNames.add(varName);
12618
- }
12619
- }
12620
- } else if (Array.isArray(value)) {
12621
- for (const item of value) {
12622
- scan(item);
12623
- }
12624
- } else if (value !== null && typeof value === "object") {
12625
- for (const val of Object.values(value)) {
12626
- scan(val);
12627
- }
12628
- }
12629
- }
12630
- scan(obj);
12631
- return Array.from(varNames);
12632
- }
12633
- function validateEnvVars(varNames) {
12634
- const missing = [];
12635
- for (const varName of varNames) {
12636
- if (process.env[varName] === void 0) {
12637
- missing.push(varName);
12638
- }
12639
- }
12640
- return missing;
12641
- }
12642
- function expandEnvVarsInObject(obj) {
12643
- if (typeof obj === "string") {
12644
- return expandEnvVars(obj);
12645
- }
12646
- if (Array.isArray(obj)) {
12647
- return obj.map((item) => expandEnvVarsInObject(item));
12648
- }
12649
- if (obj !== null && typeof obj === "object") {
12650
- const result = {};
12651
- for (const [key, value] of Object.entries(obj)) {
12652
- result[key] = expandEnvVarsInObject(value);
12653
- }
12654
- return result;
12655
- }
12656
- return obj;
12657
- }
12658
-
12659
12655
  // src/commands/build.ts
12660
12656
  var buildCommand = new Command().name("build").description("Create or update agent compose").argument("<config-file>", "Path to config YAML file").action(async (configFile) => {
12661
12657
  try {
@@ -12674,24 +12670,6 @@ var buildCommand = new Command().name("build").description("Create or update age
12674
12670
  }
12675
12671
  process.exit(1);
12676
12672
  }
12677
- const referencedVars = extractEnvVarReferences(config2);
12678
- const missingVars = validateEnvVars(referencedVars);
12679
- if (missingVars.length > 0) {
12680
- console.error(chalk2.red("\u2717 Missing required environment variables:"));
12681
- for (const varName of missingVars) {
12682
- console.error(chalk2.red(` - ${varName}`));
12683
- }
12684
- console.error();
12685
- console.error(
12686
- chalk2.gray("Please set these variables before running 'vm0 build'.")
12687
- );
12688
- console.error(chalk2.gray("Example:"));
12689
- for (const varName of missingVars) {
12690
- console.error(chalk2.gray(` export ${varName}=your-value`));
12691
- }
12692
- process.exit(1);
12693
- }
12694
- config2 = expandEnvVarsInObject(config2);
12695
12673
  const validation = validateAgentCompose(config2);
12696
12674
  if (!validation.valid) {
12697
12675
  console.error(chalk2.red(`\u2717 ${validation.error}`));
@@ -13246,7 +13224,7 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
13246
13224
  if (isUUID(name)) {
13247
13225
  composeId = name;
13248
13226
  if (verbose) {
13249
- console.log(chalk4.gray(` Using compose ID: ${composeId}`));
13227
+ console.log(chalk4.gray(` Using compose ID: ${identifier}`));
13250
13228
  }
13251
13229
  } else {
13252
13230
  if (verbose) {
@@ -14204,15 +14182,126 @@ var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact
14204
14182
  // src/commands/artifact/index.ts
14205
14183
  var artifactCommand = new Command10().name("artifact").description("Manage cloud artifacts (work products)").addCommand(initCommand2).addCommand(pushCommand2).addCommand(pullCommand2);
14206
14184
 
14185
+ // src/commands/secret/index.ts
14186
+ import { Command as Command14 } from "commander";
14187
+
14188
+ // src/commands/secret/set.ts
14189
+ import { Command as Command11 } from "commander";
14190
+ import chalk11 from "chalk";
14191
+ var setCommand = new Command11().name("set").description("Create or update a secret").argument(
14192
+ "<name>",
14193
+ "Secret name (must start with letter, alphanumeric and underscores only)"
14194
+ ).argument("<value>", "Secret value").action(async (name, value) => {
14195
+ try {
14196
+ const nameRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;
14197
+ if (!nameRegex.test(name)) {
14198
+ console.error(chalk11.red("\u2717 Invalid secret name"));
14199
+ console.error(
14200
+ chalk11.gray(
14201
+ " Must start with a letter and contain only letters, numbers, and underscores"
14202
+ )
14203
+ );
14204
+ process.exit(1);
14205
+ }
14206
+ if (name.length > 255) {
14207
+ console.error(chalk11.red("\u2717 Secret name too long (max 255 characters)"));
14208
+ process.exit(1);
14209
+ }
14210
+ const response = await apiClient.post("/api/secrets", {
14211
+ body: JSON.stringify({ name, value })
14212
+ });
14213
+ if (!response.ok) {
14214
+ const error43 = await response.json();
14215
+ throw new Error(error43.error?.message || "Failed to set secret");
14216
+ }
14217
+ const result = await response.json();
14218
+ if (result.action === "created") {
14219
+ console.log(chalk11.green(`\u2713 Secret created: ${name}`));
14220
+ } else {
14221
+ console.log(chalk11.green(`\u2713 Secret updated: ${name}`));
14222
+ }
14223
+ } catch (error43) {
14224
+ console.error(chalk11.red("\u2717 Failed to set secret"));
14225
+ if (error43 instanceof Error) {
14226
+ console.error(chalk11.gray(` ${error43.message}`));
14227
+ }
14228
+ process.exit(1);
14229
+ }
14230
+ });
14231
+
14232
+ // src/commands/secret/list.ts
14233
+ import { Command as Command12 } from "commander";
14234
+ import chalk12 from "chalk";
14235
+ var listCommand = new Command12().name("list").alias("ls").description("List all secrets (names only)").action(async () => {
14236
+ try {
14237
+ const response = await apiClient.get("/api/secrets");
14238
+ if (!response.ok) {
14239
+ const error43 = await response.json();
14240
+ throw new Error(error43.error?.message || "Failed to list secrets");
14241
+ }
14242
+ const result = await response.json();
14243
+ if (result.secrets.length === 0) {
14244
+ console.log(chalk12.gray("No secrets found"));
14245
+ console.log(
14246
+ chalk12.gray(" Create one with: vm0 secret set <name> <value>")
14247
+ );
14248
+ return;
14249
+ }
14250
+ console.log(chalk12.cyan("Secrets:"));
14251
+ for (const secret of result.secrets) {
14252
+ const updatedAt = new Date(secret.updatedAt).toLocaleDateString();
14253
+ console.log(
14254
+ ` ${chalk12.white(secret.name)} ${chalk12.gray(`(updated: ${updatedAt})`)}`
14255
+ );
14256
+ }
14257
+ console.log(chalk12.gray(`
14258
+ Total: ${result.secrets.length} secret(s)`));
14259
+ } catch (error43) {
14260
+ console.error(chalk12.red("\u2717 Failed to list secrets"));
14261
+ if (error43 instanceof Error) {
14262
+ console.error(chalk12.gray(` ${error43.message}`));
14263
+ }
14264
+ process.exit(1);
14265
+ }
14266
+ });
14267
+
14268
+ // src/commands/secret/delete.ts
14269
+ import { Command as Command13 } from "commander";
14270
+ import chalk13 from "chalk";
14271
+ var deleteCommand = new Command13().name("delete").alias("rm").description("Delete a secret").argument("<name>", "Secret name to delete").action(async (name) => {
14272
+ try {
14273
+ const response = await apiClient.delete(
14274
+ `/api/secrets?name=${encodeURIComponent(name)}`
14275
+ );
14276
+ if (!response.ok) {
14277
+ const error43 = await response.json();
14278
+ throw new Error(error43.error?.message || `Secret not found: ${name}`);
14279
+ }
14280
+ const result = await response.json();
14281
+ if (result.deleted) {
14282
+ console.log(chalk13.green(`\u2713 Secret deleted: ${name}`));
14283
+ }
14284
+ } catch (error43) {
14285
+ console.error(chalk13.red("\u2717 Failed to delete secret"));
14286
+ if (error43 instanceof Error) {
14287
+ console.error(chalk13.gray(` ${error43.message}`));
14288
+ }
14289
+ process.exit(1);
14290
+ }
14291
+ });
14292
+
14293
+ // src/commands/secret/index.ts
14294
+ var secretCommand = new Command14().name("secret").description("Manage secrets for agent compose configurations").addCommand(setCommand).addCommand(listCommand).addCommand(deleteCommand);
14295
+
14207
14296
  // src/index.ts
14208
- var program = new Command11();
14209
- program.name("vm0").description("VM0 CLI - A modern build tool").version("3.4.0");
14297
+ var program = new Command15();
14298
+ program.name("vm0").description("VM0 CLI - A modern build tool").version("3.5.0");
14210
14299
  program.command("hello").description("Say hello from the App").action(() => {
14211
- console.log(chalk11.blue("Welcome to the VM0 CLI!"));
14212
- console.log(chalk11.green(`Core says: ${FOO}`));
14300
+ console.log(chalk14.blue("Welcome to the VM0 CLI!"));
14301
+ console.log(chalk14.green(`Core says: ${FOO}`));
14213
14302
  });
14214
14303
  program.command("info").description("Display environment information").action(async () => {
14215
- console.log(chalk11.cyan("System Information:"));
14304
+ console.log(chalk14.cyan("System Information:"));
14216
14305
  console.log(`Node Version: ${process.version}`);
14217
14306
  console.log(`Platform: ${process.platform}`);
14218
14307
  console.log(`Architecture: ${process.arch}`);
@@ -14233,6 +14322,7 @@ program.addCommand(buildCommand);
14233
14322
  program.addCommand(runCommand);
14234
14323
  program.addCommand(volumeCommand);
14235
14324
  program.addCommand(artifactCommand);
14325
+ program.addCommand(secretCommand);
14236
14326
  if (process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("vm0")) {
14237
14327
  program.parse();
14238
14328
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "3.4.0",
3
+ "version": "3.5.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",