@vm0/cli 4.29.1 → 4.31.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 +240 -50
- package/package.json +2 -1
package/index.js
CHANGED
|
@@ -190,10 +190,11 @@ async function setupToken() {
|
|
|
190
190
|
// src/commands/compose.ts
|
|
191
191
|
import { Command } from "commander";
|
|
192
192
|
import chalk2 from "chalk";
|
|
193
|
-
import { readFile as
|
|
193
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
194
194
|
import { existsSync as existsSync3 } from "fs";
|
|
195
195
|
import { dirname as dirname2 } from "path";
|
|
196
|
-
import { parse as
|
|
196
|
+
import { parse as parseYaml2 } from "yaml";
|
|
197
|
+
import prompts from "prompts";
|
|
197
198
|
|
|
198
199
|
// ../../packages/core/src/variable-expander.ts
|
|
199
200
|
var VARIABLE_PATTERN = /\$\{\{\s*(env|vars|secrets)\.([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
|
|
@@ -12616,7 +12617,8 @@ var runSystemLogContract = c2.router({
|
|
|
12616
12617
|
}),
|
|
12617
12618
|
query: external_exports.object({
|
|
12618
12619
|
since: external_exports.coerce.number().optional(),
|
|
12619
|
-
limit: external_exports.coerce.number().min(1).max(100).default(5)
|
|
12620
|
+
limit: external_exports.coerce.number().min(1).max(100).default(5),
|
|
12621
|
+
order: external_exports.enum(["asc", "desc"]).default("desc")
|
|
12620
12622
|
}),
|
|
12621
12623
|
responses: {
|
|
12622
12624
|
200: systemLogResponseSchema,
|
|
@@ -12639,7 +12641,8 @@ var runMetricsContract = c2.router({
|
|
|
12639
12641
|
}),
|
|
12640
12642
|
query: external_exports.object({
|
|
12641
12643
|
since: external_exports.coerce.number().optional(),
|
|
12642
|
-
limit: external_exports.coerce.number().min(1).max(100).default(5)
|
|
12644
|
+
limit: external_exports.coerce.number().min(1).max(100).default(5),
|
|
12645
|
+
order: external_exports.enum(["asc", "desc"]).default("desc")
|
|
12643
12646
|
}),
|
|
12644
12647
|
responses: {
|
|
12645
12648
|
200: metricsResponseSchema,
|
|
@@ -12662,7 +12665,8 @@ var runAgentEventsContract = c2.router({
|
|
|
12662
12665
|
}),
|
|
12663
12666
|
query: external_exports.object({
|
|
12664
12667
|
since: external_exports.coerce.number().optional(),
|
|
12665
|
-
limit: external_exports.coerce.number().min(1).max(100).default(5)
|
|
12668
|
+
limit: external_exports.coerce.number().min(1).max(100).default(5),
|
|
12669
|
+
order: external_exports.enum(["asc", "desc"]).default("desc")
|
|
12666
12670
|
}),
|
|
12667
12671
|
responses: {
|
|
12668
12672
|
200: agentEventsResponseSchema,
|
|
@@ -12685,7 +12689,8 @@ var runNetworkLogsContract = c2.router({
|
|
|
12685
12689
|
}),
|
|
12686
12690
|
query: external_exports.object({
|
|
12687
12691
|
since: external_exports.coerce.number().optional(),
|
|
12688
|
-
limit: external_exports.coerce.number().min(1).max(100).default(5)
|
|
12692
|
+
limit: external_exports.coerce.number().min(1).max(100).default(5),
|
|
12693
|
+
order: external_exports.enum(["asc", "desc"]).default("desc")
|
|
12689
12694
|
}),
|
|
12690
12695
|
responses: {
|
|
12691
12696
|
200: networkLogsResponseSchema,
|
|
@@ -13749,6 +13754,9 @@ var ApiClient = class {
|
|
|
13749
13754
|
if (options?.limit !== void 0) {
|
|
13750
13755
|
params.set("limit", String(options.limit));
|
|
13751
13756
|
}
|
|
13757
|
+
if (options?.order !== void 0) {
|
|
13758
|
+
params.set("order", options.order);
|
|
13759
|
+
}
|
|
13752
13760
|
const queryString = params.toString();
|
|
13753
13761
|
const url2 = `${baseUrl}/api/agent/runs/${runId}/telemetry/system-log${queryString ? `?${queryString}` : ""}`;
|
|
13754
13762
|
const response = await fetch(url2, {
|
|
@@ -13771,6 +13779,9 @@ var ApiClient = class {
|
|
|
13771
13779
|
if (options?.limit !== void 0) {
|
|
13772
13780
|
params.set("limit", String(options.limit));
|
|
13773
13781
|
}
|
|
13782
|
+
if (options?.order !== void 0) {
|
|
13783
|
+
params.set("order", options.order);
|
|
13784
|
+
}
|
|
13774
13785
|
const queryString = params.toString();
|
|
13775
13786
|
const url2 = `${baseUrl}/api/agent/runs/${runId}/telemetry/metrics${queryString ? `?${queryString}` : ""}`;
|
|
13776
13787
|
const response = await fetch(url2, {
|
|
@@ -13793,6 +13804,9 @@ var ApiClient = class {
|
|
|
13793
13804
|
if (options?.limit !== void 0) {
|
|
13794
13805
|
params.set("limit", String(options.limit));
|
|
13795
13806
|
}
|
|
13807
|
+
if (options?.order !== void 0) {
|
|
13808
|
+
params.set("order", options.order);
|
|
13809
|
+
}
|
|
13796
13810
|
const queryString = params.toString();
|
|
13797
13811
|
const url2 = `${baseUrl}/api/agent/runs/${runId}/telemetry/agent${queryString ? `?${queryString}` : ""}`;
|
|
13798
13812
|
const response = await fetch(url2, {
|
|
@@ -13815,6 +13829,9 @@ var ApiClient = class {
|
|
|
13815
13829
|
if (options?.limit !== void 0) {
|
|
13816
13830
|
params.set("limit", String(options.limit));
|
|
13817
13831
|
}
|
|
13832
|
+
if (options?.order !== void 0) {
|
|
13833
|
+
params.set("order", options.order);
|
|
13834
|
+
}
|
|
13818
13835
|
const queryString = params.toString();
|
|
13819
13836
|
const url2 = `${baseUrl}/api/agent/runs/${runId}/telemetry/network${queryString ? `?${queryString}` : ""}`;
|
|
13820
13837
|
const response = await fetch(url2, {
|
|
@@ -14234,6 +14251,7 @@ import * as path from "path";
|
|
|
14234
14251
|
import * as os from "os";
|
|
14235
14252
|
import { exec } from "child_process";
|
|
14236
14253
|
import { promisify } from "util";
|
|
14254
|
+
import { parse as parseYaml } from "yaml";
|
|
14237
14255
|
var execAsync = promisify(exec);
|
|
14238
14256
|
function parseGitHubTreeUrl2(url2) {
|
|
14239
14257
|
const parsed = parseGitHubTreeUrl(url2);
|
|
@@ -14279,6 +14297,37 @@ async function validateSkillDirectory(skillDir) {
|
|
|
14279
14297
|
);
|
|
14280
14298
|
}
|
|
14281
14299
|
}
|
|
14300
|
+
function parseSkillFrontmatter(content) {
|
|
14301
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
14302
|
+
if (!frontmatterMatch) {
|
|
14303
|
+
return {};
|
|
14304
|
+
}
|
|
14305
|
+
const yamlContent = frontmatterMatch[1];
|
|
14306
|
+
if (!yamlContent) {
|
|
14307
|
+
return {};
|
|
14308
|
+
}
|
|
14309
|
+
let parsed;
|
|
14310
|
+
try {
|
|
14311
|
+
parsed = parseYaml(yamlContent);
|
|
14312
|
+
} catch {
|
|
14313
|
+
return {};
|
|
14314
|
+
}
|
|
14315
|
+
if (!parsed || typeof parsed !== "object") {
|
|
14316
|
+
return {};
|
|
14317
|
+
}
|
|
14318
|
+
const data = parsed;
|
|
14319
|
+
return {
|
|
14320
|
+
name: typeof data.name === "string" ? data.name : void 0,
|
|
14321
|
+
description: typeof data.description === "string" ? data.description : void 0,
|
|
14322
|
+
vm0_secrets: Array.isArray(data.vm0_secrets) ? data.vm0_secrets.filter((s) => typeof s === "string") : void 0,
|
|
14323
|
+
vm0_vars: Array.isArray(data.vm0_vars) ? data.vm0_vars.filter((s) => typeof s === "string") : void 0
|
|
14324
|
+
};
|
|
14325
|
+
}
|
|
14326
|
+
async function readSkillFrontmatter(skillDir) {
|
|
14327
|
+
const skillMdPath = path.join(skillDir, "SKILL.md");
|
|
14328
|
+
const content = await fs.readFile(skillMdPath, "utf8");
|
|
14329
|
+
return parseSkillFrontmatter(content);
|
|
14330
|
+
}
|
|
14282
14331
|
|
|
14283
14332
|
// src/lib/direct-upload.ts
|
|
14284
14333
|
import { createHash } from "crypto";
|
|
@@ -14615,11 +14664,14 @@ async function uploadSkill(skillUrl) {
|
|
|
14615
14664
|
try {
|
|
14616
14665
|
const skillDir = await downloadGitHubSkill(parsed, tmpDir);
|
|
14617
14666
|
await validateSkillDirectory(skillDir);
|
|
14667
|
+
const frontmatter = await readSkillFrontmatter(skillDir);
|
|
14618
14668
|
const result = await directUpload(storageName, "volume", skillDir);
|
|
14619
14669
|
return {
|
|
14620
14670
|
name: storageName,
|
|
14621
14671
|
versionId: result.versionId,
|
|
14622
|
-
action: result.deduplicated ? "deduplicated" : "created"
|
|
14672
|
+
action: result.deduplicated ? "deduplicated" : "created",
|
|
14673
|
+
skillName: parsed.skillName,
|
|
14674
|
+
frontmatter
|
|
14623
14675
|
};
|
|
14624
14676
|
} finally {
|
|
14625
14677
|
await fs4.rm(tmpDir, { recursive: true, force: true });
|
|
@@ -14654,16 +14706,16 @@ function transformExperimentalShorthand(agent) {
|
|
|
14654
14706
|
agent.environment = environment;
|
|
14655
14707
|
}
|
|
14656
14708
|
}
|
|
14657
|
-
var composeCommand = new Command().name("compose").description("Create or update agent compose").argument("<config-file>", "Path to config YAML file").action(async (configFile) => {
|
|
14709
|
+
var composeCommand = new Command().name("compose").description("Create or update agent compose").argument("<config-file>", "Path to config YAML file").option("-y, --yes", "Skip confirmation prompts for skill requirements").action(async (configFile, options) => {
|
|
14658
14710
|
try {
|
|
14659
14711
|
if (!existsSync3(configFile)) {
|
|
14660
14712
|
console.error(chalk2.red(`\u2717 Config file not found: ${configFile}`));
|
|
14661
14713
|
process.exit(1);
|
|
14662
14714
|
}
|
|
14663
|
-
const content = await
|
|
14715
|
+
const content = await readFile4(configFile, "utf8");
|
|
14664
14716
|
let config2;
|
|
14665
14717
|
try {
|
|
14666
|
-
config2 =
|
|
14718
|
+
config2 = parseYaml2(content);
|
|
14667
14719
|
} catch (error43) {
|
|
14668
14720
|
console.error(chalk2.red("\u2717 Invalid YAML format"));
|
|
14669
14721
|
if (error43 instanceof Error) {
|
|
@@ -14740,6 +14792,7 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
14740
14792
|
process.exit(1);
|
|
14741
14793
|
}
|
|
14742
14794
|
}
|
|
14795
|
+
const skillResults = [];
|
|
14743
14796
|
if (agent.skills && Array.isArray(agent.skills)) {
|
|
14744
14797
|
const skillUrls = agent.skills;
|
|
14745
14798
|
console.log(`Uploading ${skillUrls.length} skill(s)...`);
|
|
@@ -14747,9 +14800,10 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
14747
14800
|
try {
|
|
14748
14801
|
console.log(chalk2.dim(` Downloading: ${skillUrl}`));
|
|
14749
14802
|
const result = await uploadSkill(skillUrl);
|
|
14803
|
+
skillResults.push(result);
|
|
14750
14804
|
console.log(
|
|
14751
14805
|
chalk2.green(
|
|
14752
|
-
` \u2713 Skill ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.versionId.slice(0, 8)}`
|
|
14806
|
+
` \u2713 Skill ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.skillName} (${result.versionId.slice(0, 8)})`
|
|
14753
14807
|
)
|
|
14754
14808
|
);
|
|
14755
14809
|
} catch (error43) {
|
|
@@ -14761,6 +14815,83 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
14761
14815
|
}
|
|
14762
14816
|
}
|
|
14763
14817
|
}
|
|
14818
|
+
const skillSecrets = /* @__PURE__ */ new Map();
|
|
14819
|
+
const skillVars = /* @__PURE__ */ new Map();
|
|
14820
|
+
for (const result of skillResults) {
|
|
14821
|
+
const { frontmatter, skillName } = result;
|
|
14822
|
+
if (frontmatter.vm0_secrets) {
|
|
14823
|
+
for (const secret of frontmatter.vm0_secrets) {
|
|
14824
|
+
if (!skillSecrets.has(secret)) {
|
|
14825
|
+
skillSecrets.set(secret, []);
|
|
14826
|
+
}
|
|
14827
|
+
skillSecrets.get(secret).push(skillName);
|
|
14828
|
+
}
|
|
14829
|
+
}
|
|
14830
|
+
if (frontmatter.vm0_vars) {
|
|
14831
|
+
for (const varName of frontmatter.vm0_vars) {
|
|
14832
|
+
if (!skillVars.has(varName)) {
|
|
14833
|
+
skillVars.set(varName, []);
|
|
14834
|
+
}
|
|
14835
|
+
skillVars.get(varName).push(skillName);
|
|
14836
|
+
}
|
|
14837
|
+
}
|
|
14838
|
+
}
|
|
14839
|
+
const environment = agent.environment || {};
|
|
14840
|
+
const newSecrets = [...skillSecrets.entries()].filter(
|
|
14841
|
+
([name]) => !(name in environment)
|
|
14842
|
+
);
|
|
14843
|
+
const newVars = [...skillVars.entries()].filter(
|
|
14844
|
+
([name]) => !(name in environment)
|
|
14845
|
+
);
|
|
14846
|
+
if (newSecrets.length > 0 || newVars.length > 0) {
|
|
14847
|
+
console.log();
|
|
14848
|
+
console.log(
|
|
14849
|
+
chalk2.bold("Skills require the following environment variables:")
|
|
14850
|
+
);
|
|
14851
|
+
console.log();
|
|
14852
|
+
if (newSecrets.length > 0) {
|
|
14853
|
+
console.log(chalk2.cyan(" Secrets:"));
|
|
14854
|
+
for (const [name, skills] of newSecrets) {
|
|
14855
|
+
console.log(` ${name.padEnd(24)} <- ${skills.join(", ")}`);
|
|
14856
|
+
}
|
|
14857
|
+
}
|
|
14858
|
+
if (newVars.length > 0) {
|
|
14859
|
+
console.log(chalk2.cyan(" Vars:"));
|
|
14860
|
+
for (const [name, skills] of newVars) {
|
|
14861
|
+
console.log(` ${name.padEnd(24)} <- ${skills.join(", ")}`);
|
|
14862
|
+
}
|
|
14863
|
+
}
|
|
14864
|
+
console.log();
|
|
14865
|
+
if (!options.yes) {
|
|
14866
|
+
if (!process.stdin.isTTY) {
|
|
14867
|
+
console.error(
|
|
14868
|
+
chalk2.red(
|
|
14869
|
+
"\u2717 Non-interactive terminal. Use --yes flag to skip confirmation."
|
|
14870
|
+
)
|
|
14871
|
+
);
|
|
14872
|
+
process.exit(1);
|
|
14873
|
+
}
|
|
14874
|
+
const response2 = await prompts({
|
|
14875
|
+
type: "confirm",
|
|
14876
|
+
name: "value",
|
|
14877
|
+
message: "Proceed with compose?",
|
|
14878
|
+
initial: true
|
|
14879
|
+
});
|
|
14880
|
+
if (!response2.value) {
|
|
14881
|
+
console.log(chalk2.yellow("Compose cancelled."));
|
|
14882
|
+
process.exit(0);
|
|
14883
|
+
}
|
|
14884
|
+
}
|
|
14885
|
+
for (const [name] of newSecrets) {
|
|
14886
|
+
environment[name] = `\${{ secrets.${name} }}`;
|
|
14887
|
+
}
|
|
14888
|
+
for (const [name] of newVars) {
|
|
14889
|
+
environment[name] = `\${{ vars.${name} }}`;
|
|
14890
|
+
}
|
|
14891
|
+
if (Object.keys(environment).length > 0) {
|
|
14892
|
+
agent.environment = environment;
|
|
14893
|
+
}
|
|
14894
|
+
}
|
|
14764
14895
|
console.log("Uploading compose...");
|
|
14765
14896
|
const response = await apiClient.createOrUpdateCompose({
|
|
14766
14897
|
content: config2
|
|
@@ -15799,6 +15930,16 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
15799
15930
|
}
|
|
15800
15931
|
);
|
|
15801
15932
|
runCmd.command("resume").description("Resume an agent run from a checkpoint (uses all snapshot data)").argument("<checkpointId>", "Checkpoint ID to resume from").argument("<prompt>", "Prompt for the resumed agent").option(
|
|
15933
|
+
"--vars <KEY=value>",
|
|
15934
|
+
"Variables for ${{ vars.xxx }} (repeatable, falls back to env vars and .env)",
|
|
15935
|
+
collectKeyValue,
|
|
15936
|
+
{}
|
|
15937
|
+
).option(
|
|
15938
|
+
"--secrets <KEY=value>",
|
|
15939
|
+
"Secrets for ${{ secrets.xxx }} (repeatable, required for resume)",
|
|
15940
|
+
collectKeyValue,
|
|
15941
|
+
{}
|
|
15942
|
+
).option(
|
|
15802
15943
|
"--volume-version <name=version>",
|
|
15803
15944
|
"Volume version override (repeatable)",
|
|
15804
15945
|
collectVolumeVersions,
|
|
@@ -15808,6 +15949,8 @@ runCmd.command("resume").description("Resume an agent run from a checkpoint (use
|
|
|
15808
15949
|
const startTimestamp = /* @__PURE__ */ new Date();
|
|
15809
15950
|
const allOpts = command.optsWithGlobals();
|
|
15810
15951
|
const verbose = options.verbose || allOpts.verbose;
|
|
15952
|
+
const vars = { ...allOpts.vars, ...options.vars };
|
|
15953
|
+
const secrets = { ...allOpts.secrets, ...options.secrets };
|
|
15811
15954
|
try {
|
|
15812
15955
|
if (!isUUID(checkpointId)) {
|
|
15813
15956
|
console.error(
|
|
@@ -15816,10 +15959,20 @@ runCmd.command("resume").description("Resume an agent run from a checkpoint (use
|
|
|
15816
15959
|
console.error(chalk5.dim(" Checkpoint ID must be a valid UUID"));
|
|
15817
15960
|
process.exit(1);
|
|
15818
15961
|
}
|
|
15962
|
+
const secretNames = Object.keys(secrets);
|
|
15963
|
+
const loadedSecrets = secretNames.length > 0 ? secrets : loadValues({}, []);
|
|
15819
15964
|
if (verbose) {
|
|
15820
15965
|
logVerbosePreFlight("Resuming agent run from checkpoint", [
|
|
15821
15966
|
{ label: "Checkpoint ID", value: checkpointId },
|
|
15822
15967
|
{ label: "Prompt", value: prompt },
|
|
15968
|
+
{
|
|
15969
|
+
label: "Variables",
|
|
15970
|
+
value: Object.keys(vars).length > 0 ? JSON.stringify(vars) : void 0
|
|
15971
|
+
},
|
|
15972
|
+
{
|
|
15973
|
+
label: "Secrets",
|
|
15974
|
+
value: loadedSecrets && Object.keys(loadedSecrets).length > 0 ? `${Object.keys(loadedSecrets).length} loaded` : void 0
|
|
15975
|
+
},
|
|
15823
15976
|
{
|
|
15824
15977
|
label: "Volume overrides",
|
|
15825
15978
|
value: Object.keys(allOpts.volumeVersion).length > 0 ? JSON.stringify(allOpts.volumeVersion) : void 0
|
|
@@ -15829,6 +15982,8 @@ runCmd.command("resume").description("Resume an agent run from a checkpoint (use
|
|
|
15829
15982
|
const response = await apiClient.createRun({
|
|
15830
15983
|
checkpointId,
|
|
15831
15984
|
prompt,
|
|
15985
|
+
vars: Object.keys(vars).length > 0 ? vars : void 0,
|
|
15986
|
+
secrets: loadedSecrets,
|
|
15832
15987
|
volumeVersions: Object.keys(allOpts.volumeVersion).length > 0 ? allOpts.volumeVersion : void 0
|
|
15833
15988
|
});
|
|
15834
15989
|
if (response.status === "failed") {
|
|
@@ -15872,6 +16027,16 @@ runCmd.command("resume").description("Resume an agent run from a checkpoint (use
|
|
|
15872
16027
|
runCmd.command("continue").description(
|
|
15873
16028
|
"Continue an agent run from a session (uses latest artifact version)"
|
|
15874
16029
|
).argument("<agentSessionId>", "Agent session ID to continue from").argument("<prompt>", "Prompt for the continued agent").option(
|
|
16030
|
+
"--vars <KEY=value>",
|
|
16031
|
+
"Variables for ${{ vars.xxx }} (repeatable, falls back to env vars and .env)",
|
|
16032
|
+
collectKeyValue,
|
|
16033
|
+
{}
|
|
16034
|
+
).option(
|
|
16035
|
+
"--secrets <KEY=value>",
|
|
16036
|
+
"Secrets for ${{ secrets.xxx }} (repeatable, required for continue)",
|
|
16037
|
+
collectKeyValue,
|
|
16038
|
+
{}
|
|
16039
|
+
).option(
|
|
15875
16040
|
"--volume-version <name=version>",
|
|
15876
16041
|
"Volume version override (repeatable)",
|
|
15877
16042
|
collectVolumeVersions,
|
|
@@ -15881,6 +16046,8 @@ runCmd.command("continue").description(
|
|
|
15881
16046
|
const startTimestamp = /* @__PURE__ */ new Date();
|
|
15882
16047
|
const allOpts = command.optsWithGlobals();
|
|
15883
16048
|
const verbose = options.verbose || allOpts.verbose;
|
|
16049
|
+
const vars = { ...allOpts.vars, ...options.vars };
|
|
16050
|
+
const secrets = { ...allOpts.secrets, ...options.secrets };
|
|
15884
16051
|
try {
|
|
15885
16052
|
if (!isUUID(agentSessionId)) {
|
|
15886
16053
|
console.error(
|
|
@@ -15889,11 +16056,21 @@ runCmd.command("continue").description(
|
|
|
15889
16056
|
console.error(chalk5.dim(" Agent session ID must be a valid UUID"));
|
|
15890
16057
|
process.exit(1);
|
|
15891
16058
|
}
|
|
16059
|
+
const secretNames = Object.keys(secrets);
|
|
16060
|
+
const loadedSecrets = secretNames.length > 0 ? secrets : loadValues({}, []);
|
|
15892
16061
|
if (verbose) {
|
|
15893
16062
|
logVerbosePreFlight("Continuing agent run from session", [
|
|
15894
16063
|
{ label: "Session ID", value: agentSessionId },
|
|
15895
16064
|
{ label: "Prompt", value: prompt },
|
|
15896
16065
|
{ label: "Note", value: "Using latest artifact version" },
|
|
16066
|
+
{
|
|
16067
|
+
label: "Variables",
|
|
16068
|
+
value: Object.keys(vars).length > 0 ? JSON.stringify(vars) : void 0
|
|
16069
|
+
},
|
|
16070
|
+
{
|
|
16071
|
+
label: "Secrets",
|
|
16072
|
+
value: loadedSecrets && Object.keys(loadedSecrets).length > 0 ? `${Object.keys(loadedSecrets).length} loaded` : void 0
|
|
16073
|
+
},
|
|
15897
16074
|
{
|
|
15898
16075
|
label: "Volume overrides",
|
|
15899
16076
|
value: Object.keys(allOpts.volumeVersion).length > 0 ? JSON.stringify(allOpts.volumeVersion) : void 0
|
|
@@ -15903,6 +16080,8 @@ runCmd.command("continue").description(
|
|
|
15903
16080
|
const response = await apiClient.createRun({
|
|
15904
16081
|
sessionId: agentSessionId,
|
|
15905
16082
|
prompt,
|
|
16083
|
+
vars: Object.keys(vars).length > 0 ? vars : void 0,
|
|
16084
|
+
secrets: loadedSecrets,
|
|
15906
16085
|
volumeVersions: Object.keys(allOpts.volumeVersion).length > 0 ? allOpts.volumeVersion : void 0
|
|
15907
16086
|
});
|
|
15908
16087
|
if (response.status === "failed") {
|
|
@@ -15956,9 +16135,9 @@ import chalk6 from "chalk";
|
|
|
15956
16135
|
import path7 from "path";
|
|
15957
16136
|
|
|
15958
16137
|
// src/lib/storage-utils.ts
|
|
15959
|
-
import { readFile as
|
|
16138
|
+
import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
15960
16139
|
import { existsSync as existsSync5 } from "fs";
|
|
15961
|
-
import { parse as
|
|
16140
|
+
import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
|
|
15962
16141
|
import path6 from "path";
|
|
15963
16142
|
var CONFIG_DIR2 = ".vm0";
|
|
15964
16143
|
var CONFIG_FILE2 = "storage.yaml";
|
|
@@ -15981,8 +16160,8 @@ async function readStorageConfig(basePath = process.cwd()) {
|
|
|
15981
16160
|
if (!actualPath) {
|
|
15982
16161
|
return null;
|
|
15983
16162
|
}
|
|
15984
|
-
const content = await
|
|
15985
|
-
const config2 =
|
|
16163
|
+
const content = await readFile5(actualPath, "utf8");
|
|
16164
|
+
const config2 = parseYaml3(content);
|
|
15986
16165
|
if (!config2.type) {
|
|
15987
16166
|
config2.type = "volume";
|
|
15988
16167
|
}
|
|
@@ -16570,11 +16749,11 @@ var artifactCommand = new Command12().name("artifact").description("Manage cloud
|
|
|
16570
16749
|
// src/commands/cook.ts
|
|
16571
16750
|
import { Command as Command13 } from "commander";
|
|
16572
16751
|
import chalk16 from "chalk";
|
|
16573
|
-
import { readFile as
|
|
16752
|
+
import { readFile as readFile7, mkdir as mkdir6, writeFile as writeFile6, appendFile } from "fs/promises";
|
|
16574
16753
|
import { existsSync as existsSync7, readFileSync } from "fs";
|
|
16575
16754
|
import path11 from "path";
|
|
16576
16755
|
import { spawn as spawn2 } from "child_process";
|
|
16577
|
-
import { parse as
|
|
16756
|
+
import { parse as parseYaml4 } from "yaml";
|
|
16578
16757
|
import { config as dotenvConfig2 } from "dotenv";
|
|
16579
16758
|
|
|
16580
16759
|
// src/lib/update-checker.ts
|
|
@@ -16688,7 +16867,7 @@ async function checkAndUpgrade(currentVersion, prompt) {
|
|
|
16688
16867
|
// src/lib/cook-state.ts
|
|
16689
16868
|
import { homedir as homedir2 } from "os";
|
|
16690
16869
|
import { join as join6 } from "path";
|
|
16691
|
-
import { readFile as
|
|
16870
|
+
import { readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
|
|
16692
16871
|
import { existsSync as existsSync6 } from "fs";
|
|
16693
16872
|
var CONFIG_DIR3 = join6(homedir2(), ".vm0");
|
|
16694
16873
|
var COOK_STATE_FILE = join6(CONFIG_DIR3, "cook.json");
|
|
@@ -16698,7 +16877,7 @@ async function loadCookStateFile() {
|
|
|
16698
16877
|
return { ppid: {} };
|
|
16699
16878
|
}
|
|
16700
16879
|
try {
|
|
16701
|
-
const content = await
|
|
16880
|
+
const content = await readFile6(COOK_STATE_FILE, "utf8");
|
|
16702
16881
|
const data = JSON.parse(content);
|
|
16703
16882
|
if (!data.ppid) {
|
|
16704
16883
|
const oldState = data;
|
|
@@ -16909,7 +17088,7 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
16909
17088
|
}
|
|
16910
17089
|
var cookCmd = new Command13().name("cook").description("One-click agent preparation and execution from vm0.yaml");
|
|
16911
17090
|
cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
16912
|
-
const shouldExit = await checkAndUpgrade("4.
|
|
17091
|
+
const shouldExit = await checkAndUpgrade("4.31.0", prompt);
|
|
16913
17092
|
if (shouldExit) {
|
|
16914
17093
|
process.exit(0);
|
|
16915
17094
|
}
|
|
@@ -16921,8 +17100,8 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
16921
17100
|
}
|
|
16922
17101
|
let config2;
|
|
16923
17102
|
try {
|
|
16924
|
-
const content = await
|
|
16925
|
-
config2 =
|
|
17103
|
+
const content = await readFile7(CONFIG_FILE3, "utf8");
|
|
17104
|
+
config2 = parseYaml4(content);
|
|
16926
17105
|
} catch (error43) {
|
|
16927
17106
|
console.error(chalk16.red("\u2717 Invalid YAML format"));
|
|
16928
17107
|
if (error43 instanceof Error) {
|
|
@@ -17082,7 +17261,7 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
17082
17261
|
cookCmd.command("logs").description("View logs from the last cook run").option("-a, --agent", "Show agent events (default)").option("-s, --system", "Show system log").option("-m, --metrics", "Show metrics").option("-n, --network", "Show network logs (proxy traffic)").option(
|
|
17083
17262
|
"--since <time>",
|
|
17084
17263
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z)"
|
|
17085
|
-
).option("--
|
|
17264
|
+
).option("--tail <n>", "Show last N entries (default: 5, max: 100)").option("--head <n>", "Show first N entries (max: 100)").action(
|
|
17086
17265
|
async (options) => {
|
|
17087
17266
|
const state = await loadCookState();
|
|
17088
17267
|
if (!state.lastRunId) {
|
|
@@ -17112,9 +17291,13 @@ cookCmd.command("logs").description("View logs from the last cook run").option("
|
|
|
17112
17291
|
args.push("--since", options.since);
|
|
17113
17292
|
displayArgs.push(`--since ${options.since}`);
|
|
17114
17293
|
}
|
|
17115
|
-
if (options.
|
|
17116
|
-
args.push("--
|
|
17117
|
-
displayArgs.push(`--
|
|
17294
|
+
if (options.tail) {
|
|
17295
|
+
args.push("--tail", options.tail);
|
|
17296
|
+
displayArgs.push(`--tail ${options.tail}`);
|
|
17297
|
+
}
|
|
17298
|
+
if (options.head) {
|
|
17299
|
+
args.push("--head", options.head);
|
|
17300
|
+
displayArgs.push(`--head ${options.head}`);
|
|
17118
17301
|
}
|
|
17119
17302
|
printCommand(displayArgs.join(" "));
|
|
17120
17303
|
await execVm0Command(args);
|
|
@@ -17192,7 +17375,7 @@ import { Command as Command18 } from "commander";
|
|
|
17192
17375
|
// src/commands/image/build.ts
|
|
17193
17376
|
import { Command as Command14 } from "commander";
|
|
17194
17377
|
import chalk17 from "chalk";
|
|
17195
|
-
import { readFile as
|
|
17378
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
17196
17379
|
import { existsSync as existsSync8 } from "fs";
|
|
17197
17380
|
|
|
17198
17381
|
// src/lib/dockerfile-validator.ts
|
|
@@ -17253,7 +17436,7 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17253
17436
|
}
|
|
17254
17437
|
try {
|
|
17255
17438
|
const scope = await apiClient.getScope();
|
|
17256
|
-
const dockerfile = await
|
|
17439
|
+
const dockerfile = await readFile8(file2, "utf8");
|
|
17257
17440
|
const validation = validateDockerfile(dockerfile);
|
|
17258
17441
|
if (!validation.valid) {
|
|
17259
17442
|
console.error(chalk17.red("\u2717 Dockerfile validation failed\n"));
|
|
@@ -17704,34 +17887,38 @@ function getLogType(options) {
|
|
|
17704
17887
|
var logsCommand = new Command19().name("logs").description("View logs for an agent run").argument("<runId>", "Run ID to fetch logs for").option("-a, --agent", "Show agent events (default)").option("-s, --system", "Show system log").option("-m, --metrics", "Show metrics").option("-n, --network", "Show network logs (proxy traffic)").option(
|
|
17705
17888
|
"--since <time>",
|
|
17706
17889
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z, 1705312200)"
|
|
17707
|
-
).option(
|
|
17708
|
-
"--limit <n>",
|
|
17709
|
-
"Maximum number of entries to show (default: 5, max: 100)",
|
|
17710
|
-
"5"
|
|
17711
|
-
).action(
|
|
17890
|
+
).option("--tail <n>", "Show last N entries (default: 5, max: 100)").option("--head <n>", "Show first N entries (max: 100)").action(
|
|
17712
17891
|
async (runId, options) => {
|
|
17713
17892
|
try {
|
|
17714
17893
|
const logType = getLogType(options);
|
|
17894
|
+
if (options.tail !== void 0 && options.head !== void 0) {
|
|
17895
|
+
console.error(
|
|
17896
|
+
chalk21.red("Options --tail and --head are mutually exclusive")
|
|
17897
|
+
);
|
|
17898
|
+
process.exit(1);
|
|
17899
|
+
}
|
|
17715
17900
|
let since;
|
|
17716
17901
|
if (options.since) {
|
|
17717
17902
|
since = parseTime(options.since);
|
|
17718
17903
|
}
|
|
17904
|
+
const isHead = options.head !== void 0;
|
|
17719
17905
|
const limit = Math.min(
|
|
17720
|
-
Math.max(1, parseInt(options.
|
|
17906
|
+
Math.max(1, parseInt(options.head || options.tail || "5", 10)),
|
|
17721
17907
|
100
|
|
17722
17908
|
);
|
|
17909
|
+
const order = isHead ? "asc" : "desc";
|
|
17723
17910
|
switch (logType) {
|
|
17724
17911
|
case "agent":
|
|
17725
|
-
await showAgentEvents(runId, { since, limit });
|
|
17912
|
+
await showAgentEvents(runId, { since, limit, order });
|
|
17726
17913
|
break;
|
|
17727
17914
|
case "system":
|
|
17728
|
-
await showSystemLog(runId, { since, limit });
|
|
17915
|
+
await showSystemLog(runId, { since, limit, order });
|
|
17729
17916
|
break;
|
|
17730
17917
|
case "metrics":
|
|
17731
|
-
await showMetrics(runId, { since, limit });
|
|
17918
|
+
await showMetrics(runId, { since, limit, order });
|
|
17732
17919
|
break;
|
|
17733
17920
|
case "network":
|
|
17734
|
-
await showNetworkLogs(runId, { since, limit });
|
|
17921
|
+
await showNetworkLogs(runId, { since, limit, order });
|
|
17735
17922
|
break;
|
|
17736
17923
|
}
|
|
17737
17924
|
} catch (error43) {
|
|
@@ -17746,14 +17933,15 @@ async function showAgentEvents(runId, options) {
|
|
|
17746
17933
|
console.log(chalk21.yellow("No agent events found for this run."));
|
|
17747
17934
|
return;
|
|
17748
17935
|
}
|
|
17749
|
-
|
|
17936
|
+
const events = options.order === "desc" ? [...response.events].reverse() : response.events;
|
|
17937
|
+
for (const event of events) {
|
|
17750
17938
|
renderAgentEvent(event, response.provider);
|
|
17751
17939
|
}
|
|
17752
17940
|
if (response.hasMore) {
|
|
17753
17941
|
console.log();
|
|
17754
17942
|
console.log(
|
|
17755
17943
|
chalk21.dim(
|
|
17756
|
-
`Showing ${response.events.length} events. Use --
|
|
17944
|
+
`Showing ${response.events.length} events. Use --tail to see more.`
|
|
17757
17945
|
)
|
|
17758
17946
|
);
|
|
17759
17947
|
}
|
|
@@ -17768,7 +17956,7 @@ async function showSystemLog(runId, options) {
|
|
|
17768
17956
|
if (response.hasMore) {
|
|
17769
17957
|
console.log();
|
|
17770
17958
|
console.log(
|
|
17771
|
-
chalk21.dim("More log entries available. Use --
|
|
17959
|
+
chalk21.dim("More log entries available. Use --tail to see more.")
|
|
17772
17960
|
);
|
|
17773
17961
|
}
|
|
17774
17962
|
}
|
|
@@ -17778,14 +17966,15 @@ async function showMetrics(runId, options) {
|
|
|
17778
17966
|
console.log(chalk21.yellow("No metrics found for this run."));
|
|
17779
17967
|
return;
|
|
17780
17968
|
}
|
|
17781
|
-
|
|
17969
|
+
const metrics = options.order === "desc" ? [...response.metrics].reverse() : response.metrics;
|
|
17970
|
+
for (const metric of metrics) {
|
|
17782
17971
|
console.log(formatMetric(metric));
|
|
17783
17972
|
}
|
|
17784
17973
|
if (response.hasMore) {
|
|
17785
17974
|
console.log();
|
|
17786
17975
|
console.log(
|
|
17787
17976
|
chalk21.dim(
|
|
17788
|
-
`Showing ${response.metrics.length} metrics. Use --
|
|
17977
|
+
`Showing ${response.metrics.length} metrics. Use --tail to see more.`
|
|
17789
17978
|
)
|
|
17790
17979
|
);
|
|
17791
17980
|
}
|
|
@@ -17800,14 +17989,15 @@ async function showNetworkLogs(runId, options) {
|
|
|
17800
17989
|
);
|
|
17801
17990
|
return;
|
|
17802
17991
|
}
|
|
17803
|
-
|
|
17992
|
+
const networkLogs = options.order === "desc" ? [...response.networkLogs].reverse() : response.networkLogs;
|
|
17993
|
+
for (const entry of networkLogs) {
|
|
17804
17994
|
console.log(formatNetworkLog(entry));
|
|
17805
17995
|
}
|
|
17806
17996
|
if (response.hasMore) {
|
|
17807
17997
|
console.log();
|
|
17808
17998
|
console.log(
|
|
17809
17999
|
chalk21.dim(
|
|
17810
|
-
`Showing ${response.networkLogs.length} network logs. Use --
|
|
18000
|
+
`Showing ${response.networkLogs.length} network logs. Use --tail to see more.`
|
|
17811
18001
|
)
|
|
17812
18002
|
);
|
|
17813
18003
|
}
|
|
@@ -18052,9 +18242,9 @@ import { Command as Command24 } from "commander";
|
|
|
18052
18242
|
import chalk25 from "chalk";
|
|
18053
18243
|
import * as readline3 from "readline";
|
|
18054
18244
|
import { existsSync as existsSync10 } from "fs";
|
|
18055
|
-
import { mkdir as mkdir7, readFile as
|
|
18245
|
+
import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
|
|
18056
18246
|
import { execSync, spawnSync } from "child_process";
|
|
18057
|
-
import { parse as
|
|
18247
|
+
import { parse as parseYaml5 } from "yaml";
|
|
18058
18248
|
function isGhInstalled() {
|
|
18059
18249
|
try {
|
|
18060
18250
|
execSync("gh --version", { stdio: "ignore" });
|
|
@@ -18374,8 +18564,8 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18374
18564
|
}
|
|
18375
18565
|
console.log();
|
|
18376
18566
|
console.log("Analyzing vm0.yaml...");
|
|
18377
|
-
const content = await
|
|
18378
|
-
const config2 =
|
|
18567
|
+
const content = await readFile9("vm0.yaml", "utf8");
|
|
18568
|
+
const config2 = parseYaml5(content);
|
|
18379
18569
|
const agents = config2.agents;
|
|
18380
18570
|
const agentName = Object.keys(agents)[0];
|
|
18381
18571
|
console.log(chalk25.green(`\u2713 Agent: ${agentName}`));
|
|
@@ -18511,7 +18701,7 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18511
18701
|
|
|
18512
18702
|
// src/index.ts
|
|
18513
18703
|
var program = new Command25();
|
|
18514
|
-
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.
|
|
18704
|
+
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.31.0");
|
|
18515
18705
|
program.command("info").description("Display environment information").action(async () => {
|
|
18516
18706
|
console.log(chalk26.bold("System Information:"));
|
|
18517
18707
|
console.log(`Node Version: ${process.version}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vm0/cli",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.31.0",
|
|
4
4
|
"description": "CLI application",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"chalk": "^5.6.0",
|
|
20
20
|
"commander": "^14.0.0",
|
|
21
21
|
"dotenv": "^17.2.1",
|
|
22
|
+
"prompts": "^2.4.2",
|
|
22
23
|
"tar": "^7.5.2",
|
|
23
24
|
"yaml": "^2.3.4"
|
|
24
25
|
}
|