@vm0/cli 9.4.1 → 9.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.
- package/index.js +475 -439
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -4382,175 +4382,201 @@ function getSecretsFromComposeContent(content) {
|
|
|
4382
4382
|
const grouped = groupVariablesBySource(refs);
|
|
4383
4383
|
return new Set(grouped.secrets.map((r) => r.name));
|
|
4384
4384
|
}
|
|
4385
|
-
|
|
4385
|
+
async function loadAndValidateConfig(configFile) {
|
|
4386
|
+
if (!existsSync3(configFile)) {
|
|
4387
|
+
console.error(chalk3.red(`\u2717 Config file not found: ${configFile}`));
|
|
4388
|
+
process.exit(1);
|
|
4389
|
+
}
|
|
4390
|
+
const content = await readFile4(configFile, "utf8");
|
|
4391
|
+
let config;
|
|
4386
4392
|
try {
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
let config;
|
|
4393
|
-
try {
|
|
4394
|
-
config = parseYaml2(content);
|
|
4395
|
-
} catch (error) {
|
|
4396
|
-
console.error(chalk3.red("\u2717 Invalid YAML format"));
|
|
4397
|
-
if (error instanceof Error) {
|
|
4398
|
-
console.error(chalk3.dim(` ${error.message}`));
|
|
4399
|
-
}
|
|
4400
|
-
process.exit(1);
|
|
4401
|
-
}
|
|
4402
|
-
const validation = validateAgentCompose(config);
|
|
4403
|
-
if (!validation.valid) {
|
|
4404
|
-
console.error(chalk3.red(`\u2717 ${validation.error}`));
|
|
4405
|
-
process.exit(1);
|
|
4393
|
+
config = parseYaml2(content);
|
|
4394
|
+
} catch (error) {
|
|
4395
|
+
console.error(chalk3.red("\u2717 Invalid YAML format"));
|
|
4396
|
+
if (error instanceof Error) {
|
|
4397
|
+
console.error(chalk3.dim(` ${error.message}`));
|
|
4406
4398
|
}
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4399
|
+
process.exit(1);
|
|
4400
|
+
}
|
|
4401
|
+
const validation = validateAgentCompose(config);
|
|
4402
|
+
if (!validation.valid) {
|
|
4403
|
+
console.error(chalk3.red(`\u2717 ${validation.error}`));
|
|
4404
|
+
process.exit(1);
|
|
4405
|
+
}
|
|
4406
|
+
const cfg = config;
|
|
4407
|
+
const agentsConfig = cfg.agents;
|
|
4408
|
+
const agentName = Object.keys(agentsConfig)[0];
|
|
4409
|
+
const agent = agentsConfig[agentName];
|
|
4410
|
+
const basePath = dirname2(configFile);
|
|
4411
|
+
return { config, agentName, agent, basePath };
|
|
4412
|
+
}
|
|
4413
|
+
function checkLegacyImageFormat(config) {
|
|
4414
|
+
const cfg = config;
|
|
4415
|
+
const agentsConfig = cfg.agents;
|
|
4416
|
+
for (const [name, agentConfig] of Object.entries(agentsConfig)) {
|
|
4417
|
+
const image = agentConfig.image;
|
|
4418
|
+
if (image) {
|
|
4419
|
+
console.log(
|
|
4420
|
+
chalk3.yellow(
|
|
4421
|
+
`\u26A0 Agent "${name}": 'image' field is deprecated. Use 'apps' field for pre-installed tools.`
|
|
4422
|
+
)
|
|
4423
|
+
);
|
|
4424
|
+
const warning = getLegacySystemTemplateWarning(image);
|
|
4425
|
+
if (warning) {
|
|
4426
|
+
console.log(chalk3.yellow(` ${warning}`));
|
|
4421
4427
|
}
|
|
4422
4428
|
}
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
async function uploadAssets(agentName, agent, basePath) {
|
|
4432
|
+
if (agent.instructions) {
|
|
4433
|
+
console.log(`Uploading instructions: ${agent.instructions}`);
|
|
4434
|
+
const result = await uploadInstructions(
|
|
4435
|
+
agentName,
|
|
4436
|
+
agent.instructions,
|
|
4437
|
+
basePath,
|
|
4438
|
+
agent.framework
|
|
4439
|
+
);
|
|
4440
|
+
console.log(
|
|
4441
|
+
chalk3.green(
|
|
4442
|
+
`\u2713 Instructions ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.versionId.slice(0, 8)}`
|
|
4443
|
+
)
|
|
4444
|
+
);
|
|
4445
|
+
}
|
|
4446
|
+
const skillResults = [];
|
|
4447
|
+
if (agent.skills && Array.isArray(agent.skills)) {
|
|
4448
|
+
console.log(`Uploading ${agent.skills.length} skill(s)...`);
|
|
4449
|
+
for (const skillUrl of agent.skills) {
|
|
4450
|
+
console.log(chalk3.dim(` Downloading: ${skillUrl}`));
|
|
4451
|
+
const result = await uploadSkill(skillUrl);
|
|
4452
|
+
skillResults.push(result);
|
|
4437
4453
|
console.log(
|
|
4438
4454
|
chalk3.green(
|
|
4439
|
-
|
|
4455
|
+
` \u2713 Skill ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.skillName} (${result.versionId.slice(0, 8)})`
|
|
4440
4456
|
)
|
|
4441
4457
|
);
|
|
4442
4458
|
}
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
)
|
|
4455
|
-
);
|
|
4456
|
-
}
|
|
4457
|
-
}
|
|
4458
|
-
const skillSecrets = /* @__PURE__ */ new Map();
|
|
4459
|
-
const skillVars = /* @__PURE__ */ new Map();
|
|
4460
|
-
for (const result of skillResults) {
|
|
4461
|
-
const { frontmatter, skillName } = result;
|
|
4462
|
-
if (frontmatter.vm0_secrets) {
|
|
4463
|
-
for (const secret of frontmatter.vm0_secrets) {
|
|
4464
|
-
if (!skillSecrets.has(secret)) {
|
|
4465
|
-
skillSecrets.set(secret, []);
|
|
4466
|
-
}
|
|
4467
|
-
skillSecrets.get(secret).push(skillName);
|
|
4459
|
+
}
|
|
4460
|
+
return skillResults;
|
|
4461
|
+
}
|
|
4462
|
+
async function collectSkillVariables(skillResults, environment, agentName) {
|
|
4463
|
+
const skillSecrets = /* @__PURE__ */ new Map();
|
|
4464
|
+
const skillVars = /* @__PURE__ */ new Map();
|
|
4465
|
+
for (const result of skillResults) {
|
|
4466
|
+
const { frontmatter, skillName } = result;
|
|
4467
|
+
if (frontmatter.vm0_secrets) {
|
|
4468
|
+
for (const secret of frontmatter.vm0_secrets) {
|
|
4469
|
+
if (!skillSecrets.has(secret)) {
|
|
4470
|
+
skillSecrets.set(secret, []);
|
|
4468
4471
|
}
|
|
4472
|
+
skillSecrets.get(secret).push(skillName);
|
|
4469
4473
|
}
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
skillVars.get(varName).push(skillName);
|
|
4474
|
+
}
|
|
4475
|
+
if (frontmatter.vm0_vars) {
|
|
4476
|
+
for (const varName of frontmatter.vm0_vars) {
|
|
4477
|
+
if (!skillVars.has(varName)) {
|
|
4478
|
+
skillVars.set(varName, []);
|
|
4476
4479
|
}
|
|
4480
|
+
skillVars.get(varName).push(skillName);
|
|
4477
4481
|
}
|
|
4478
4482
|
}
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4483
|
+
}
|
|
4484
|
+
const newSecrets = [...skillSecrets.entries()].filter(
|
|
4485
|
+
([name]) => !(name in environment)
|
|
4486
|
+
);
|
|
4487
|
+
const newVars = [...skillVars.entries()].filter(
|
|
4488
|
+
([name]) => !(name in environment)
|
|
4489
|
+
);
|
|
4490
|
+
let headSecrets = /* @__PURE__ */ new Set();
|
|
4491
|
+
const existingCompose = await getComposeByName(agentName);
|
|
4492
|
+
if (existingCompose?.content) {
|
|
4493
|
+
headSecrets = getSecretsFromComposeContent(existingCompose.content);
|
|
4494
|
+
}
|
|
4495
|
+
const trulyNewSecrets = newSecrets.map(([name]) => name).filter((name) => !headSecrets.has(name));
|
|
4496
|
+
return { newSecrets, newVars, trulyNewSecrets };
|
|
4497
|
+
}
|
|
4498
|
+
async function displayAndConfirmVariables(variables, options) {
|
|
4499
|
+
const { newSecrets, newVars, trulyNewSecrets } = variables;
|
|
4500
|
+
if (newSecrets.length === 0 && newVars.length === 0) {
|
|
4501
|
+
return true;
|
|
4502
|
+
}
|
|
4503
|
+
console.log();
|
|
4504
|
+
console.log(
|
|
4505
|
+
chalk3.bold("Skills require the following environment variables:")
|
|
4506
|
+
);
|
|
4507
|
+
console.log();
|
|
4508
|
+
if (newSecrets.length > 0) {
|
|
4509
|
+
console.log(chalk3.cyan(" Secrets:"));
|
|
4510
|
+
for (const [name, skills] of newSecrets) {
|
|
4511
|
+
const isNew = trulyNewSecrets.includes(name);
|
|
4512
|
+
const newMarker = isNew ? chalk3.yellow(" (new)") : "";
|
|
4513
|
+
console.log(` ${name.padEnd(24)}${newMarker} <- ${skills.join(", ")}`);
|
|
4490
4514
|
}
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4515
|
+
}
|
|
4516
|
+
if (newVars.length > 0) {
|
|
4517
|
+
console.log(chalk3.cyan(" Vars:"));
|
|
4518
|
+
for (const [name, skills] of newVars) {
|
|
4519
|
+
console.log(` ${name.padEnd(24)} <- ${skills.join(", ")}`);
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
console.log();
|
|
4523
|
+
if (trulyNewSecrets.length > 0 && !options.yes) {
|
|
4524
|
+
if (!isInteractive()) {
|
|
4525
|
+
console.error(
|
|
4526
|
+
chalk3.red(`\u2717 New secrets detected: ${trulyNewSecrets.join(", ")}`)
|
|
4496
4527
|
);
|
|
4497
|
-
console.
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
console.log(` ${name.padEnd(24)} <- ${skills.join(", ")}`);
|
|
4512
|
-
}
|
|
4513
|
-
}
|
|
4514
|
-
console.log();
|
|
4515
|
-
if (trulyNewSecrets.length > 0) {
|
|
4516
|
-
if (!options.yes) {
|
|
4517
|
-
if (!isInteractive()) {
|
|
4518
|
-
console.error(
|
|
4519
|
-
chalk3.red(
|
|
4520
|
-
`\u2717 New secrets detected: ${trulyNewSecrets.join(", ")}`
|
|
4521
|
-
)
|
|
4522
|
-
);
|
|
4523
|
-
console.error(
|
|
4524
|
-
chalk3.dim(
|
|
4525
|
-
" Use --yes flag to approve new secrets in non-interactive mode."
|
|
4526
|
-
)
|
|
4527
|
-
);
|
|
4528
|
-
process.exit(1);
|
|
4529
|
-
}
|
|
4530
|
-
const confirmed = await promptConfirm(
|
|
4531
|
-
`Approve ${trulyNewSecrets.length} new secret(s)?`,
|
|
4532
|
-
true
|
|
4533
|
-
);
|
|
4534
|
-
if (!confirmed) {
|
|
4535
|
-
console.log(chalk3.yellow("Compose cancelled"));
|
|
4536
|
-
process.exit(0);
|
|
4537
|
-
}
|
|
4538
|
-
}
|
|
4539
|
-
}
|
|
4540
|
-
for (const [name] of newSecrets) {
|
|
4541
|
-
environment[name] = `\${{ secrets.${name} }}`;
|
|
4542
|
-
}
|
|
4543
|
-
for (const [name] of newVars) {
|
|
4544
|
-
environment[name] = `\${{ vars.${name} }}`;
|
|
4545
|
-
}
|
|
4546
|
-
if (Object.keys(environment).length > 0) {
|
|
4547
|
-
agent.environment = environment;
|
|
4548
|
-
}
|
|
4528
|
+
console.error(
|
|
4529
|
+
chalk3.dim(
|
|
4530
|
+
" Use --yes flag to approve new secrets in non-interactive mode."
|
|
4531
|
+
)
|
|
4532
|
+
);
|
|
4533
|
+
process.exit(1);
|
|
4534
|
+
}
|
|
4535
|
+
const confirmed = await promptConfirm(
|
|
4536
|
+
`Approve ${trulyNewSecrets.length} new secret(s)?`,
|
|
4537
|
+
true
|
|
4538
|
+
);
|
|
4539
|
+
if (!confirmed) {
|
|
4540
|
+
console.log(chalk3.yellow("Compose cancelled"));
|
|
4541
|
+
return false;
|
|
4549
4542
|
}
|
|
4543
|
+
}
|
|
4544
|
+
return true;
|
|
4545
|
+
}
|
|
4546
|
+
function mergeSkillVariables(agent, variables) {
|
|
4547
|
+
const { newSecrets, newVars } = variables;
|
|
4548
|
+
if (newSecrets.length === 0 && newVars.length === 0) {
|
|
4549
|
+
return;
|
|
4550
|
+
}
|
|
4551
|
+
const environment = agent.environment || {};
|
|
4552
|
+
for (const [name] of newSecrets) {
|
|
4553
|
+
environment[name] = `\${{ secrets.${name} }}`;
|
|
4554
|
+
}
|
|
4555
|
+
for (const [name] of newVars) {
|
|
4556
|
+
environment[name] = `\${{ vars.${name} }}`;
|
|
4557
|
+
}
|
|
4558
|
+
if (Object.keys(environment).length > 0) {
|
|
4559
|
+
agent.environment = environment;
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4562
|
+
var composeCommand = new Command7().name("compose").description("Create or update agent compose (e.g., vm0.yaml)").argument("<agent-yaml>", "Path to agent YAML file").option("-y, --yes", "Skip confirmation prompts for skill requirements").action(async (configFile, options) => {
|
|
4563
|
+
try {
|
|
4564
|
+
const { config, agentName, agent, basePath } = await loadAndValidateConfig(configFile);
|
|
4565
|
+
checkLegacyImageFormat(config);
|
|
4566
|
+
const skillResults = await uploadAssets(agentName, agent, basePath);
|
|
4567
|
+
const environment = agent.environment || {};
|
|
4568
|
+
const variables = await collectSkillVariables(
|
|
4569
|
+
skillResults,
|
|
4570
|
+
environment,
|
|
4571
|
+
agentName
|
|
4572
|
+
);
|
|
4573
|
+
const confirmed = await displayAndConfirmVariables(variables, options);
|
|
4574
|
+
if (!confirmed) {
|
|
4575
|
+
process.exit(0);
|
|
4576
|
+
}
|
|
4577
|
+
mergeSkillVariables(agent, variables);
|
|
4550
4578
|
console.log("Uploading compose...");
|
|
4551
|
-
const response = await createOrUpdateCompose({
|
|
4552
|
-
content: config
|
|
4553
|
-
});
|
|
4579
|
+
const response = await createOrUpdateCompose({ content: config });
|
|
4554
4580
|
const scopeResponse = await getScope();
|
|
4555
4581
|
const shortVersionId = response.versionId.slice(0, 8);
|
|
4556
4582
|
const displayName = `${scopeResponse.slug}/${response.name}`;
|
|
@@ -4571,9 +4597,6 @@ var composeCommand = new Command7().name("compose").description("Create or updat
|
|
|
4571
4597
|
if (error instanceof Error) {
|
|
4572
4598
|
if (error.message.includes("Not authenticated")) {
|
|
4573
4599
|
console.error(chalk3.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
4574
|
-
} else if (error.message.includes("Failed to create compose")) {
|
|
4575
|
-
console.error(chalk3.red("\u2717 Failed to create compose"));
|
|
4576
|
-
console.error(chalk3.dim(` ${error.message}`));
|
|
4577
4600
|
} else {
|
|
4578
4601
|
console.error(chalk3.red("\u2717 Failed to create compose"));
|
|
4579
4602
|
console.error(chalk3.dim(` ${error.message}`));
|
|
@@ -7960,135 +7983,89 @@ function checkMissingVariables(varNames, envFilePath) {
|
|
|
7960
7983
|
}
|
|
7961
7984
|
return missing;
|
|
7962
7985
|
}
|
|
7963
|
-
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7977
|
-
if (!existsSync9(CONFIG_FILE2)) {
|
|
7978
|
-
console.error(chalk28.red(`\u2717 Config file not found: ${CONFIG_FILE2}`));
|
|
7979
|
-
process.exit(1);
|
|
7986
|
+
async function loadAndValidateConfig2() {
|
|
7987
|
+
console.log(chalk28.bold(`Reading config: ${CONFIG_FILE2}`));
|
|
7988
|
+
if (!existsSync9(CONFIG_FILE2)) {
|
|
7989
|
+
console.error(chalk28.red(`\u2717 Config file not found: ${CONFIG_FILE2}`));
|
|
7990
|
+
process.exit(1);
|
|
7991
|
+
}
|
|
7992
|
+
let config;
|
|
7993
|
+
try {
|
|
7994
|
+
const content = await readFile7(CONFIG_FILE2, "utf8");
|
|
7995
|
+
config = parseYaml4(content);
|
|
7996
|
+
} catch (error) {
|
|
7997
|
+
console.error(chalk28.red("\u2717 Invalid YAML format"));
|
|
7998
|
+
if (error instanceof Error) {
|
|
7999
|
+
console.error(chalk28.dim(` ${error.message}`));
|
|
7980
8000
|
}
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
|
|
7986
|
-
|
|
7987
|
-
|
|
7988
|
-
|
|
8001
|
+
process.exit(1);
|
|
8002
|
+
}
|
|
8003
|
+
const validation = validateAgentCompose(config);
|
|
8004
|
+
if (!validation.valid) {
|
|
8005
|
+
console.error(chalk28.red(`\u2717 ${validation.error}`));
|
|
8006
|
+
process.exit(1);
|
|
8007
|
+
}
|
|
8008
|
+
const agentNames = Object.keys(config.agents);
|
|
8009
|
+
const agentName = agentNames[0];
|
|
8010
|
+
const volumeCount = config.volumes ? Object.keys(config.volumes).length : 0;
|
|
8011
|
+
console.log(
|
|
8012
|
+
chalk28.green(`\u2713 Config validated: 1 agent, ${volumeCount} volume(s)`)
|
|
8013
|
+
);
|
|
8014
|
+
return { config, agentName, volumeCount };
|
|
8015
|
+
}
|
|
8016
|
+
function validateEnvVariables(config, envFile) {
|
|
8017
|
+
const requiredVarNames = extractRequiredVarNames(config);
|
|
8018
|
+
if (requiredVarNames.length === 0) {
|
|
8019
|
+
return;
|
|
8020
|
+
}
|
|
8021
|
+
try {
|
|
8022
|
+
const missingVars = checkMissingVariables(requiredVarNames, envFile);
|
|
8023
|
+
if (missingVars.length > 0) {
|
|
8024
|
+
console.log();
|
|
8025
|
+
console.error(chalk28.red("\u2717 Missing required variables:"));
|
|
8026
|
+
for (const varName of missingVars) {
|
|
8027
|
+
console.error(chalk28.red(` ${varName}`));
|
|
7989
8028
|
}
|
|
8029
|
+
console.error(
|
|
8030
|
+
chalk28.dim(
|
|
8031
|
+
"\n Provide via --env-file, or set as environment variables"
|
|
8032
|
+
)
|
|
8033
|
+
);
|
|
7990
8034
|
process.exit(1);
|
|
7991
8035
|
}
|
|
7992
|
-
|
|
7993
|
-
if (
|
|
7994
|
-
console.error(chalk28.red(`\u2717 ${
|
|
7995
|
-
process.exit(1);
|
|
7996
|
-
}
|
|
7997
|
-
const agentNames = Object.keys(config.agents);
|
|
7998
|
-
const agentName = agentNames[0];
|
|
7999
|
-
const volumeCount = config.volumes ? Object.keys(config.volumes).length : 0;
|
|
8000
|
-
console.log(
|
|
8001
|
-
chalk28.green(`\u2713 Config validated: 1 agent, ${volumeCount} volume(s)`)
|
|
8002
|
-
);
|
|
8003
|
-
const requiredVarNames = extractRequiredVarNames(config);
|
|
8004
|
-
if (requiredVarNames.length > 0) {
|
|
8005
|
-
try {
|
|
8006
|
-
const missingVars = checkMissingVariables(
|
|
8007
|
-
requiredVarNames,
|
|
8008
|
-
options.envFile
|
|
8009
|
-
);
|
|
8010
|
-
if (missingVars.length > 0) {
|
|
8011
|
-
console.log();
|
|
8012
|
-
console.error(chalk28.red("\u2717 Missing required variables:"));
|
|
8013
|
-
for (const varName of missingVars) {
|
|
8014
|
-
console.error(chalk28.red(` ${varName}`));
|
|
8015
|
-
}
|
|
8016
|
-
console.error(
|
|
8017
|
-
chalk28.dim(
|
|
8018
|
-
"\n Provide via --env-file, or set as environment variables"
|
|
8019
|
-
)
|
|
8020
|
-
);
|
|
8021
|
-
process.exit(1);
|
|
8022
|
-
}
|
|
8023
|
-
} catch (error) {
|
|
8024
|
-
if (error instanceof Error) {
|
|
8025
|
-
console.error(chalk28.red(`\u2717 ${error.message}`));
|
|
8026
|
-
}
|
|
8027
|
-
process.exit(1);
|
|
8028
|
-
}
|
|
8036
|
+
} catch (error) {
|
|
8037
|
+
if (error instanceof Error) {
|
|
8038
|
+
console.error(chalk28.red(`\u2717 ${error.message}`));
|
|
8029
8039
|
}
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
8043
|
-
|
|
8044
|
-
|
|
8045
|
-
printCommand(`cd ${volumeConfig.name}`);
|
|
8046
|
-
const existingConfig = await readStorageConfig(volumeDir);
|
|
8047
|
-
if (!existingConfig) {
|
|
8048
|
-
printCommand(`vm0 volume init --name ${volumeConfig.name}`);
|
|
8049
|
-
await execVm0Command(
|
|
8050
|
-
["volume", "init", "--name", volumeConfig.name],
|
|
8051
|
-
{
|
|
8052
|
-
cwd: volumeDir,
|
|
8053
|
-
silent: true
|
|
8054
|
-
}
|
|
8055
|
-
);
|
|
8056
|
-
}
|
|
8057
|
-
printCommand("vm0 volume push");
|
|
8058
|
-
await execVm0Command(["volume", "push"], {
|
|
8059
|
-
cwd: volumeDir,
|
|
8060
|
-
silent: true
|
|
8061
|
-
});
|
|
8062
|
-
printCommand("cd ..");
|
|
8063
|
-
} catch (error) {
|
|
8064
|
-
console.error(chalk28.red(`\u2717 Failed`));
|
|
8065
|
-
if (error instanceof Error) {
|
|
8066
|
-
console.error(chalk28.dim(` ${error.message}`));
|
|
8067
|
-
}
|
|
8068
|
-
process.exit(1);
|
|
8069
|
-
}
|
|
8070
|
-
}
|
|
8040
|
+
process.exit(1);
|
|
8041
|
+
}
|
|
8042
|
+
}
|
|
8043
|
+
async function processVolumes(config, cwd) {
|
|
8044
|
+
if (!config.volumes || Object.keys(config.volumes).length === 0) {
|
|
8045
|
+
return;
|
|
8046
|
+
}
|
|
8047
|
+
console.log();
|
|
8048
|
+
console.log(chalk28.bold("Processing volumes:"));
|
|
8049
|
+
for (const volumeConfig of Object.values(config.volumes)) {
|
|
8050
|
+
const volumeDir = path11.join(cwd, volumeConfig.name);
|
|
8051
|
+
if (!existsSync9(volumeDir)) {
|
|
8052
|
+
console.error(chalk28.red(`\u2717 Directory not found: ${volumeConfig.name}`));
|
|
8053
|
+
console.error(chalk28.dim(" Create the directory and add files first"));
|
|
8054
|
+
process.exit(1);
|
|
8071
8055
|
}
|
|
8072
|
-
console.log();
|
|
8073
|
-
console.log(chalk28.bold("Processing artifact:"));
|
|
8074
|
-
const artifactDir = path11.join(cwd, ARTIFACT_DIR);
|
|
8075
8056
|
try {
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
await mkdir6(artifactDir, { recursive: true });
|
|
8079
|
-
}
|
|
8080
|
-
printCommand(`cd ${ARTIFACT_DIR}`);
|
|
8081
|
-
const existingConfig = await readStorageConfig(artifactDir);
|
|
8057
|
+
printCommand(`cd ${volumeConfig.name}`);
|
|
8058
|
+
const existingConfig = await readStorageConfig(volumeDir);
|
|
8082
8059
|
if (!existingConfig) {
|
|
8083
|
-
printCommand(`vm0
|
|
8084
|
-
await execVm0Command(["
|
|
8085
|
-
cwd:
|
|
8060
|
+
printCommand(`vm0 volume init --name ${volumeConfig.name}`);
|
|
8061
|
+
await execVm0Command(["volume", "init", "--name", volumeConfig.name], {
|
|
8062
|
+
cwd: volumeDir,
|
|
8086
8063
|
silent: true
|
|
8087
8064
|
});
|
|
8088
8065
|
}
|
|
8089
|
-
printCommand("vm0
|
|
8090
|
-
await execVm0Command(["
|
|
8091
|
-
cwd:
|
|
8066
|
+
printCommand("vm0 volume push");
|
|
8067
|
+
await execVm0Command(["volume", "push"], {
|
|
8068
|
+
cwd: volumeDir,
|
|
8092
8069
|
silent: true
|
|
8093
8070
|
});
|
|
8094
8071
|
printCommand("cd ..");
|
|
@@ -8099,51 +8076,112 @@ var cookAction = new Command27().name("cook").description("Quick start: prepare,
|
|
|
8099
8076
|
}
|
|
8100
8077
|
process.exit(1);
|
|
8101
8078
|
}
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8108
|
-
|
|
8079
|
+
}
|
|
8080
|
+
}
|
|
8081
|
+
async function processArtifact(cwd) {
|
|
8082
|
+
console.log();
|
|
8083
|
+
console.log(chalk28.bold("Processing artifact:"));
|
|
8084
|
+
const artifactDir = path11.join(cwd, ARTIFACT_DIR);
|
|
8085
|
+
try {
|
|
8086
|
+
if (!existsSync9(artifactDir)) {
|
|
8087
|
+
printCommand(`mkdir ${ARTIFACT_DIR}`);
|
|
8088
|
+
await mkdir6(artifactDir, { recursive: true });
|
|
8089
|
+
}
|
|
8090
|
+
printCommand(`cd ${ARTIFACT_DIR}`);
|
|
8091
|
+
const existingConfig = await readStorageConfig(artifactDir);
|
|
8092
|
+
if (!existingConfig) {
|
|
8093
|
+
printCommand(`vm0 artifact init --name ${ARTIFACT_DIR}`);
|
|
8094
|
+
await execVm0Command(["artifact", "init", "--name", ARTIFACT_DIR], {
|
|
8095
|
+
cwd: artifactDir,
|
|
8096
|
+
silent: true
|
|
8109
8097
|
});
|
|
8110
|
-
}
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8098
|
+
}
|
|
8099
|
+
printCommand("vm0 artifact push");
|
|
8100
|
+
await execVm0Command(["artifact", "push"], {
|
|
8101
|
+
cwd: artifactDir,
|
|
8102
|
+
silent: true
|
|
8103
|
+
});
|
|
8104
|
+
printCommand("cd ..");
|
|
8105
|
+
} catch (error) {
|
|
8106
|
+
console.error(chalk28.red(`\u2717 Failed`));
|
|
8107
|
+
if (error instanceof Error) {
|
|
8108
|
+
console.error(chalk28.dim(` ${error.message}`));
|
|
8109
|
+
}
|
|
8110
|
+
process.exit(1);
|
|
8111
|
+
}
|
|
8112
|
+
return artifactDir;
|
|
8113
|
+
}
|
|
8114
|
+
async function composeAgent(cwd, skipConfirm) {
|
|
8115
|
+
console.log();
|
|
8116
|
+
console.log(chalk28.bold("Composing agent:"));
|
|
8117
|
+
const composeArgs = skipConfirm ? ["compose", "--yes", CONFIG_FILE2] : ["compose", CONFIG_FILE2];
|
|
8118
|
+
printCommand(`vm0 ${composeArgs.join(" ")}`);
|
|
8119
|
+
try {
|
|
8120
|
+
await execVm0Command(composeArgs, { cwd });
|
|
8121
|
+
} catch (error) {
|
|
8122
|
+
console.error(chalk28.red(`\u2717 Compose failed`));
|
|
8123
|
+
if (error instanceof Error) {
|
|
8124
|
+
console.error(chalk28.dim(` ${error.message}`));
|
|
8125
|
+
}
|
|
8126
|
+
process.exit(1);
|
|
8127
|
+
}
|
|
8128
|
+
}
|
|
8129
|
+
async function runAgent(agentName, artifactDir, prompt, cwd, debugNoMockClaude) {
|
|
8130
|
+
console.log();
|
|
8131
|
+
console.log(chalk28.bold("Running agent:"));
|
|
8132
|
+
printCommand(
|
|
8133
|
+
`vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "${prompt}"`
|
|
8134
|
+
);
|
|
8135
|
+
console.log();
|
|
8136
|
+
let runOutput;
|
|
8137
|
+
try {
|
|
8138
|
+
const runArgs = [
|
|
8139
|
+
"run",
|
|
8140
|
+
agentName,
|
|
8141
|
+
"--artifact-name",
|
|
8142
|
+
ARTIFACT_DIR,
|
|
8143
|
+
...debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
|
|
8144
|
+
prompt
|
|
8145
|
+
];
|
|
8146
|
+
runOutput = await execVm0RunWithCapture(runArgs, { cwd });
|
|
8147
|
+
} catch {
|
|
8148
|
+
process.exit(1);
|
|
8149
|
+
}
|
|
8150
|
+
const runIds = parseRunIdsFromOutput(runOutput);
|
|
8151
|
+
if (runIds.runId || runIds.sessionId || runIds.checkpointId) {
|
|
8152
|
+
await saveCookState({
|
|
8153
|
+
lastRunId: runIds.runId,
|
|
8154
|
+
lastSessionId: runIds.sessionId,
|
|
8155
|
+
lastCheckpointId: runIds.checkpointId
|
|
8156
|
+
});
|
|
8157
|
+
}
|
|
8158
|
+
await autoPullArtifact(runOutput, artifactDir);
|
|
8159
|
+
}
|
|
8160
|
+
var cookAction = new Command27().name("cook").description("Quick start: prepare, compose and run agent from vm0.yaml").argument("[prompt]", "Prompt for the agent").option(
|
|
8161
|
+
"--env-file <path>",
|
|
8162
|
+
"Load environment variables from file (priority: CLI flags > file > env vars)"
|
|
8163
|
+
).option("-y, --yes", "Skip confirmation prompts").addOption(new Option4("--debug-no-mock-claude").hideHelp()).addOption(new Option4("--no-auto-update").hideHelp()).action(
|
|
8164
|
+
async (prompt, options) => {
|
|
8165
|
+
if (!options.noAutoUpdate) {
|
|
8166
|
+
const shouldExit = await checkAndUpgrade("9.5.0", prompt);
|
|
8167
|
+
if (shouldExit) {
|
|
8168
|
+
process.exit(0);
|
|
8114
8169
|
}
|
|
8115
|
-
process.exit(1);
|
|
8116
8170
|
}
|
|
8171
|
+
const cwd = process.cwd();
|
|
8172
|
+
const { config, agentName } = await loadAndValidateConfig2();
|
|
8173
|
+
validateEnvVariables(config, options.envFile);
|
|
8174
|
+
await processVolumes(config, cwd);
|
|
8175
|
+
const artifactDir = await processArtifact(cwd);
|
|
8176
|
+
await composeAgent(cwd, options.yes ?? false);
|
|
8117
8177
|
if (prompt) {
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8178
|
+
await runAgent(
|
|
8179
|
+
agentName,
|
|
8180
|
+
artifactDir,
|
|
8181
|
+
prompt,
|
|
8182
|
+
cwd,
|
|
8183
|
+
options.debugNoMockClaude ?? false
|
|
8122
8184
|
);
|
|
8123
|
-
console.log();
|
|
8124
|
-
let runOutput;
|
|
8125
|
-
try {
|
|
8126
|
-
const runArgs = [
|
|
8127
|
-
"run",
|
|
8128
|
-
agentName,
|
|
8129
|
-
"--artifact-name",
|
|
8130
|
-
ARTIFACT_DIR,
|
|
8131
|
-
...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
|
|
8132
|
-
prompt
|
|
8133
|
-
];
|
|
8134
|
-
runOutput = await execVm0RunWithCapture(runArgs, { cwd });
|
|
8135
|
-
} catch {
|
|
8136
|
-
process.exit(1);
|
|
8137
|
-
}
|
|
8138
|
-
const runIds = parseRunIdsFromOutput(runOutput);
|
|
8139
|
-
if (runIds.runId || runIds.sessionId || runIds.checkpointId) {
|
|
8140
|
-
await saveCookState({
|
|
8141
|
-
lastRunId: runIds.runId,
|
|
8142
|
-
lastSessionId: runIds.sessionId,
|
|
8143
|
-
lastCheckpointId: runIds.checkpointId
|
|
8144
|
-
});
|
|
8145
|
-
}
|
|
8146
|
-
await autoPullArtifact(runOutput, artifactDir);
|
|
8147
8185
|
} else {
|
|
8148
8186
|
console.log();
|
|
8149
8187
|
console.log("To run your agent:");
|
|
@@ -10710,82 +10748,106 @@ import path16 from "path";
|
|
|
10710
10748
|
|
|
10711
10749
|
// src/lib/ui/welcome-box.ts
|
|
10712
10750
|
import chalk53 from "chalk";
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10751
|
+
var gradientColors = [
|
|
10752
|
+
chalk53.hex("#FF9650"),
|
|
10753
|
+
// Line 1 - lightest
|
|
10754
|
+
chalk53.hex("#FF7832"),
|
|
10755
|
+
// Line 2
|
|
10756
|
+
chalk53.hex("#FF7832"),
|
|
10757
|
+
// Line 3
|
|
10758
|
+
chalk53.hex("#ED4E01"),
|
|
10759
|
+
// Line 4 - brand orange
|
|
10760
|
+
chalk53.hex("#ED4E01"),
|
|
10761
|
+
// Line 5
|
|
10762
|
+
chalk53.hex("#C83C00")
|
|
10763
|
+
// Line 6 - darkest
|
|
10764
|
+
];
|
|
10765
|
+
var vm0LogoLines = [
|
|
10766
|
+
"\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557",
|
|
10767
|
+
"\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557",
|
|
10768
|
+
"\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551",
|
|
10769
|
+
"\u255A\u2588\u2588\u2557 \u2588\u2588\u2554\u255D\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551",
|
|
10770
|
+
" \u255A\u2588\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D",
|
|
10771
|
+
" \u255A\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D"
|
|
10772
|
+
];
|
|
10773
|
+
function renderVm0Banner() {
|
|
10774
|
+
console.log();
|
|
10775
|
+
for (let i = 0; i < vm0LogoLines.length; i++) {
|
|
10776
|
+
const color = gradientColors[i] ?? gradientColors[gradientColors.length - 1];
|
|
10777
|
+
console.log(` ${color?.(vm0LogoLines[i])}`);
|
|
10778
|
+
}
|
|
10779
|
+
console.log();
|
|
10729
10780
|
}
|
|
10730
10781
|
function renderOnboardWelcome() {
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
"Let's create your first agent.",
|
|
10736
|
-
""
|
|
10737
|
-
]);
|
|
10782
|
+
renderVm0Banner();
|
|
10783
|
+
console.log(` ${chalk53.bold("Welcome to VM0!")}`);
|
|
10784
|
+
console.log(` ${chalk53.dim("Let's create your first agent.")}`);
|
|
10785
|
+
console.log();
|
|
10738
10786
|
}
|
|
10739
10787
|
|
|
10740
10788
|
// src/lib/ui/progress-line.ts
|
|
10741
10789
|
import chalk54 from "chalk";
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
case "pending":
|
|
10757
|
-
default:
|
|
10758
|
-
return chalk54.dim;
|
|
10759
|
-
}
|
|
10760
|
-
}
|
|
10761
|
-
function renderProgressLine(steps) {
|
|
10762
|
-
for (let i = 0; i < steps.length; i++) {
|
|
10763
|
-
const step = steps[i];
|
|
10764
|
-
if (!step) continue;
|
|
10765
|
-
const symbol = STATUS_SYMBOLS[step.status];
|
|
10766
|
-
const color = getStatusColor(step.status);
|
|
10767
|
-
console.log(color(`${symbol} ${step.label}`));
|
|
10768
|
-
if (i < steps.length - 1) {
|
|
10769
|
-
console.log(chalk54.dim("\u2502"));
|
|
10790
|
+
function createProgressiveProgress(interactive = true) {
|
|
10791
|
+
let currentLabel = "";
|
|
10792
|
+
let detailLineCount = 0;
|
|
10793
|
+
let isFinalStep = false;
|
|
10794
|
+
const clearDetails = () => {
|
|
10795
|
+
if (!interactive || detailLineCount === 0) return;
|
|
10796
|
+
process.stdout.write(`\x1B[${detailLineCount + 1}A`);
|
|
10797
|
+
process.stdout.write(`\x1B[K`);
|
|
10798
|
+
};
|
|
10799
|
+
const clearDetailLines = () => {
|
|
10800
|
+
if (!interactive) return;
|
|
10801
|
+
for (let i = 0; i < detailLineCount; i++) {
|
|
10802
|
+
process.stdout.write(`
|
|
10803
|
+
\x1B[K`);
|
|
10770
10804
|
}
|
|
10771
|
-
|
|
10772
|
-
}
|
|
10773
|
-
|
|
10774
|
-
|
|
10775
|
-
{ label: "Authentication", status: "pending" },
|
|
10776
|
-
{ label: "Model Provider Setup", status: "pending" },
|
|
10777
|
-
{ label: "Create Agent", status: "pending" },
|
|
10778
|
-
{ label: "Claude Plugin Install", status: "pending" },
|
|
10779
|
-
{ label: "Complete", status: "pending" }
|
|
10780
|
-
];
|
|
10805
|
+
if (detailLineCount > 0) {
|
|
10806
|
+
process.stdout.write(`\x1B[${detailLineCount}A`);
|
|
10807
|
+
}
|
|
10808
|
+
};
|
|
10781
10809
|
return {
|
|
10782
|
-
|
|
10783
|
-
|
|
10784
|
-
|
|
10785
|
-
|
|
10786
|
-
|
|
10787
|
-
|
|
10810
|
+
startStep: (label) => {
|
|
10811
|
+
currentLabel = label;
|
|
10812
|
+
detailLineCount = 0;
|
|
10813
|
+
isFinalStep = false;
|
|
10814
|
+
console.log(chalk54.yellow(`\u25CB ${label}`));
|
|
10815
|
+
},
|
|
10816
|
+
detail: (message) => {
|
|
10817
|
+
console.log(chalk54.dim(`\u2502 ${message}`));
|
|
10818
|
+
detailLineCount++;
|
|
10819
|
+
},
|
|
10820
|
+
completeStep: () => {
|
|
10821
|
+
if (interactive && detailLineCount > 0) {
|
|
10822
|
+
clearDetails();
|
|
10823
|
+
} else if (interactive) {
|
|
10824
|
+
process.stdout.write(`\x1B[1A\x1B[K`);
|
|
10825
|
+
}
|
|
10826
|
+
console.log(chalk54.green(`\u25CF ${currentLabel}`));
|
|
10827
|
+
if (interactive && detailLineCount > 0) {
|
|
10828
|
+
clearDetailLines();
|
|
10788
10829
|
}
|
|
10830
|
+
if (!isFinalStep) {
|
|
10831
|
+
console.log(chalk54.dim("\u2502"));
|
|
10832
|
+
}
|
|
10833
|
+
currentLabel = "";
|
|
10834
|
+
detailLineCount = 0;
|
|
10835
|
+
},
|
|
10836
|
+
failStep: () => {
|
|
10837
|
+
if (interactive && detailLineCount > 0) {
|
|
10838
|
+
clearDetails();
|
|
10839
|
+
} else if (interactive) {
|
|
10840
|
+
process.stdout.write(`\x1B[1A\x1B[K`);
|
|
10841
|
+
}
|
|
10842
|
+
console.log(chalk54.red(`\u2717 ${currentLabel}`));
|
|
10843
|
+
if (interactive && detailLineCount > 0) {
|
|
10844
|
+
clearDetailLines();
|
|
10845
|
+
}
|
|
10846
|
+
currentLabel = "";
|
|
10847
|
+
detailLineCount = 0;
|
|
10848
|
+
},
|
|
10849
|
+
setFinalStep: () => {
|
|
10850
|
+
isFinalStep = true;
|
|
10789
10851
|
}
|
|
10790
10852
|
};
|
|
10791
10853
|
}
|
|
@@ -11022,61 +11084,54 @@ async function installVm0Plugin(scope = "user", cwd) {
|
|
|
11022
11084
|
// src/commands/onboard/index.ts
|
|
11023
11085
|
var DEFAULT_AGENT_NAME = "my-vm0-agent";
|
|
11024
11086
|
async function handleAuthentication(ctx) {
|
|
11025
|
-
ctx.
|
|
11087
|
+
ctx.progress.startStep("Authentication");
|
|
11026
11088
|
const authenticated = await isAuthenticated();
|
|
11027
11089
|
if (authenticated) {
|
|
11028
|
-
ctx.
|
|
11090
|
+
ctx.progress.completeStep();
|
|
11029
11091
|
return;
|
|
11030
11092
|
}
|
|
11031
11093
|
if (!ctx.interactive) {
|
|
11094
|
+
ctx.progress.failStep();
|
|
11032
11095
|
console.error(chalk56.red("Error: Not authenticated"));
|
|
11033
11096
|
console.error("Run 'vm0 auth login' first or set VM0_TOKEN");
|
|
11034
11097
|
process.exit(1);
|
|
11035
11098
|
}
|
|
11036
|
-
console.log(chalk56.dim("Authentication required..."));
|
|
11037
|
-
console.log();
|
|
11038
11099
|
await runAuthFlow({
|
|
11039
11100
|
onInitiating: () => {
|
|
11040
|
-
console.log("Initiating authentication...");
|
|
11041
11101
|
},
|
|
11042
11102
|
onDeviceCodeReady: (url, code, expiresIn) => {
|
|
11043
|
-
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11047
|
-
console.log(`
|
|
11048
|
-
The code expires in ${expiresIn} minutes.`);
|
|
11049
|
-
console.log("\nWaiting for authentication...");
|
|
11103
|
+
ctx.progress.detail(`Visit: ${url}`);
|
|
11104
|
+
ctx.progress.detail(`Code: ${code}`);
|
|
11105
|
+
ctx.progress.detail(`Expires in ${expiresIn} minutes`);
|
|
11106
|
+
ctx.progress.detail("Waiting for confirmation...");
|
|
11050
11107
|
},
|
|
11051
11108
|
onPolling: () => {
|
|
11052
|
-
process.stdout.write(chalk56.dim("."));
|
|
11053
11109
|
},
|
|
11054
11110
|
onSuccess: () => {
|
|
11055
|
-
console.log(chalk56.green("\nAuthentication successful!"));
|
|
11056
|
-
console.log("Your credentials have been saved.");
|
|
11057
11111
|
},
|
|
11058
11112
|
onError: (error) => {
|
|
11113
|
+
ctx.progress.failStep();
|
|
11059
11114
|
console.error(chalk56.red(`
|
|
11060
11115
|
${error.message}`));
|
|
11061
11116
|
process.exit(1);
|
|
11062
11117
|
}
|
|
11063
11118
|
});
|
|
11064
|
-
ctx.
|
|
11119
|
+
ctx.progress.completeStep();
|
|
11065
11120
|
}
|
|
11066
11121
|
async function handleModelProvider(ctx) {
|
|
11067
|
-
ctx.
|
|
11122
|
+
ctx.progress.startStep("Model Provider Setup");
|
|
11068
11123
|
const providerStatus = await checkModelProviderStatus();
|
|
11069
11124
|
if (providerStatus.hasProvider) {
|
|
11070
|
-
ctx.
|
|
11125
|
+
ctx.progress.completeStep();
|
|
11071
11126
|
return;
|
|
11072
11127
|
}
|
|
11073
11128
|
if (!ctx.interactive) {
|
|
11129
|
+
ctx.progress.failStep();
|
|
11074
11130
|
console.error(chalk56.red("Error: No model provider configured"));
|
|
11075
11131
|
console.error("Run 'vm0 model-provider setup' first");
|
|
11076
11132
|
process.exit(1);
|
|
11077
11133
|
}
|
|
11078
|
-
|
|
11079
|
-
console.log();
|
|
11134
|
+
ctx.progress.detail("Setup required...");
|
|
11080
11135
|
const choices = getProviderChoices();
|
|
11081
11136
|
const providerType = await promptSelect(
|
|
11082
11137
|
"Select provider type:",
|
|
@@ -11090,11 +11145,6 @@ async function handleModelProvider(ctx) {
|
|
|
11090
11145
|
process.exit(0);
|
|
11091
11146
|
}
|
|
11092
11147
|
const selectedChoice = choices.find((c20) => c20.type === providerType);
|
|
11093
|
-
if (selectedChoice) {
|
|
11094
|
-
console.log();
|
|
11095
|
-
console.log(chalk56.dim(selectedChoice.helpText));
|
|
11096
|
-
console.log();
|
|
11097
|
-
}
|
|
11098
11148
|
const credential = await promptPassword(
|
|
11099
11149
|
`Enter your ${selectedChoice?.credentialLabel ?? "credential"}:`
|
|
11100
11150
|
);
|
|
@@ -11103,16 +11153,13 @@ async function handleModelProvider(ctx) {
|
|
|
11103
11153
|
process.exit(0);
|
|
11104
11154
|
}
|
|
11105
11155
|
const result = await setupModelProvider(providerType, credential);
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
`
|
|
11109
|
-
\u2713 Model provider "${providerType}" ${result.created ? "created" : "updated"}${result.isDefault ? ` (default for ${result.framework})` : ""}`
|
|
11110
|
-
)
|
|
11156
|
+
ctx.progress.detail(
|
|
11157
|
+
`${providerType} ${result.created ? "created" : "updated"}${result.isDefault ? ` (default for ${result.framework})` : ""}`
|
|
11111
11158
|
);
|
|
11112
|
-
ctx.
|
|
11159
|
+
ctx.progress.completeStep();
|
|
11113
11160
|
}
|
|
11114
11161
|
async function handleAgentCreation(ctx) {
|
|
11115
|
-
ctx.
|
|
11162
|
+
ctx.progress.startStep("Create Agent");
|
|
11116
11163
|
let agentName = ctx.options.name ?? DEFAULT_AGENT_NAME;
|
|
11117
11164
|
if (!ctx.options.yes && !ctx.options.name && ctx.interactive) {
|
|
11118
11165
|
const inputName = await promptText(
|
|
@@ -11131,6 +11178,7 @@ async function handleAgentCreation(ctx) {
|
|
|
11131
11178
|
agentName = inputName;
|
|
11132
11179
|
}
|
|
11133
11180
|
if (!validateAgentName(agentName)) {
|
|
11181
|
+
ctx.progress.failStep();
|
|
11134
11182
|
console.error(
|
|
11135
11183
|
chalk56.red(
|
|
11136
11184
|
"Invalid agent name: must be 3-64 chars, alphanumeric + hyphens"
|
|
@@ -11139,20 +11187,20 @@ async function handleAgentCreation(ctx) {
|
|
|
11139
11187
|
process.exit(1);
|
|
11140
11188
|
}
|
|
11141
11189
|
if (existsSync11(agentName)) {
|
|
11142
|
-
|
|
11143
|
-
|
|
11190
|
+
ctx.progress.failStep();
|
|
11191
|
+
console.error(chalk56.red(`${agentName}/ already exists`));
|
|
11144
11192
|
console.log();
|
|
11145
11193
|
console.log("Remove it first or choose a different name:");
|
|
11146
11194
|
console.log(chalk56.cyan(` rm -rf ${agentName}`));
|
|
11147
11195
|
process.exit(1);
|
|
11148
11196
|
}
|
|
11149
11197
|
await mkdir7(agentName, { recursive: true });
|
|
11150
|
-
|
|
11151
|
-
ctx.
|
|
11198
|
+
ctx.progress.detail(`Created ${agentName}/`);
|
|
11199
|
+
ctx.progress.completeStep();
|
|
11152
11200
|
return agentName;
|
|
11153
11201
|
}
|
|
11154
11202
|
async function handlePluginInstallation(ctx, agentName) {
|
|
11155
|
-
ctx.
|
|
11203
|
+
ctx.progress.startStep("Claude Plugin Install");
|
|
11156
11204
|
let shouldInstall = true;
|
|
11157
11205
|
if (!ctx.options.yes && ctx.interactive) {
|
|
11158
11206
|
const confirmed = await promptConfirm(
|
|
@@ -11163,21 +11211,21 @@ async function handlePluginInstallation(ctx, agentName) {
|
|
|
11163
11211
|
shouldInstall = confirmed ?? true;
|
|
11164
11212
|
}
|
|
11165
11213
|
if (!shouldInstall) {
|
|
11166
|
-
|
|
11167
|
-
ctx.
|
|
11214
|
+
ctx.progress.detail("Skipped");
|
|
11215
|
+
ctx.progress.completeStep();
|
|
11168
11216
|
return;
|
|
11169
11217
|
}
|
|
11170
11218
|
const scope = "project";
|
|
11171
11219
|
try {
|
|
11172
11220
|
const agentDir = path16.resolve(process.cwd(), agentName);
|
|
11173
11221
|
const result = await installVm0Plugin(scope, agentDir);
|
|
11174
|
-
|
|
11175
|
-
|
|
11222
|
+
ctx.progress.detail(
|
|
11223
|
+
`Installed ${result.pluginId} (scope: ${result.scope})`
|
|
11176
11224
|
);
|
|
11177
11225
|
} catch (error) {
|
|
11178
11226
|
handlePluginError(error);
|
|
11179
11227
|
}
|
|
11180
|
-
ctx.
|
|
11228
|
+
ctx.progress.completeStep();
|
|
11181
11229
|
}
|
|
11182
11230
|
function printNextSteps(agentName) {
|
|
11183
11231
|
console.log();
|
|
@@ -11195,27 +11243,15 @@ var onboardCommand = new Command56().name("onboard").description("Guided setup f
|
|
|
11195
11243
|
renderOnboardWelcome();
|
|
11196
11244
|
console.log();
|
|
11197
11245
|
}
|
|
11198
|
-
const progress =
|
|
11199
|
-
const
|
|
11200
|
-
progress.update(index, status);
|
|
11201
|
-
if (interactive) {
|
|
11202
|
-
console.clear();
|
|
11203
|
-
renderOnboardWelcome();
|
|
11204
|
-
console.log();
|
|
11205
|
-
progress.render();
|
|
11206
|
-
console.log();
|
|
11207
|
-
}
|
|
11208
|
-
};
|
|
11209
|
-
if (interactive) {
|
|
11210
|
-
progress.render();
|
|
11211
|
-
console.log();
|
|
11212
|
-
}
|
|
11213
|
-
const ctx = { interactive, options, updateProgress };
|
|
11246
|
+
const progress = createProgressiveProgress(interactive);
|
|
11247
|
+
const ctx = { interactive, options, progress };
|
|
11214
11248
|
await handleAuthentication(ctx);
|
|
11215
11249
|
await handleModelProvider(ctx);
|
|
11216
11250
|
const agentName = await handleAgentCreation(ctx);
|
|
11217
11251
|
await handlePluginInstallation(ctx, agentName);
|
|
11218
|
-
|
|
11252
|
+
progress.startStep("Complete");
|
|
11253
|
+
progress.setFinalStep();
|
|
11254
|
+
progress.completeStep();
|
|
11219
11255
|
printNextSteps(agentName);
|
|
11220
11256
|
});
|
|
11221
11257
|
|
|
@@ -11245,7 +11281,7 @@ var setupClaudeCommand = new Command57().name("setup-claude").description("Insta
|
|
|
11245
11281
|
|
|
11246
11282
|
// src/index.ts
|
|
11247
11283
|
var program = new Command58();
|
|
11248
|
-
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.
|
|
11284
|
+
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.5.0");
|
|
11249
11285
|
program.addCommand(authCommand);
|
|
11250
11286
|
program.addCommand(infoCommand);
|
|
11251
11287
|
program.addCommand(composeCommand);
|