@vm0/cli 4.18.0 → 4.20.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 +129 -49
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -12357,7 +12357,8 @@ var volumeConfigSchema = external_exports.object({
12357
12357
  });
12358
12358
  var agentDefinitionSchema = external_exports.object({
12359
12359
  description: external_exports.string().optional(),
12360
- image: external_exports.string().min(1, "Image is required"),
12360
+ image: external_exports.string().optional(),
12361
+ // Optional when provider supports auto-config
12361
12362
  provider: external_exports.string().min(1, "Provider is required"),
12362
12363
  volumes: external_exports.array(external_exports.string()).optional(),
12363
12364
  working_dir: external_exports.string().optional(),
@@ -12371,15 +12372,15 @@ var agentDefinitionSchema = external_exports.object({
12371
12372
  */
12372
12373
  beta_network_security: external_exports.boolean().optional().default(false),
12373
12374
  /**
12374
- * Path to system prompt file (e.g., AGENTS.md).
12375
+ * Path to instructions file (e.g., AGENTS.md).
12375
12376
  * Auto-uploaded as volume and mounted at /home/user/.claude/CLAUDE.md
12376
12377
  */
12377
- beta_system_prompt: external_exports.string().optional(),
12378
+ instructions: external_exports.string().optional(),
12378
12379
  /**
12379
- * Array of GitHub tree URLs for system skills.
12380
+ * Array of GitHub tree URLs for agent skills.
12380
12381
  * Each skill is auto-downloaded and mounted at /home/user/.claude/skills/{skillName}/
12381
12382
  */
12382
- beta_system_skills: external_exports.array(external_exports.string()).optional()
12383
+ skills: external_exports.array(external_exports.string()).optional()
12383
12384
  });
12384
12385
  var agentComposeContentSchema = external_exports.object({
12385
12386
  version: external_exports.string().min(1, "Version is required"),
@@ -13507,6 +13508,14 @@ function formatVersionIdForDisplay(versionId) {
13507
13508
  return versionId.slice(0, VERSION_ID_DISPLAY_LENGTH);
13508
13509
  }
13509
13510
 
13511
+ // ../../packages/core/src/storage-names.ts
13512
+ function getInstructionsStorageName(agentName) {
13513
+ return `agent-instructions@${agentName}`;
13514
+ }
13515
+ function getSkillStorageName(fullPath) {
13516
+ return `agent-skills@${fullPath}`;
13517
+ }
13518
+
13510
13519
  // src/lib/api-client.ts
13511
13520
  var ApiClient = class {
13512
13521
  async getHeaders() {
@@ -13886,7 +13895,11 @@ var apiClient = new ApiClient();
13886
13895
  // src/lib/provider-config.ts
13887
13896
  var PROVIDER_DEFAULTS = {
13888
13897
  "claude-code": {
13889
- workingDir: "/home/user/workspace"
13898
+ workingDir: "/home/user/workspace",
13899
+ image: {
13900
+ production: "vm0/claude-code:latest",
13901
+ development: "vm0/claude-code:dev"
13902
+ }
13890
13903
  }
13891
13904
  };
13892
13905
  function getProviderDefaults(provider) {
@@ -13895,6 +13908,12 @@ function getProviderDefaults(provider) {
13895
13908
  function isProviderSupported(provider) {
13896
13909
  return provider in PROVIDER_DEFAULTS;
13897
13910
  }
13911
+ function getDefaultImage(provider) {
13912
+ const defaults = PROVIDER_DEFAULTS[provider];
13913
+ if (!defaults) return void 0;
13914
+ const isProduction = process.env.NODE_ENV === "production";
13915
+ return isProduction ? defaults.image.production : defaults.image.development;
13916
+ }
13898
13917
 
13899
13918
  // src/lib/yaml-validator.ts
13900
13919
  function validateAgentName(name) {
@@ -13967,10 +13986,16 @@ function validateAgentCompose(config2) {
13967
13986
  };
13968
13987
  }
13969
13988
  const providerIsSupported = isProviderSupported(agent.provider);
13970
- if (!agent.image || typeof agent.image !== "string") {
13989
+ if (agent.image !== void 0 && typeof agent.image !== "string") {
13990
+ return {
13991
+ valid: false,
13992
+ error: "agent.image must be a string if provided"
13993
+ };
13994
+ }
13995
+ if (!agent.image && !providerIsSupported) {
13971
13996
  return {
13972
13997
  valid: false,
13973
- error: "Missing or invalid agent.image (must be a string)"
13998
+ error: "Missing agent.image (required when provider is not auto-configured)"
13974
13999
  };
13975
14000
  }
13976
14001
  if (agent.working_dir !== void 0 && typeof agent.working_dir !== "string") {
@@ -13985,38 +14010,38 @@ function validateAgentCompose(config2) {
13985
14010
  error: "Missing agent.working_dir (required when provider is not auto-configured)"
13986
14011
  };
13987
14012
  }
13988
- if (agent.beta_system_prompt !== void 0) {
13989
- if (typeof agent.beta_system_prompt !== "string") {
14013
+ if (agent.instructions !== void 0) {
14014
+ if (typeof agent.instructions !== "string") {
13990
14015
  return {
13991
14016
  valid: false,
13992
- error: "agent.beta_system_prompt must be a string (path to AGENTS.md file)"
14017
+ error: "agent.instructions must be a string (path to instructions file)"
13993
14018
  };
13994
14019
  }
13995
- if (agent.beta_system_prompt.length === 0) {
14020
+ if (agent.instructions.length === 0) {
13996
14021
  return {
13997
14022
  valid: false,
13998
- error: "agent.beta_system_prompt cannot be empty"
14023
+ error: "agent.instructions cannot be empty"
13999
14024
  };
14000
14025
  }
14001
14026
  }
14002
- if (agent.beta_system_skills !== void 0) {
14003
- if (!Array.isArray(agent.beta_system_skills)) {
14027
+ if (agent.skills !== void 0) {
14028
+ if (!Array.isArray(agent.skills)) {
14004
14029
  return {
14005
14030
  valid: false,
14006
- error: "agent.beta_system_skills must be an array of GitHub tree URLs"
14031
+ error: "agent.skills must be an array of GitHub tree URLs"
14007
14032
  };
14008
14033
  }
14009
- for (const skillUrl of agent.beta_system_skills) {
14034
+ for (const skillUrl of agent.skills) {
14010
14035
  if (typeof skillUrl !== "string") {
14011
14036
  return {
14012
14037
  valid: false,
14013
- error: "Each beta_system_skill must be a string URL"
14038
+ error: "Each skill must be a string URL"
14014
14039
  };
14015
14040
  }
14016
14041
  if (!validateGitHubTreeUrl(skillUrl)) {
14017
14042
  return {
14018
14043
  valid: false,
14019
- error: `Invalid beta_system_skill URL: ${skillUrl}. Expected format: https://github.com/{owner}/{repo}/tree/{branch}/{path}`
14044
+ error: `Invalid skill URL: ${skillUrl}. Expected format: https://github.com/{owner}/{repo}/tree/{branch}/{path}`
14020
14045
  };
14021
14046
  }
14022
14047
  }
@@ -14117,11 +14142,8 @@ function parseGitHubTreeUrl(url2) {
14117
14142
  fullPath
14118
14143
  };
14119
14144
  }
14120
- function getSkillStorageName(parsed) {
14121
- return `system-skill@${parsed.fullPath}`;
14122
- }
14123
- function getSystemPromptStorageName(composeName) {
14124
- return `system-prompt@${composeName}`;
14145
+ function getSkillStorageName2(parsed) {
14146
+ return getSkillStorageName(parsed.fullPath);
14125
14147
  }
14126
14148
  async function downloadGitHubSkill(parsed, destDir) {
14127
14149
  const repoUrl = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
@@ -14457,16 +14479,16 @@ async function directUpload(storageName, storageType, cwd, options) {
14457
14479
  }
14458
14480
 
14459
14481
  // src/lib/system-storage.ts
14460
- async function uploadSystemPrompt(agentName, promptFilePath, basePath) {
14461
- const storageName = getSystemPromptStorageName(agentName);
14462
- const absolutePath = path4.isAbsolute(promptFilePath) ? promptFilePath : path4.join(basePath, promptFilePath);
14482
+ async function uploadInstructions(agentName, instructionsFilePath, basePath) {
14483
+ const storageName = getInstructionsStorageName(agentName);
14484
+ const absolutePath = path4.isAbsolute(instructionsFilePath) ? instructionsFilePath : path4.join(basePath, instructionsFilePath);
14463
14485
  const content = await fs4.readFile(absolutePath, "utf8");
14464
- const tmpDir = await fs4.mkdtemp(path4.join(os3.tmpdir(), "vm0-prompt-"));
14465
- const promptDir = path4.join(tmpDir, "prompt");
14466
- await fs4.mkdir(promptDir);
14467
- await fs4.writeFile(path4.join(promptDir, "CLAUDE.md"), content);
14486
+ const tmpDir = await fs4.mkdtemp(path4.join(os3.tmpdir(), "vm0-instructions-"));
14487
+ const instructionsDir = path4.join(tmpDir, "instructions");
14488
+ await fs4.mkdir(instructionsDir);
14489
+ await fs4.writeFile(path4.join(instructionsDir, "CLAUDE.md"), content);
14468
14490
  try {
14469
- const result = await directUpload(storageName, "volume", promptDir);
14491
+ const result = await directUpload(storageName, "volume", instructionsDir);
14470
14492
  return {
14471
14493
  name: storageName,
14472
14494
  versionId: result.versionId,
@@ -14476,9 +14498,9 @@ async function uploadSystemPrompt(agentName, promptFilePath, basePath) {
14476
14498
  await fs4.rm(tmpDir, { recursive: true, force: true });
14477
14499
  }
14478
14500
  }
14479
- async function uploadSystemSkill(skillUrl) {
14501
+ async function uploadSkill(skillUrl) {
14480
14502
  const parsed = parseGitHubTreeUrl(skillUrl);
14481
- const storageName = getSkillStorageName(parsed);
14503
+ const storageName = getSkillStorageName2(parsed);
14482
14504
  const tmpDir = await fs4.mkdtemp(path4.join(os3.tmpdir(), "vm0-skill-"));
14483
14505
  try {
14484
14506
  const skillDir = await downloadGitHubSkill(parsed, tmpDir);
@@ -14535,6 +14557,15 @@ var composeCommand = new Command().name("compose").description("Create or update
14535
14557
  if (agent.provider) {
14536
14558
  const defaults = getProviderDefaults(agent.provider);
14537
14559
  if (defaults) {
14560
+ if (!agent.image) {
14561
+ const defaultImage = getDefaultImage(agent.provider);
14562
+ if (defaultImage) {
14563
+ agent.image = defaultImage;
14564
+ console.log(
14565
+ chalk2.gray(` Auto-configured image: ${defaultImage}`)
14566
+ );
14567
+ }
14568
+ }
14538
14569
  if (!agent.working_dir) {
14539
14570
  agent.working_dir = defaults.workingDir;
14540
14571
  console.log(
@@ -14545,37 +14576,35 @@ var composeCommand = new Command().name("compose").description("Create or update
14545
14576
  }
14546
14577
  }
14547
14578
  }
14548
- if (agent.beta_system_prompt) {
14549
- const promptPath = agent.beta_system_prompt;
14550
- console.log(chalk2.blue(`Uploading system prompt: ${promptPath}`));
14579
+ if (agent.instructions) {
14580
+ const instructionsPath = agent.instructions;
14581
+ console.log(chalk2.blue(`Uploading instructions: ${instructionsPath}`));
14551
14582
  try {
14552
- const result = await uploadSystemPrompt(
14583
+ const result = await uploadInstructions(
14553
14584
  agentName,
14554
- promptPath,
14585
+ instructionsPath,
14555
14586
  basePath
14556
14587
  );
14557
14588
  console.log(
14558
14589
  chalk2.green(
14559
- `\u2713 System prompt ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.versionId.slice(0, 8)}`
14590
+ `\u2713 Instructions ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.versionId.slice(0, 8)}`
14560
14591
  )
14561
14592
  );
14562
14593
  } catch (error43) {
14563
- console.error(chalk2.red(`\u2717 Failed to upload system prompt`));
14594
+ console.error(chalk2.red(`\u2717 Failed to upload instructions`));
14564
14595
  if (error43 instanceof Error) {
14565
14596
  console.error(chalk2.gray(` ${error43.message}`));
14566
14597
  }
14567
14598
  process.exit(1);
14568
14599
  }
14569
14600
  }
14570
- if (agent.beta_system_skills && Array.isArray(agent.beta_system_skills)) {
14571
- const skillUrls = agent.beta_system_skills;
14572
- console.log(
14573
- chalk2.blue(`Uploading ${skillUrls.length} system skill(s)...`)
14574
- );
14601
+ if (agent.skills && Array.isArray(agent.skills)) {
14602
+ const skillUrls = agent.skills;
14603
+ console.log(chalk2.blue(`Uploading ${skillUrls.length} skill(s)...`));
14575
14604
  for (const skillUrl of skillUrls) {
14576
14605
  try {
14577
14606
  console.log(chalk2.gray(` Downloading: ${skillUrl}`));
14578
- const result = await uploadSystemSkill(skillUrl);
14607
+ const result = await uploadSkill(skillUrl);
14579
14608
  console.log(
14580
14609
  chalk2.green(
14581
14610
  ` \u2713 Skill ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.versionId.slice(0, 8)}`
@@ -16294,7 +16323,7 @@ async function generateEnvPlaceholders(missingVars, envFilePath) {
16294
16323
  }
16295
16324
  }
16296
16325
  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.18.0", prompt);
16326
+ const shouldExit = await checkAndUpgrade("4.20.0", prompt);
16298
16327
  if (shouldExit) {
16299
16328
  process.exit(0);
16300
16329
  }
@@ -16481,6 +16510,38 @@ import { Command as Command14 } from "commander";
16481
16510
  import chalk16 from "chalk";
16482
16511
  import { readFile as readFile6 } from "fs/promises";
16483
16512
  import { existsSync as existsSync7 } from "fs";
16513
+
16514
+ // src/lib/dockerfile-validator.ts
16515
+ var ALLOWED_INSTRUCTIONS = /* @__PURE__ */ new Set(["FROM", "RUN"]);
16516
+ function validateDockerfile(content) {
16517
+ const errors = [];
16518
+ const lines = content.split("\n");
16519
+ let inContinuation = false;
16520
+ for (let i = 0; i < lines.length; i++) {
16521
+ const line = lines[i];
16522
+ const trimmed = line.trim();
16523
+ if (!inContinuation && !trimmed) continue;
16524
+ if (!inContinuation && trimmed.startsWith("#")) continue;
16525
+ if (inContinuation) {
16526
+ inContinuation = trimmed.endsWith("\\");
16527
+ continue;
16528
+ }
16529
+ const match = trimmed.match(/^([A-Za-z]+)\s/);
16530
+ if (match) {
16531
+ const instruction = match[1].toUpperCase();
16532
+ if (!ALLOWED_INSTRUCTIONS.has(instruction)) {
16533
+ errors.push(`Unsupported instruction: ${instruction} (line ${i + 1})`);
16534
+ }
16535
+ }
16536
+ inContinuation = trimmed.endsWith("\\");
16537
+ }
16538
+ return {
16539
+ valid: errors.length === 0,
16540
+ errors
16541
+ };
16542
+ }
16543
+
16544
+ // src/commands/image/build.ts
16484
16545
  var sleep2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
16485
16546
  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
16547
  async (options) => {
@@ -16509,6 +16570,25 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
16509
16570
  try {
16510
16571
  const scope = await apiClient.getScope();
16511
16572
  const dockerfile = await readFile6(file2, "utf8");
16573
+ const validation = validateDockerfile(dockerfile);
16574
+ if (!validation.valid) {
16575
+ console.error(chalk16.red("\u2717 Dockerfile validation failed\n"));
16576
+ for (const error43 of validation.errors) {
16577
+ console.error(chalk16.red(` ${error43}`));
16578
+ }
16579
+ console.error();
16580
+ console.error(
16581
+ chalk16.yellow(
16582
+ " vm0 image build only supports FROM and RUN instructions."
16583
+ )
16584
+ );
16585
+ console.error(
16586
+ chalk16.yellow(
16587
+ " The purpose is to pre-install environment dependencies."
16588
+ )
16589
+ );
16590
+ process.exit(1);
16591
+ }
16512
16592
  console.log(chalk16.blue(`Building image: ${scope.slug}/${name}`));
16513
16593
  console.log();
16514
16594
  const buildInfo = await apiClient.createImage({
@@ -17178,7 +17258,7 @@ var scopeCommand = new Command22().name("scope").description("Manage your scope
17178
17258
 
17179
17259
  // src/index.ts
17180
17260
  var program = new Command23();
17181
- program.name("vm0").description("VM0 CLI - A modern build tool").version("4.18.0");
17261
+ program.name("vm0").description("VM0 CLI - A modern build tool").version("4.20.0");
17182
17262
  program.command("info").description("Display environment information").action(async () => {
17183
17263
  console.log(chalk23.cyan("System Information:"));
17184
17264
  console.log(`Node Version: ${process.version}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vm0/cli",
3
- "version": "4.18.0",
3
+ "version": "4.20.0",
4
4
  "description": "CLI application",
5
5
  "repository": {
6
6
  "type": "git",