@vm0/cli 4.17.0 → 4.19.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 +64 -15
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -13255,9 +13255,9 @@ var createImageRequestSchema = external_exports.object({
13255
13255
  /^[a-zA-Z0-9][a-zA-Z0-9-]{1,62}[a-zA-Z0-9]$/,
13256
13256
  "alias must be 3-64 characters, alphanumeric and hyphens, start/end with alphanumeric"
13257
13257
  ).refine(
13258
- (val) => !val.startsWith("vm0-"),
13258
+ (val) => !val.toLowerCase().startsWith("vm0-"),
13259
13259
  'alias cannot start with "vm0-" (reserved for system templates)'
13260
- ),
13260
+ ).transform((s) => s.toLowerCase()),
13261
13261
  deleteExisting: external_exports.boolean().optional()
13262
13262
  });
13263
13263
  var createImageResponseSchema = external_exports.object({
@@ -13487,10 +13487,10 @@ function getLegacySystemTemplateWarning(legacyFormat) {
13487
13487
  return void 0;
13488
13488
  }
13489
13489
  if (legacyFormat === "vm0-claude-code") {
13490
- return `Warning: "${legacyFormat}" format is deprecated. Use "@vm0/claude-code" instead.`;
13490
+ return `Warning: "${legacyFormat}" format is deprecated. Use "vm0/claude-code" instead.`;
13491
13491
  }
13492
13492
  if (legacyFormat === "vm0-claude-code-dev") {
13493
- return `Warning: "${legacyFormat}" format is deprecated. Use "@vm0/claude-code:dev" instead.`;
13493
+ return `Warning: "${legacyFormat}" format is deprecated. Use "vm0/claude-code:dev" instead.`;
13494
13494
  }
13495
13495
  if (legacyFormat.startsWith("vm0-github-cli")) {
13496
13496
  return `Warning: "${legacyFormat}" is deprecated and will be removed. No replacement available.`;
@@ -16294,7 +16294,7 @@ async function generateEnvPlaceholders(missingVars, envFilePath) {
16294
16294
  }
16295
16295
  }
16296
16296
  var cookCommand = new Command13().name("cook").description("One-click agent preparation and execution from vm0.yaml").argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
16297
- const shouldExit = await checkAndUpgrade("4.17.0", prompt);
16297
+ const shouldExit = await checkAndUpgrade("4.19.0", prompt);
16298
16298
  if (shouldExit) {
16299
16299
  process.exit(0);
16300
16300
  }
@@ -16481,6 +16481,38 @@ import { Command as Command14 } from "commander";
16481
16481
  import chalk16 from "chalk";
16482
16482
  import { readFile as readFile6 } from "fs/promises";
16483
16483
  import { existsSync as existsSync7 } from "fs";
16484
+
16485
+ // src/lib/dockerfile-validator.ts
16486
+ var ALLOWED_INSTRUCTIONS = /* @__PURE__ */ new Set(["FROM", "RUN"]);
16487
+ function validateDockerfile(content) {
16488
+ const errors = [];
16489
+ const lines = content.split("\n");
16490
+ let inContinuation = false;
16491
+ for (let i = 0; i < lines.length; i++) {
16492
+ const line = lines[i];
16493
+ const trimmed = line.trim();
16494
+ if (!inContinuation && !trimmed) continue;
16495
+ if (!inContinuation && trimmed.startsWith("#")) continue;
16496
+ if (inContinuation) {
16497
+ inContinuation = trimmed.endsWith("\\");
16498
+ continue;
16499
+ }
16500
+ const match = trimmed.match(/^([A-Za-z]+)\s/);
16501
+ if (match) {
16502
+ const instruction = match[1].toUpperCase();
16503
+ if (!ALLOWED_INSTRUCTIONS.has(instruction)) {
16504
+ errors.push(`Unsupported instruction: ${instruction} (line ${i + 1})`);
16505
+ }
16506
+ }
16507
+ inContinuation = trimmed.endsWith("\\");
16508
+ }
16509
+ return {
16510
+ valid: errors.length === 0,
16511
+ errors
16512
+ };
16513
+ }
16514
+
16515
+ // src/commands/image/build.ts
16484
16516
  var sleep2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
16485
16517
  var buildCommand = new Command14().name("build").description("Build a custom image from a Dockerfile").requiredOption("-f, --file <path>", "Path to Dockerfile").requiredOption("-n, --name <name>", "Name for the image").option("--delete-existing", "Delete existing image before building").action(
16486
16518
  async (options) => {
@@ -16509,7 +16541,26 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
16509
16541
  try {
16510
16542
  const scope = await apiClient.getScope();
16511
16543
  const dockerfile = await readFile6(file2, "utf8");
16512
- console.log(chalk16.blue(`Building image: @${scope.slug}/${name}`));
16544
+ const validation = validateDockerfile(dockerfile);
16545
+ if (!validation.valid) {
16546
+ console.error(chalk16.red("\u2717 Dockerfile validation failed\n"));
16547
+ for (const error43 of validation.errors) {
16548
+ console.error(chalk16.red(` ${error43}`));
16549
+ }
16550
+ console.error();
16551
+ console.error(
16552
+ chalk16.yellow(
16553
+ " vm0 image build only supports FROM and RUN instructions."
16554
+ )
16555
+ );
16556
+ console.error(
16557
+ chalk16.yellow(
16558
+ " The purpose is to pre-install environment dependencies."
16559
+ )
16560
+ );
16561
+ process.exit(1);
16562
+ }
16563
+ console.log(chalk16.blue(`Building image: ${scope.slug}/${name}`));
16513
16564
  console.log();
16514
16565
  const buildInfo = await apiClient.createImage({
16515
16566
  dockerfile,
@@ -16545,9 +16596,7 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
16545
16596
  if (status === "ready") {
16546
16597
  const shortVersion = formatVersionIdForDisplay(versionId);
16547
16598
  console.log(
16548
- chalk16.green(
16549
- `\u2713 Image built: @${scope.slug}/${name}:${shortVersion}`
16550
- )
16599
+ chalk16.green(`\u2713 Image built: ${scope.slug}/${name}:${shortVersion}`)
16551
16600
  );
16552
16601
  } else {
16553
16602
  console.error(chalk16.red(`\u2717 Build failed`));
@@ -17074,7 +17123,7 @@ var statusCommand3 = new Command20().name("status").description("View current sc
17074
17123
  try {
17075
17124
  const scope = await apiClient.getScope();
17076
17125
  console.log(chalk21.cyan("Scope Information:"));
17077
- console.log(` Slug: ${chalk21.green("@" + scope.slug)}`);
17126
+ console.log(` Slug: ${chalk21.green(scope.slug)}`);
17078
17127
  console.log(` Type: ${scope.type}`);
17079
17128
  if (scope.displayName) {
17080
17129
  console.log(` Display Name: ${scope.displayName}`);
@@ -17119,7 +17168,7 @@ var setCommand = new Command21().name("set").description("Set your scope slug").
17119
17168
  if (existingScope) {
17120
17169
  if (!options.force) {
17121
17170
  console.error(
17122
- chalk22.yellow(`You already have a scope: @${existingScope.slug}`)
17171
+ chalk22.yellow(`You already have a scope: ${existingScope.slug}`)
17123
17172
  );
17124
17173
  console.error();
17125
17174
  console.error("To change your scope, use --force:");
@@ -17133,17 +17182,17 @@ var setCommand = new Command21().name("set").description("Set your scope slug").
17133
17182
  process.exit(1);
17134
17183
  }
17135
17184
  scope = await apiClient.updateScope({ slug, force: true });
17136
- console.log(chalk22.green(`\u2713 Scope updated to @${scope.slug}`));
17185
+ console.log(chalk22.green(`\u2713 Scope updated to ${scope.slug}`));
17137
17186
  } else {
17138
17187
  scope = await apiClient.createScope({
17139
17188
  slug,
17140
17189
  displayName: options.displayName
17141
17190
  });
17142
- console.log(chalk22.green(`\u2713 Scope created: @${scope.slug}`));
17191
+ console.log(chalk22.green(`\u2713 Scope created: ${scope.slug}`));
17143
17192
  }
17144
17193
  console.log();
17145
17194
  console.log("Your images will now be namespaced as:");
17146
- console.log(chalk22.cyan(` @${scope.slug}/<image-name>`));
17195
+ console.log(chalk22.cyan(` ${scope.slug}/<image-name>`));
17147
17196
  } catch (error43) {
17148
17197
  if (error43 instanceof Error) {
17149
17198
  if (error43.message.includes("Not authenticated")) {
@@ -17180,7 +17229,7 @@ var scopeCommand = new Command22().name("scope").description("Manage your scope
17180
17229
 
17181
17230
  // src/index.ts
17182
17231
  var program = new Command23();
17183
- program.name("vm0").description("VM0 CLI - A modern build tool").version("4.17.0");
17232
+ program.name("vm0").description("VM0 CLI - A modern build tool").version("4.19.0");
17184
17233
  program.command("info").description("Display environment information").action(async () => {
17185
17234
  console.log(chalk23.cyan("System Information:"));
17186
17235
  console.log(`Node Version: ${process.version}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "4.17.0",
3
+ "version": "4.19.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",