@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.
- package/index.js +129 -49
- 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().
|
|
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
|
|
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
|
-
|
|
12378
|
+
instructions: external_exports.string().optional(),
|
|
12378
12379
|
/**
|
|
12379
|
-
* Array of GitHub tree URLs for
|
|
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
|
-
|
|
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 (
|
|
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
|
|
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.
|
|
13989
|
-
if (typeof agent.
|
|
14013
|
+
if (agent.instructions !== void 0) {
|
|
14014
|
+
if (typeof agent.instructions !== "string") {
|
|
13990
14015
|
return {
|
|
13991
14016
|
valid: false,
|
|
13992
|
-
error: "agent.
|
|
14017
|
+
error: "agent.instructions must be a string (path to instructions file)"
|
|
13993
14018
|
};
|
|
13994
14019
|
}
|
|
13995
|
-
if (agent.
|
|
14020
|
+
if (agent.instructions.length === 0) {
|
|
13996
14021
|
return {
|
|
13997
14022
|
valid: false,
|
|
13998
|
-
error: "agent.
|
|
14023
|
+
error: "agent.instructions cannot be empty"
|
|
13999
14024
|
};
|
|
14000
14025
|
}
|
|
14001
14026
|
}
|
|
14002
|
-
if (agent.
|
|
14003
|
-
if (!Array.isArray(agent.
|
|
14027
|
+
if (agent.skills !== void 0) {
|
|
14028
|
+
if (!Array.isArray(agent.skills)) {
|
|
14004
14029
|
return {
|
|
14005
14030
|
valid: false,
|
|
14006
|
-
error: "agent.
|
|
14031
|
+
error: "agent.skills must be an array of GitHub tree URLs"
|
|
14007
14032
|
};
|
|
14008
14033
|
}
|
|
14009
|
-
for (const skillUrl of agent.
|
|
14034
|
+
for (const skillUrl of agent.skills) {
|
|
14010
14035
|
if (typeof skillUrl !== "string") {
|
|
14011
14036
|
return {
|
|
14012
14037
|
valid: false,
|
|
14013
|
-
error: "Each
|
|
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
|
|
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
|
|
14121
|
-
return
|
|
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
|
|
14461
|
-
const storageName =
|
|
14462
|
-
const absolutePath = path4.isAbsolute(
|
|
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-
|
|
14465
|
-
const
|
|
14466
|
-
await fs4.mkdir(
|
|
14467
|
-
await fs4.writeFile(path4.join(
|
|
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",
|
|
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
|
|
14501
|
+
async function uploadSkill(skillUrl) {
|
|
14480
14502
|
const parsed = parseGitHubTreeUrl(skillUrl);
|
|
14481
|
-
const storageName =
|
|
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.
|
|
14549
|
-
const
|
|
14550
|
-
console.log(chalk2.blue(`Uploading
|
|
14579
|
+
if (agent.instructions) {
|
|
14580
|
+
const instructionsPath = agent.instructions;
|
|
14581
|
+
console.log(chalk2.blue(`Uploading instructions: ${instructionsPath}`));
|
|
14551
14582
|
try {
|
|
14552
|
-
const result = await
|
|
14583
|
+
const result = await uploadInstructions(
|
|
14553
14584
|
agentName,
|
|
14554
|
-
|
|
14585
|
+
instructionsPath,
|
|
14555
14586
|
basePath
|
|
14556
14587
|
);
|
|
14557
14588
|
console.log(
|
|
14558
14589
|
chalk2.green(
|
|
14559
|
-
`\u2713
|
|
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
|
|
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.
|
|
14571
|
-
const skillUrls = agent.
|
|
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
|
|
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.
|
|
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.
|
|
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}`);
|