@vm0/cli 9.0.0 → 9.1.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 +462 -41
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
5
|
-
import
|
|
4
|
+
import { Command as Command47 } from "commander";
|
|
5
|
+
import chalk48 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/lib/api/auth.ts
|
|
8
8
|
import chalk from "chalk";
|
|
@@ -86,7 +86,7 @@ async function authenticate(apiUrl) {
|
|
|
86
86
|
console.log("Initiating authentication...");
|
|
87
87
|
const deviceAuth = await requestDeviceCode(targetApiUrl);
|
|
88
88
|
console.log(chalk.green("\nDevice code generated"));
|
|
89
|
-
const verificationUrl = `${targetApiUrl}
|
|
89
|
+
const verificationUrl = `${targetApiUrl}${deviceAuth.verification_path}`;
|
|
90
90
|
console.log(chalk.cyan(`
|
|
91
91
|
To authenticate, visit: ${verificationUrl}`));
|
|
92
92
|
console.log(`And enter this code: ${chalk.bold(deviceAuth.user_code)}`);
|
|
@@ -1483,7 +1483,7 @@ var cliAuthDeviceContract = c6.router({
|
|
|
1483
1483
|
200: z8.object({
|
|
1484
1484
|
device_code: z8.string(),
|
|
1485
1485
|
user_code: z8.string(),
|
|
1486
|
-
|
|
1486
|
+
verification_path: z8.string(),
|
|
1487
1487
|
expires_in: z8.number(),
|
|
1488
1488
|
interval: z8.number()
|
|
1489
1489
|
}),
|
|
@@ -2327,6 +2327,11 @@ var timestampSchema = z18.string().datetime();
|
|
|
2327
2327
|
|
|
2328
2328
|
// ../../packages/core/src/contracts/platform.ts
|
|
2329
2329
|
var c15 = initContract();
|
|
2330
|
+
var platformPaginationSchema = z19.object({
|
|
2331
|
+
hasMore: z19.boolean(),
|
|
2332
|
+
nextCursor: z19.string().nullable(),
|
|
2333
|
+
totalPages: z19.number()
|
|
2334
|
+
});
|
|
2330
2335
|
var platformLogStatusSchema = z19.enum([
|
|
2331
2336
|
"pending",
|
|
2332
2337
|
"running",
|
|
@@ -2338,9 +2343,10 @@ var platformLogStatusSchema = z19.enum([
|
|
|
2338
2343
|
var platformLogEntrySchema = z19.object({
|
|
2339
2344
|
id: z19.string().uuid()
|
|
2340
2345
|
});
|
|
2341
|
-
var platformLogsListResponseSchema =
|
|
2342
|
-
platformLogEntrySchema
|
|
2343
|
-
|
|
2346
|
+
var platformLogsListResponseSchema = z19.object({
|
|
2347
|
+
data: z19.array(platformLogEntrySchema),
|
|
2348
|
+
pagination: platformPaginationSchema
|
|
2349
|
+
});
|
|
2344
2350
|
var artifactSchema = z19.object({
|
|
2345
2351
|
name: z19.string().nullable(),
|
|
2346
2352
|
version: z19.string().nullable()
|
|
@@ -2349,7 +2355,7 @@ var platformLogDetailSchema = z19.object({
|
|
|
2349
2355
|
id: z19.string().uuid(),
|
|
2350
2356
|
sessionId: z19.string().nullable(),
|
|
2351
2357
|
agentName: z19.string(),
|
|
2352
|
-
|
|
2358
|
+
framework: z19.string().nullable(),
|
|
2353
2359
|
status: platformLogStatusSchema,
|
|
2354
2360
|
prompt: z19.string(),
|
|
2355
2361
|
error: z19.string().nullable(),
|
|
@@ -2387,6 +2393,26 @@ var platformLogsByIdContract = c15.router({
|
|
|
2387
2393
|
summary: "Get agent run log details by ID"
|
|
2388
2394
|
}
|
|
2389
2395
|
});
|
|
2396
|
+
var artifactDownloadResponseSchema = z19.object({
|
|
2397
|
+
url: z19.string().url(),
|
|
2398
|
+
expiresAt: z19.string()
|
|
2399
|
+
});
|
|
2400
|
+
var platformArtifactDownloadContract = c15.router({
|
|
2401
|
+
getDownloadUrl: {
|
|
2402
|
+
method: "GET",
|
|
2403
|
+
path: "/api/platform/artifacts/download",
|
|
2404
|
+
query: z19.object({
|
|
2405
|
+
name: z19.string().min(1, "Artifact name is required"),
|
|
2406
|
+
version: z19.string().optional()
|
|
2407
|
+
}),
|
|
2408
|
+
responses: {
|
|
2409
|
+
200: artifactDownloadResponseSchema,
|
|
2410
|
+
401: apiErrorSchema,
|
|
2411
|
+
404: apiErrorSchema
|
|
2412
|
+
},
|
|
2413
|
+
summary: "Get presigned URL for artifact download"
|
|
2414
|
+
}
|
|
2415
|
+
});
|
|
2390
2416
|
|
|
2391
2417
|
// ../../packages/core/src/contracts/public/agents.ts
|
|
2392
2418
|
import { z as z20 } from "zod";
|
|
@@ -3094,10 +3120,10 @@ async function getRawHeaders() {
|
|
|
3094
3120
|
}
|
|
3095
3121
|
return headers;
|
|
3096
3122
|
}
|
|
3097
|
-
async function httpGet(
|
|
3123
|
+
async function httpGet(path15) {
|
|
3098
3124
|
const baseUrl = await getBaseUrl();
|
|
3099
3125
|
const headers = await getRawHeaders();
|
|
3100
|
-
return fetch(`${baseUrl}${
|
|
3126
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
3101
3127
|
method: "GET",
|
|
3102
3128
|
headers
|
|
3103
3129
|
});
|
|
@@ -3577,49 +3603,49 @@ var cliComposeSchema = z24.object({
|
|
|
3577
3603
|
function formatZodError(error) {
|
|
3578
3604
|
const issue = error.issues[0];
|
|
3579
3605
|
if (!issue) return "Validation failed";
|
|
3580
|
-
const
|
|
3606
|
+
const path15 = issue.path.join(".");
|
|
3581
3607
|
const message = issue.message;
|
|
3582
|
-
if (!
|
|
3608
|
+
if (!path15) return message;
|
|
3583
3609
|
if (issue.code === "invalid_type") {
|
|
3584
3610
|
const received = issue.received;
|
|
3585
3611
|
const isMissing = received === "undefined" || message.includes("received undefined") || message === "Required";
|
|
3586
|
-
if (
|
|
3612
|
+
if (path15 === "version" && isMissing) {
|
|
3587
3613
|
return "Missing config.version";
|
|
3588
3614
|
}
|
|
3589
|
-
if (
|
|
3615
|
+
if (path15 === "agents" && isMissing) {
|
|
3590
3616
|
return "Missing agents object in config";
|
|
3591
3617
|
}
|
|
3592
|
-
if (
|
|
3593
|
-
const volumeKey =
|
|
3618
|
+
if (path15.startsWith("volumes.") && path15.endsWith(".name")) {
|
|
3619
|
+
const volumeKey = path15.split(".")[1];
|
|
3594
3620
|
return `Volume "${volumeKey}" must have a 'name' field (string)`;
|
|
3595
3621
|
}
|
|
3596
|
-
if (
|
|
3597
|
-
const volumeKey =
|
|
3622
|
+
if (path15.startsWith("volumes.") && path15.endsWith(".version")) {
|
|
3623
|
+
const volumeKey = path15.split(".")[1];
|
|
3598
3624
|
return `Volume "${volumeKey}" must have a 'version' field (string)`;
|
|
3599
3625
|
}
|
|
3600
3626
|
if (issue.expected === "array") {
|
|
3601
|
-
const fieldName =
|
|
3627
|
+
const fieldName = path15.replace(/^agents\.[^.]+\./, "agent.");
|
|
3602
3628
|
return `${fieldName} must be an array`;
|
|
3603
3629
|
}
|
|
3604
3630
|
if (issue.expected === "string" && received === "number") {
|
|
3605
|
-
const fieldName =
|
|
3631
|
+
const fieldName = path15.replace(/^agents\.[^.]+\./, "agent.");
|
|
3606
3632
|
const match = fieldName.match(/^(agent\.[^.]+)\.\d+$/);
|
|
3607
3633
|
if (match) {
|
|
3608
3634
|
return `Each entry in ${match[1]?.replace("agent.", "")} must be a string`;
|
|
3609
3635
|
}
|
|
3610
3636
|
}
|
|
3611
3637
|
}
|
|
3612
|
-
if (issue.code === "invalid_key" &&
|
|
3638
|
+
if (issue.code === "invalid_key" && path15.startsWith("agents.")) {
|
|
3613
3639
|
return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
|
|
3614
3640
|
}
|
|
3615
|
-
if (message === "Invalid key in record" &&
|
|
3641
|
+
if (message === "Invalid key in record" && path15.startsWith("agents.")) {
|
|
3616
3642
|
return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
|
|
3617
3643
|
}
|
|
3618
3644
|
if (issue.code === "custom") {
|
|
3619
3645
|
return message;
|
|
3620
3646
|
}
|
|
3621
|
-
if (
|
|
3622
|
-
const cleanPath =
|
|
3647
|
+
if (path15.startsWith("agents.")) {
|
|
3648
|
+
const cleanPath = path15.replace(/^agents\.[^.]+\./, "agent.");
|
|
3623
3649
|
if (message.startsWith("Invalid input:")) {
|
|
3624
3650
|
const match = message.match(/expected (\w+), received (\w+)/);
|
|
3625
3651
|
if (match && match[1] === "string" && match[2] === "number") {
|
|
@@ -3631,7 +3657,7 @@ function formatZodError(error) {
|
|
|
3631
3657
|
}
|
|
3632
3658
|
return `${cleanPath}: ${message}`;
|
|
3633
3659
|
}
|
|
3634
|
-
return `${
|
|
3660
|
+
return `${path15}: ${message}`;
|
|
3635
3661
|
}
|
|
3636
3662
|
function validateAgentName(name) {
|
|
3637
3663
|
return cliAgentNameSchema.safeParse(name).success;
|
|
@@ -5834,7 +5860,7 @@ var ApiClient = class {
|
|
|
5834
5860
|
/**
|
|
5835
5861
|
* Generic GET request
|
|
5836
5862
|
*/
|
|
5837
|
-
async get(
|
|
5863
|
+
async get(path15) {
|
|
5838
5864
|
const baseUrl = await this.getBaseUrl();
|
|
5839
5865
|
const token = await getToken();
|
|
5840
5866
|
if (!token) {
|
|
@@ -5847,7 +5873,7 @@ var ApiClient = class {
|
|
|
5847
5873
|
if (bypassSecret) {
|
|
5848
5874
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
5849
5875
|
}
|
|
5850
|
-
return fetch(`${baseUrl}${
|
|
5876
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
5851
5877
|
method: "GET",
|
|
5852
5878
|
headers
|
|
5853
5879
|
});
|
|
@@ -5855,7 +5881,7 @@ var ApiClient = class {
|
|
|
5855
5881
|
/**
|
|
5856
5882
|
* Generic POST request
|
|
5857
5883
|
*/
|
|
5858
|
-
async post(
|
|
5884
|
+
async post(path15, options) {
|
|
5859
5885
|
const baseUrl = await this.getBaseUrl();
|
|
5860
5886
|
const token = await getToken();
|
|
5861
5887
|
if (!token) {
|
|
@@ -5871,7 +5897,7 @@ var ApiClient = class {
|
|
|
5871
5897
|
if (bypassSecret) {
|
|
5872
5898
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
5873
5899
|
}
|
|
5874
|
-
return fetch(`${baseUrl}${
|
|
5900
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
5875
5901
|
method: "POST",
|
|
5876
5902
|
headers,
|
|
5877
5903
|
body: options?.body
|
|
@@ -5880,7 +5906,7 @@ var ApiClient = class {
|
|
|
5880
5906
|
/**
|
|
5881
5907
|
* Generic DELETE request
|
|
5882
5908
|
*/
|
|
5883
|
-
async delete(
|
|
5909
|
+
async delete(path15) {
|
|
5884
5910
|
const baseUrl = await this.getBaseUrl();
|
|
5885
5911
|
const token = await getToken();
|
|
5886
5912
|
if (!token) {
|
|
@@ -5893,7 +5919,7 @@ var ApiClient = class {
|
|
|
5893
5919
|
if (bypassSecret) {
|
|
5894
5920
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
5895
5921
|
}
|
|
5896
|
-
return fetch(`${baseUrl}${
|
|
5922
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
5897
5923
|
method: "DELETE",
|
|
5898
5924
|
headers
|
|
5899
5925
|
});
|
|
@@ -7888,7 +7914,7 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
|
7888
7914
|
// eslint-disable-next-line complexity -- TODO: refactor complex function
|
|
7889
7915
|
async (prompt, options) => {
|
|
7890
7916
|
if (!options.noAutoUpdate) {
|
|
7891
|
-
const shouldExit = await checkAndUpgrade("9.
|
|
7917
|
+
const shouldExit = await checkAndUpgrade("9.1.0", prompt);
|
|
7892
7918
|
if (shouldExit) {
|
|
7893
7919
|
process.exit(0);
|
|
7894
7920
|
}
|
|
@@ -9568,7 +9594,7 @@ Deploying schedule for agent ${chalk32.cyan(params.agentName)}...`
|
|
|
9568
9594
|
secrets: expandedSecrets,
|
|
9569
9595
|
artifactName: params.artifactName
|
|
9570
9596
|
});
|
|
9571
|
-
|
|
9597
|
+
return deployResult;
|
|
9572
9598
|
}
|
|
9573
9599
|
function handleSetupError(error) {
|
|
9574
9600
|
console.error(chalk32.red("\u2717 Failed to setup schedule"));
|
|
@@ -9608,14 +9634,53 @@ function displayDeployResult(agentName, deployResult) {
|
|
|
9608
9634
|
);
|
|
9609
9635
|
console.log(chalk32.dim(` At: ${atTimeFormatted}`));
|
|
9610
9636
|
}
|
|
9611
|
-
|
|
9612
|
-
|
|
9637
|
+
}
|
|
9638
|
+
async function tryEnableSchedule(scheduleName, composeId, agentName) {
|
|
9639
|
+
try {
|
|
9640
|
+
await enableSchedule({ name: scheduleName, composeId });
|
|
9613
9641
|
console.log(
|
|
9614
|
-
|
|
9642
|
+
chalk32.green(`\u2713 Enabled schedule for agent ${chalk32.cyan(agentName)}`)
|
|
9643
|
+
);
|
|
9644
|
+
} catch (error) {
|
|
9645
|
+
console.error(chalk32.yellow("\u26A0 Failed to enable schedule"));
|
|
9646
|
+
if (error instanceof ApiRequestError) {
|
|
9647
|
+
if (error.code === "SCHEDULE_PAST") {
|
|
9648
|
+
console.error(chalk32.dim(" Scheduled time has already passed"));
|
|
9649
|
+
} else {
|
|
9650
|
+
console.error(chalk32.dim(` ${error.message}`));
|
|
9651
|
+
}
|
|
9652
|
+
} else if (error instanceof Error) {
|
|
9653
|
+
console.error(chalk32.dim(` ${error.message}`));
|
|
9654
|
+
}
|
|
9655
|
+
console.log(
|
|
9656
|
+
` To enable manually: ${chalk32.cyan(`vm0 schedule enable ${agentName}`)}`
|
|
9615
9657
|
);
|
|
9616
9658
|
}
|
|
9617
9659
|
}
|
|
9618
|
-
|
|
9660
|
+
function showEnableHint(agentName) {
|
|
9661
|
+
console.log();
|
|
9662
|
+
console.log(` To enable: ${chalk32.cyan(`vm0 schedule enable ${agentName}`)}`);
|
|
9663
|
+
}
|
|
9664
|
+
async function handleScheduleEnabling(params) {
|
|
9665
|
+
const { scheduleName, composeId, agentName, enableFlag, shouldPromptEnable } = params;
|
|
9666
|
+
if (enableFlag) {
|
|
9667
|
+
await tryEnableSchedule(scheduleName, composeId, agentName);
|
|
9668
|
+
return;
|
|
9669
|
+
}
|
|
9670
|
+
if (shouldPromptEnable && isInteractive()) {
|
|
9671
|
+
const enableNow = await promptConfirm("Enable this schedule?", true);
|
|
9672
|
+
if (enableNow) {
|
|
9673
|
+
await tryEnableSchedule(scheduleName, composeId, agentName);
|
|
9674
|
+
} else {
|
|
9675
|
+
showEnableHint(agentName);
|
|
9676
|
+
}
|
|
9677
|
+
return;
|
|
9678
|
+
}
|
|
9679
|
+
if (shouldPromptEnable) {
|
|
9680
|
+
showEnableHint(agentName);
|
|
9681
|
+
}
|
|
9682
|
+
}
|
|
9683
|
+
var setupCommand = new Command28().name("setup").description("Create or edit a schedule for an agent").argument("<agent-name>", "Agent name to configure schedule for").option("-f, --frequency <type>", "Frequency: daily|weekly|monthly|once").option("-t, --time <HH:MM>", "Time to run (24-hour format)").option("-d, --day <day>", "Day of week (mon-sun) or day of month (1-31)").option("-z, --timezone <tz>", "IANA timezone").option("-p, --prompt <text>", "Prompt to run").option("--var <name=value>", "Variable (can be repeated)", collect, []).option("--secret <name=value>", "Secret (can be repeated)", collect, []).option("--artifact-name <name>", "Artifact name", "artifact").option("-e, --enable", "Enable schedule immediately after creation").action(async (agentName, options) => {
|
|
9619
9684
|
try {
|
|
9620
9685
|
const { composeId, scheduleName, composeContent } = await resolveAgent(agentName);
|
|
9621
9686
|
const requiredConfig = extractRequiredConfiguration(composeContent);
|
|
@@ -9662,7 +9727,7 @@ var setupCommand = new Command28().name("setup").description("Create or edit a s
|
|
|
9662
9727
|
optionVars: options.var || [],
|
|
9663
9728
|
existingSchedule
|
|
9664
9729
|
});
|
|
9665
|
-
await buildAndDeploy({
|
|
9730
|
+
const deployResult = await buildAndDeploy({
|
|
9666
9731
|
scheduleName,
|
|
9667
9732
|
composeId,
|
|
9668
9733
|
agentName,
|
|
@@ -9676,6 +9741,15 @@ var setupCommand = new Command28().name("setup").description("Create or edit a s
|
|
|
9676
9741
|
secrets: config.preserveExistingSecrets ? void 0 : Object.keys(config.secrets).length > 0 ? config.secrets : void 0,
|
|
9677
9742
|
artifactName: options.artifactName
|
|
9678
9743
|
});
|
|
9744
|
+
displayDeployResult(agentName, deployResult);
|
|
9745
|
+
const shouldPromptEnable = deployResult.created || existingSchedule !== void 0 && !existingSchedule.enabled;
|
|
9746
|
+
await handleScheduleEnabling({
|
|
9747
|
+
scheduleName,
|
|
9748
|
+
composeId,
|
|
9749
|
+
agentName,
|
|
9750
|
+
enableFlag: options.enable ?? false,
|
|
9751
|
+
shouldPromptEnable
|
|
9752
|
+
});
|
|
9679
9753
|
} catch (error) {
|
|
9680
9754
|
handleSetupError(error);
|
|
9681
9755
|
}
|
|
@@ -10555,11 +10629,356 @@ var setDefaultCommand = new Command43().name("set-default").description("Set a m
|
|
|
10555
10629
|
// src/commands/model-provider/index.ts
|
|
10556
10630
|
var modelProviderCommand = new Command44().name("model-provider").description("Manage model providers for agent runs").addCommand(listCommand6).addCommand(setupCommand2).addCommand(deleteCommand3).addCommand(setDefaultCommand);
|
|
10557
10631
|
|
|
10632
|
+
// src/commands/onboard.ts
|
|
10633
|
+
import { Command as Command46 } from "commander";
|
|
10634
|
+
import chalk47 from "chalk";
|
|
10635
|
+
import prompts3 from "prompts";
|
|
10636
|
+
import { mkdir as mkdir8 } from "fs/promises";
|
|
10637
|
+
import { existsSync as existsSync10 } from "fs";
|
|
10638
|
+
|
|
10639
|
+
// src/commands/setup-claude.ts
|
|
10640
|
+
import { Command as Command45 } from "commander";
|
|
10641
|
+
import chalk46 from "chalk";
|
|
10642
|
+
import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
|
|
10643
|
+
import path14 from "path";
|
|
10644
|
+
var SKILL_DIR = ".claude/skills/vm0-agent-builder";
|
|
10645
|
+
var SKILL_CONTENT = `---
|
|
10646
|
+
name: vm0-agent-builder
|
|
10647
|
+
description: Guide for building VM0 agents with Claude's help. Use this skill when users want to create or improve their agent's AGENTS.md and vm0.yaml configuration.
|
|
10648
|
+
---
|
|
10649
|
+
|
|
10650
|
+
# VM0 Agent Builder
|
|
10651
|
+
|
|
10652
|
+
Help users create effective AI agents using the VM0 platform. This skill guides the process of designing agent workflows, writing AGENTS.md instructions, and configuring vm0.yaml.
|
|
10653
|
+
|
|
10654
|
+
## When to Use
|
|
10655
|
+
|
|
10656
|
+
- User wants to create a new VM0 agent from scratch
|
|
10657
|
+
- User wants to improve an existing agent's instructions
|
|
10658
|
+
- User needs help configuring vm0.yaml with skills
|
|
10659
|
+
- User is unsure how to structure their agent's workflow
|
|
10660
|
+
|
|
10661
|
+
## Workflow
|
|
10662
|
+
|
|
10663
|
+
### Step 1: Understand the Goal
|
|
10664
|
+
|
|
10665
|
+
Ask the user what they want their agent to accomplish:
|
|
10666
|
+
- What is the main task or problem to solve?
|
|
10667
|
+
- What inputs will the agent receive?
|
|
10668
|
+
- What outputs should the agent produce?
|
|
10669
|
+
- Are there any constraints or requirements?
|
|
10670
|
+
|
|
10671
|
+
### Step 2: Design the Workflow
|
|
10672
|
+
|
|
10673
|
+
Break down the task into clear, sequential steps:
|
|
10674
|
+
1. Each step should be a single, focused action
|
|
10675
|
+
2. Steps should build on each other logically
|
|
10676
|
+
3. Include error handling and edge cases
|
|
10677
|
+
4. Consider what tools/skills the agent will need
|
|
10678
|
+
|
|
10679
|
+
### Step 3: Write AGENTS.md
|
|
10680
|
+
|
|
10681
|
+
Create the agent instructions file with:
|
|
10682
|
+
|
|
10683
|
+
\`\`\`markdown
|
|
10684
|
+
# Agent Instructions
|
|
10685
|
+
|
|
10686
|
+
You are a [role description].
|
|
10687
|
+
|
|
10688
|
+
## Goal
|
|
10689
|
+
|
|
10690
|
+
[Clear statement of what the agent should accomplish]
|
|
10691
|
+
|
|
10692
|
+
## Workflow
|
|
10693
|
+
|
|
10694
|
+
1. [First step with specific instructions]
|
|
10695
|
+
2. [Second step with specific instructions]
|
|
10696
|
+
3. [Continue with remaining steps...]
|
|
10697
|
+
|
|
10698
|
+
## Output
|
|
10699
|
+
|
|
10700
|
+
[Describe the expected output format and location]
|
|
10701
|
+
|
|
10702
|
+
## Constraints
|
|
10703
|
+
|
|
10704
|
+
[Any limitations or rules the agent should follow]
|
|
10705
|
+
\`\`\`
|
|
10706
|
+
|
|
10707
|
+
### Step 4: Configure vm0.yaml
|
|
10708
|
+
|
|
10709
|
+
Update the vm0.yaml to include necessary skills:
|
|
10710
|
+
|
|
10711
|
+
\`\`\`yaml
|
|
10712
|
+
version: "1.0"
|
|
10713
|
+
|
|
10714
|
+
agents:
|
|
10715
|
+
agent-name:
|
|
10716
|
+
framework: claude-code
|
|
10717
|
+
instructions: AGENTS.md
|
|
10718
|
+
skills:
|
|
10719
|
+
- https://github.com/vm0-ai/vm0-skills/tree/main/skill-name
|
|
10720
|
+
environment:
|
|
10721
|
+
# Add any required environment variables
|
|
10722
|
+
API_KEY: "\${{ secrets.API_KEY }}"
|
|
10723
|
+
\`\`\`
|
|
10724
|
+
|
|
10725
|
+
### Step 5: Test the Agent
|
|
10726
|
+
|
|
10727
|
+
Guide the user to test their agent:
|
|
10728
|
+
|
|
10729
|
+
\`\`\`bash
|
|
10730
|
+
# Deploy the agent configuration
|
|
10731
|
+
vm0 compose vm0.yaml
|
|
10732
|
+
|
|
10733
|
+
# Run the agent with a test prompt
|
|
10734
|
+
vm0 cook "start working on the task"
|
|
10735
|
+
|
|
10736
|
+
# Check the logs if needed
|
|
10737
|
+
vm0 logs <run-id>
|
|
10738
|
+
\`\`\`
|
|
10739
|
+
|
|
10740
|
+
## Available Skills
|
|
10741
|
+
|
|
10742
|
+
Common skills from vm0-skills repository:
|
|
10743
|
+
|
|
10744
|
+
| Skill | Purpose |
|
|
10745
|
+
|-------|---------|
|
|
10746
|
+
| \`github\` | GitHub API operations (issues, PRs, repos) |
|
|
10747
|
+
| \`slack\` | Send messages to Slack channels |
|
|
10748
|
+
| \`notion\` | Read/write Notion pages and databases |
|
|
10749
|
+
| \`firecrawl\` | Web scraping and content extraction |
|
|
10750
|
+
| \`browserbase\` | Browser automation |
|
|
10751
|
+
| \`openai\` | OpenAI API for embeddings, completions |
|
|
10752
|
+
| \`supabase\` | Database operations with Supabase |
|
|
10753
|
+
|
|
10754
|
+
Browse all skills: https://github.com/vm0-ai/vm0-skills
|
|
10755
|
+
|
|
10756
|
+
## Example Agents
|
|
10757
|
+
|
|
10758
|
+
### Content Curator Agent
|
|
10759
|
+
|
|
10760
|
+
\`\`\`markdown
|
|
10761
|
+
# Agent Instructions
|
|
10762
|
+
|
|
10763
|
+
You are a content curator that monitors HackerNews for AI-related articles.
|
|
10764
|
+
|
|
10765
|
+
## Workflow
|
|
10766
|
+
|
|
10767
|
+
1. Go to HackerNews and read the top 30 stories
|
|
10768
|
+
2. Filter for AI, ML, and LLM related content
|
|
10769
|
+
3. For each relevant article, extract:
|
|
10770
|
+
- Title and URL
|
|
10771
|
+
- Key points (2-3 sentences)
|
|
10772
|
+
- Why it's interesting
|
|
10773
|
+
4. Write a summary to \`daily-digest.md\`
|
|
10774
|
+
|
|
10775
|
+
## Output
|
|
10776
|
+
|
|
10777
|
+
Create \`daily-digest.md\` with today's date as the header.
|
|
10778
|
+
\`\`\`
|
|
10779
|
+
|
|
10780
|
+
### GitHub Issue Tracker Agent
|
|
10781
|
+
|
|
10782
|
+
\`\`\`markdown
|
|
10783
|
+
# Agent Instructions
|
|
10784
|
+
|
|
10785
|
+
You are a GitHub issue tracker that summarizes open issues.
|
|
10786
|
+
|
|
10787
|
+
## Workflow
|
|
10788
|
+
|
|
10789
|
+
1. List all open issues in the repository
|
|
10790
|
+
2. Group issues by labels (bug, feature, docs)
|
|
10791
|
+
3. For each group, summarize:
|
|
10792
|
+
- Number of issues
|
|
10793
|
+
- Oldest issue age
|
|
10794
|
+
- Most discussed issues
|
|
10795
|
+
4. Create a report in \`issue-report.md\`
|
|
10796
|
+
|
|
10797
|
+
## Skills Required
|
|
10798
|
+
|
|
10799
|
+
- github (for API access)
|
|
10800
|
+
\`\`\`
|
|
10801
|
+
|
|
10802
|
+
### Data Pipeline Agent
|
|
10803
|
+
|
|
10804
|
+
\`\`\`markdown
|
|
10805
|
+
# Agent Instructions
|
|
10806
|
+
|
|
10807
|
+
You are a data pipeline agent that processes CSV files.
|
|
10808
|
+
|
|
10809
|
+
## Workflow
|
|
10810
|
+
|
|
10811
|
+
1. Read all CSV files from the input volume
|
|
10812
|
+
2. For each file:
|
|
10813
|
+
- Validate the schema
|
|
10814
|
+
- Clean missing values
|
|
10815
|
+
- Transform dates to ISO format
|
|
10816
|
+
3. Merge all files into \`combined.csv\`
|
|
10817
|
+
4. Generate a summary report
|
|
10818
|
+
|
|
10819
|
+
## Input
|
|
10820
|
+
|
|
10821
|
+
Files are provided via volume mount.
|
|
10822
|
+
|
|
10823
|
+
## Output
|
|
10824
|
+
|
|
10825
|
+
Write results to the artifact directory.
|
|
10826
|
+
\`\`\`
|
|
10827
|
+
|
|
10828
|
+
## Best Practices
|
|
10829
|
+
|
|
10830
|
+
1. **Be Specific**: Vague instructions lead to unpredictable results
|
|
10831
|
+
2. **One Task Per Step**: Keep workflow steps focused and atomic
|
|
10832
|
+
3. **Define Output Clearly**: Specify exact file names and formats
|
|
10833
|
+
4. **Handle Errors**: Include what to do when things go wrong
|
|
10834
|
+
5. **Test Incrementally**: Start with simple workflows, add complexity
|
|
10835
|
+
6. **Use Skills Wisely**: Only include skills the agent actually needs
|
|
10836
|
+
|
|
10837
|
+
## Troubleshooting
|
|
10838
|
+
|
|
10839
|
+
### Agent doesn't follow instructions
|
|
10840
|
+
- Make instructions more specific and explicit
|
|
10841
|
+
- Add examples of expected behavior
|
|
10842
|
+
- Break complex steps into smaller sub-steps
|
|
10843
|
+
|
|
10844
|
+
### Agent uses wrong tools
|
|
10845
|
+
- Specify which tools/skills to use for each step
|
|
10846
|
+
- Add constraints about what NOT to do
|
|
10847
|
+
|
|
10848
|
+
### Output format is wrong
|
|
10849
|
+
- Provide exact templates for output files
|
|
10850
|
+
- Include example output in the instructions
|
|
10851
|
+
`;
|
|
10852
|
+
var setupClaudeCommand = new Command45().name("setup-claude").description("Add/update Claude skill for agent building").action(async () => {
|
|
10853
|
+
console.log(chalk46.dim("Installing vm0-agent-builder skill..."));
|
|
10854
|
+
await mkdir7(SKILL_DIR, { recursive: true });
|
|
10855
|
+
await writeFile7(path14.join(SKILL_DIR, "SKILL.md"), SKILL_CONTENT);
|
|
10856
|
+
console.log(
|
|
10857
|
+
chalk46.green(`Done Installed vm0-agent-builder skill to ${SKILL_DIR}`)
|
|
10858
|
+
);
|
|
10859
|
+
console.log();
|
|
10860
|
+
console.log("Next step:");
|
|
10861
|
+
console.log(
|
|
10862
|
+
chalk46.cyan(
|
|
10863
|
+
' claude /vm0-agent-builder "I want to build an agent that..."'
|
|
10864
|
+
)
|
|
10865
|
+
);
|
|
10866
|
+
});
|
|
10867
|
+
|
|
10868
|
+
// src/commands/onboard.ts
|
|
10869
|
+
var DEMO_AGENT_DIR = "vm0-demo-agent";
|
|
10870
|
+
var DEMO_AGENT_NAME = "vm0-demo-agent";
|
|
10871
|
+
var onboardCommand = new Command46().name("onboard").description("Guided setup for new VM0 users").option("-y, --yes", "Skip confirmation prompts").option(
|
|
10872
|
+
"--method <method>",
|
|
10873
|
+
"Agent building method: claude or manual",
|
|
10874
|
+
void 0
|
|
10875
|
+
).action(async (options) => {
|
|
10876
|
+
const token = await getToken();
|
|
10877
|
+
if (token) {
|
|
10878
|
+
console.log(chalk47.green("Done Authenticated"));
|
|
10879
|
+
} else {
|
|
10880
|
+
console.log(chalk47.dim("Authentication required..."));
|
|
10881
|
+
console.log();
|
|
10882
|
+
await authenticate();
|
|
10883
|
+
}
|
|
10884
|
+
try {
|
|
10885
|
+
const result = await listModelProviders();
|
|
10886
|
+
if (result.modelProviders.length > 0) {
|
|
10887
|
+
console.log(chalk47.green("Done Model provider configured"));
|
|
10888
|
+
} else {
|
|
10889
|
+
console.log(chalk47.yellow("! No model provider configured"));
|
|
10890
|
+
console.log();
|
|
10891
|
+
console.log("Run the following to set up:");
|
|
10892
|
+
console.log(chalk47.cyan(" vm0 model-provider setup"));
|
|
10893
|
+
console.log();
|
|
10894
|
+
}
|
|
10895
|
+
} catch (error) {
|
|
10896
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10897
|
+
console.log(
|
|
10898
|
+
chalk47.yellow(`! Could not check model provider status: ${message}`)
|
|
10899
|
+
);
|
|
10900
|
+
console.log();
|
|
10901
|
+
}
|
|
10902
|
+
let createAgent = options.yes;
|
|
10903
|
+
if (!createAgent && isInteractive()) {
|
|
10904
|
+
const response = await prompts3(
|
|
10905
|
+
{
|
|
10906
|
+
type: "confirm",
|
|
10907
|
+
name: "create",
|
|
10908
|
+
message: `Create ${DEMO_AGENT_DIR}?`,
|
|
10909
|
+
initial: true
|
|
10910
|
+
},
|
|
10911
|
+
{ onCancel: () => process.exit(0) }
|
|
10912
|
+
);
|
|
10913
|
+
createAgent = response.create;
|
|
10914
|
+
}
|
|
10915
|
+
if (!createAgent) {
|
|
10916
|
+
console.log(chalk47.dim("Skipped agent creation"));
|
|
10917
|
+
return;
|
|
10918
|
+
}
|
|
10919
|
+
if (existsSync10(DEMO_AGENT_DIR)) {
|
|
10920
|
+
console.log(chalk47.red(`x ${DEMO_AGENT_DIR}/ already exists`));
|
|
10921
|
+
console.log();
|
|
10922
|
+
console.log("Remove it first or use a different directory:");
|
|
10923
|
+
console.log(chalk47.cyan(` rm -rf ${DEMO_AGENT_DIR}`));
|
|
10924
|
+
process.exit(1);
|
|
10925
|
+
}
|
|
10926
|
+
await mkdir8(DEMO_AGENT_DIR, { recursive: true });
|
|
10927
|
+
const originalDir = process.cwd();
|
|
10928
|
+
process.chdir(DEMO_AGENT_DIR);
|
|
10929
|
+
try {
|
|
10930
|
+
await initCommand3.parseAsync(["--name", DEMO_AGENT_NAME], {
|
|
10931
|
+
from: "user"
|
|
10932
|
+
});
|
|
10933
|
+
} finally {
|
|
10934
|
+
process.chdir(originalDir);
|
|
10935
|
+
}
|
|
10936
|
+
console.log();
|
|
10937
|
+
let method = options.method;
|
|
10938
|
+
if (!method && isInteractive()) {
|
|
10939
|
+
const response = await prompts3(
|
|
10940
|
+
{
|
|
10941
|
+
type: "select",
|
|
10942
|
+
name: "method",
|
|
10943
|
+
message: "How would you like to build your agent?",
|
|
10944
|
+
choices: [
|
|
10945
|
+
{
|
|
10946
|
+
title: "Use `vm0 setup-claude` to let Claude help (Recommended)",
|
|
10947
|
+
value: "claude"
|
|
10948
|
+
},
|
|
10949
|
+
{
|
|
10950
|
+
title: "I will do it myself (Edit `AGENTS.md` and `vm0.yaml`)",
|
|
10951
|
+
value: "manual"
|
|
10952
|
+
}
|
|
10953
|
+
]
|
|
10954
|
+
},
|
|
10955
|
+
{ onCancel: () => process.exit(0) }
|
|
10956
|
+
);
|
|
10957
|
+
method = response.method;
|
|
10958
|
+
}
|
|
10959
|
+
if (method === "claude") {
|
|
10960
|
+
process.chdir(DEMO_AGENT_DIR);
|
|
10961
|
+
try {
|
|
10962
|
+
await setupClaudeCommand.parseAsync([], { from: "user" });
|
|
10963
|
+
} finally {
|
|
10964
|
+
process.chdir(originalDir);
|
|
10965
|
+
}
|
|
10966
|
+
} else {
|
|
10967
|
+
console.log("Next steps:");
|
|
10968
|
+
console.log(` 1. ${chalk47.cyan(`cd ${DEMO_AGENT_DIR}`)}`);
|
|
10969
|
+
console.log(
|
|
10970
|
+
` 2. Edit ${chalk47.cyan("AGENTS.md")} to define your agent's workflow`
|
|
10971
|
+
);
|
|
10972
|
+
console.log(` 3. Edit ${chalk47.cyan("vm0.yaml")} to configure skills`);
|
|
10973
|
+
console.log(` 4. Run ${chalk47.cyan('vm0 cook "start working"')} to test`);
|
|
10974
|
+
}
|
|
10975
|
+
});
|
|
10976
|
+
|
|
10558
10977
|
// src/index.ts
|
|
10559
|
-
var program = new
|
|
10560
|
-
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.
|
|
10978
|
+
var program = new Command47();
|
|
10979
|
+
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.1.0");
|
|
10561
10980
|
program.command("info").description("Display environment information").action(async () => {
|
|
10562
|
-
console.log(
|
|
10981
|
+
console.log(chalk48.bold("System Information:"));
|
|
10563
10982
|
console.log(`Node Version: ${process.version}`);
|
|
10564
10983
|
console.log(`Platform: ${process.platform}`);
|
|
10565
10984
|
console.log(`Architecture: ${process.arch}`);
|
|
@@ -10592,6 +11011,8 @@ program.addCommand(scheduleCommand);
|
|
|
10592
11011
|
program.addCommand(usageCommand);
|
|
10593
11012
|
program.addCommand(credentialCommand);
|
|
10594
11013
|
program.addCommand(modelProviderCommand);
|
|
11014
|
+
program.addCommand(onboardCommand);
|
|
11015
|
+
program.addCommand(setupClaudeCommand);
|
|
10595
11016
|
if (process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("vm0")) {
|
|
10596
11017
|
program.parse();
|
|
10597
11018
|
}
|