@vm0/cli 1.6.0 → 1.9.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 +362 -80
- package/package.json +6 -1
package/index.js
CHANGED
|
@@ -736,15 +736,15 @@ function mergeDefs(...defs) {
|
|
|
736
736
|
function cloneDef(schema) {
|
|
737
737
|
return mergeDefs(schema._zod.def);
|
|
738
738
|
}
|
|
739
|
-
function getElementAtPath(obj,
|
|
740
|
-
if (!
|
|
739
|
+
function getElementAtPath(obj, path9) {
|
|
740
|
+
if (!path9)
|
|
741
741
|
return obj;
|
|
742
|
-
return
|
|
742
|
+
return path9.reduce((acc, key) => acc?.[key], obj);
|
|
743
743
|
}
|
|
744
744
|
function promiseAllObject(promisesObj) {
|
|
745
745
|
const keys = Object.keys(promisesObj);
|
|
746
|
-
const
|
|
747
|
-
return Promise.all(
|
|
746
|
+
const promises6 = keys.map((key) => promisesObj[key]);
|
|
747
|
+
return Promise.all(promises6).then((results) => {
|
|
748
748
|
const resolvedObj = {};
|
|
749
749
|
for (let i = 0; i < keys.length; i++) {
|
|
750
750
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -1098,11 +1098,11 @@ function aborted(x, startIndex = 0) {
|
|
|
1098
1098
|
}
|
|
1099
1099
|
return false;
|
|
1100
1100
|
}
|
|
1101
|
-
function prefixIssues(
|
|
1101
|
+
function prefixIssues(path9, issues) {
|
|
1102
1102
|
return issues.map((iss) => {
|
|
1103
1103
|
var _a;
|
|
1104
1104
|
(_a = iss).path ?? (_a.path = []);
|
|
1105
|
-
iss.path.unshift(
|
|
1105
|
+
iss.path.unshift(path9);
|
|
1106
1106
|
return iss;
|
|
1107
1107
|
});
|
|
1108
1108
|
}
|
|
@@ -1270,7 +1270,7 @@ function treeifyError(error43, _mapper) {
|
|
|
1270
1270
|
return issue2.message;
|
|
1271
1271
|
};
|
|
1272
1272
|
const result = { errors: [] };
|
|
1273
|
-
const processError = (error44,
|
|
1273
|
+
const processError = (error44, path9 = []) => {
|
|
1274
1274
|
var _a, _b;
|
|
1275
1275
|
for (const issue2 of error44.issues) {
|
|
1276
1276
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -1280,7 +1280,7 @@ function treeifyError(error43, _mapper) {
|
|
|
1280
1280
|
} else if (issue2.code === "invalid_element") {
|
|
1281
1281
|
processError({ issues: issue2.issues }, issue2.path);
|
|
1282
1282
|
} else {
|
|
1283
|
-
const fullpath = [...
|
|
1283
|
+
const fullpath = [...path9, ...issue2.path];
|
|
1284
1284
|
if (fullpath.length === 0) {
|
|
1285
1285
|
result.errors.push(mapper(issue2));
|
|
1286
1286
|
continue;
|
|
@@ -1312,8 +1312,8 @@ function treeifyError(error43, _mapper) {
|
|
|
1312
1312
|
}
|
|
1313
1313
|
function toDotPath(_path) {
|
|
1314
1314
|
const segs = [];
|
|
1315
|
-
const
|
|
1316
|
-
for (const seg of
|
|
1315
|
+
const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1316
|
+
for (const seg of path9) {
|
|
1317
1317
|
if (typeof seg === "number")
|
|
1318
1318
|
segs.push(`[${seg}]`);
|
|
1319
1319
|
else if (typeof seg === "symbol")
|
|
@@ -12413,10 +12413,37 @@ var ApiClient = class {
|
|
|
12413
12413
|
}
|
|
12414
12414
|
return await response.json();
|
|
12415
12415
|
}
|
|
12416
|
+
async continueSession(body) {
|
|
12417
|
+
const baseUrl = await this.getBaseUrl();
|
|
12418
|
+
const headers = await this.getHeaders();
|
|
12419
|
+
const response = await fetch(`${baseUrl}/api/agent/runs/continue`, {
|
|
12420
|
+
method: "POST",
|
|
12421
|
+
headers,
|
|
12422
|
+
body: JSON.stringify(body)
|
|
12423
|
+
});
|
|
12424
|
+
if (!response.ok) {
|
|
12425
|
+
const error43 = await response.json();
|
|
12426
|
+
throw new Error(error43.error?.message || "Failed to continue session");
|
|
12427
|
+
}
|
|
12428
|
+
return await response.json();
|
|
12429
|
+
}
|
|
12430
|
+
async getAgentSession(id) {
|
|
12431
|
+
const baseUrl = await this.getBaseUrl();
|
|
12432
|
+
const headers = await this.getHeaders();
|
|
12433
|
+
const response = await fetch(`${baseUrl}/api/agent/sessions/${id}`, {
|
|
12434
|
+
method: "GET",
|
|
12435
|
+
headers
|
|
12436
|
+
});
|
|
12437
|
+
if (!response.ok) {
|
|
12438
|
+
const error43 = await response.json();
|
|
12439
|
+
throw new Error(error43.error?.message || "Failed to get agent session");
|
|
12440
|
+
}
|
|
12441
|
+
return await response.json();
|
|
12442
|
+
}
|
|
12416
12443
|
/**
|
|
12417
12444
|
* Generic GET request
|
|
12418
12445
|
*/
|
|
12419
|
-
async get(
|
|
12446
|
+
async get(path9) {
|
|
12420
12447
|
const baseUrl = await this.getBaseUrl();
|
|
12421
12448
|
const token = await getToken();
|
|
12422
12449
|
if (!token) {
|
|
@@ -12429,7 +12456,7 @@ var ApiClient = class {
|
|
|
12429
12456
|
if (bypassSecret) {
|
|
12430
12457
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
12431
12458
|
}
|
|
12432
|
-
return fetch(`${baseUrl}${
|
|
12459
|
+
return fetch(`${baseUrl}${path9}`, {
|
|
12433
12460
|
method: "GET",
|
|
12434
12461
|
headers
|
|
12435
12462
|
});
|
|
@@ -12437,7 +12464,7 @@ var ApiClient = class {
|
|
|
12437
12464
|
/**
|
|
12438
12465
|
* Generic POST request
|
|
12439
12466
|
*/
|
|
12440
|
-
async post(
|
|
12467
|
+
async post(path9, options) {
|
|
12441
12468
|
const baseUrl = await this.getBaseUrl();
|
|
12442
12469
|
const token = await getToken();
|
|
12443
12470
|
if (!token) {
|
|
@@ -12450,7 +12477,7 @@ var ApiClient = class {
|
|
|
12450
12477
|
if (bypassSecret) {
|
|
12451
12478
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
12452
12479
|
}
|
|
12453
|
-
return fetch(`${baseUrl}${
|
|
12480
|
+
return fetch(`${baseUrl}${path9}`, {
|
|
12454
12481
|
method: "POST",
|
|
12455
12482
|
headers,
|
|
12456
12483
|
body: options?.body
|
|
@@ -12464,6 +12491,19 @@ function validateAgentName(name) {
|
|
|
12464
12491
|
const nameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{1,62}[a-zA-Z0-9])?$/;
|
|
12465
12492
|
return nameRegex.test(name);
|
|
12466
12493
|
}
|
|
12494
|
+
function validateVolumeConfig(volumeKey, volumeConfig) {
|
|
12495
|
+
if (!volumeConfig || typeof volumeConfig !== "object") {
|
|
12496
|
+
return `Volume "${volumeKey}" must be an object`;
|
|
12497
|
+
}
|
|
12498
|
+
const vol = volumeConfig;
|
|
12499
|
+
if (!vol.name || typeof vol.name !== "string") {
|
|
12500
|
+
return `Volume "${volumeKey}" must have a 'name' field (string)`;
|
|
12501
|
+
}
|
|
12502
|
+
if (!vol.version || typeof vol.version !== "string") {
|
|
12503
|
+
return `Volume "${volumeKey}" must have a 'version' field (string)`;
|
|
12504
|
+
}
|
|
12505
|
+
return null;
|
|
12506
|
+
}
|
|
12467
12507
|
function validateAgentConfig(config2) {
|
|
12468
12508
|
if (!config2 || typeof config2 !== "object") {
|
|
12469
12509
|
return { valid: false, error: "Config must be an object" };
|
|
@@ -12472,22 +12512,83 @@ function validateAgentConfig(config2) {
|
|
|
12472
12512
|
if (!cfg.version) {
|
|
12473
12513
|
return { valid: false, error: "Missing config.version" };
|
|
12474
12514
|
}
|
|
12475
|
-
if (!cfg.
|
|
12476
|
-
return { valid: false, error: "Missing config.
|
|
12515
|
+
if (!cfg.agents || !Array.isArray(cfg.agents)) {
|
|
12516
|
+
return { valid: false, error: "Missing config.agents array" };
|
|
12517
|
+
}
|
|
12518
|
+
if (cfg.agents.length === 0) {
|
|
12519
|
+
return { valid: false, error: "config.agents array must not be empty" };
|
|
12520
|
+
}
|
|
12521
|
+
const agent = cfg.agents[0];
|
|
12522
|
+
if (!agent || typeof agent !== "object") {
|
|
12523
|
+
return { valid: false, error: "First agent must be an object" };
|
|
12477
12524
|
}
|
|
12478
|
-
const agent = cfg.agent;
|
|
12479
12525
|
if (!agent.name) {
|
|
12480
|
-
return { valid: false, error: "Missing
|
|
12526
|
+
return { valid: false, error: "Missing agents[0].name" };
|
|
12481
12527
|
}
|
|
12482
12528
|
if (typeof agent.name !== "string") {
|
|
12483
|
-
return { valid: false, error: "
|
|
12529
|
+
return { valid: false, error: "agents[0].name must be a string" };
|
|
12484
12530
|
}
|
|
12485
12531
|
if (!validateAgentName(agent.name)) {
|
|
12486
12532
|
return {
|
|
12487
12533
|
valid: false,
|
|
12488
|
-
error: "Invalid
|
|
12534
|
+
error: "Invalid agents[0].name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number."
|
|
12489
12535
|
};
|
|
12490
12536
|
}
|
|
12537
|
+
if (!agent.working_dir || typeof agent.working_dir !== "string") {
|
|
12538
|
+
return {
|
|
12539
|
+
valid: false,
|
|
12540
|
+
error: "Missing or invalid agents[0].working_dir (must be a string)"
|
|
12541
|
+
};
|
|
12542
|
+
}
|
|
12543
|
+
if (!agent.image || typeof agent.image !== "string") {
|
|
12544
|
+
return {
|
|
12545
|
+
valid: false,
|
|
12546
|
+
error: "Missing or invalid agents[0].image (must be a string)"
|
|
12547
|
+
};
|
|
12548
|
+
}
|
|
12549
|
+
if (!agent.provider || typeof agent.provider !== "string") {
|
|
12550
|
+
return {
|
|
12551
|
+
valid: false,
|
|
12552
|
+
error: "Missing or invalid agents[0].provider (must be a string)"
|
|
12553
|
+
};
|
|
12554
|
+
}
|
|
12555
|
+
const agentVolumes = agent.volumes;
|
|
12556
|
+
if (agentVolumes && Array.isArray(agentVolumes) && agentVolumes.length > 0) {
|
|
12557
|
+
const volumesSection = cfg.volumes;
|
|
12558
|
+
if (!volumesSection || typeof volumesSection !== "object") {
|
|
12559
|
+
return {
|
|
12560
|
+
valid: false,
|
|
12561
|
+
error: "Agent references volumes but no volumes section defined. Each volume must have explicit name and version."
|
|
12562
|
+
};
|
|
12563
|
+
}
|
|
12564
|
+
for (const volDeclaration of agentVolumes) {
|
|
12565
|
+
if (typeof volDeclaration !== "string") {
|
|
12566
|
+
return {
|
|
12567
|
+
valid: false,
|
|
12568
|
+
error: "Volume declaration must be a string in format 'key:/path'"
|
|
12569
|
+
};
|
|
12570
|
+
}
|
|
12571
|
+
const parts = volDeclaration.split(":");
|
|
12572
|
+
if (parts.length !== 2) {
|
|
12573
|
+
return {
|
|
12574
|
+
valid: false,
|
|
12575
|
+
error: `Invalid volume declaration: ${volDeclaration}. Expected format: volume-key:/mount/path`
|
|
12576
|
+
};
|
|
12577
|
+
}
|
|
12578
|
+
const volumeKey = parts[0].trim();
|
|
12579
|
+
const volumeConfig = volumesSection[volumeKey];
|
|
12580
|
+
if (!volumeConfig) {
|
|
12581
|
+
return {
|
|
12582
|
+
valid: false,
|
|
12583
|
+
error: `Volume "${volumeKey}" is not defined in volumes section. Each volume must have explicit name and version.`
|
|
12584
|
+
};
|
|
12585
|
+
}
|
|
12586
|
+
const volError = validateVolumeConfig(volumeKey, volumeConfig);
|
|
12587
|
+
if (volError) {
|
|
12588
|
+
return { valid: false, error: volError };
|
|
12589
|
+
}
|
|
12590
|
+
}
|
|
12591
|
+
}
|
|
12491
12592
|
return { valid: true };
|
|
12492
12593
|
}
|
|
12493
12594
|
|
|
@@ -12598,7 +12699,11 @@ var buildCommand = new Command().name("build").description("Create or update age
|
|
|
12598
12699
|
console.log(chalk2.gray(` Config ID: ${response.configId}`));
|
|
12599
12700
|
console.log();
|
|
12600
12701
|
console.log(" Run your agent:");
|
|
12601
|
-
console.log(
|
|
12702
|
+
console.log(
|
|
12703
|
+
chalk2.cyan(
|
|
12704
|
+
` vm0 run ${response.name} --artifact-name <artifact> "your prompt"`
|
|
12705
|
+
)
|
|
12706
|
+
);
|
|
12602
12707
|
} catch (error43) {
|
|
12603
12708
|
if (error43 instanceof Error) {
|
|
12604
12709
|
if (error43.message.includes("Not authenticated")) {
|
|
@@ -12737,7 +12842,7 @@ var ClaudeEventParser = class {
|
|
|
12737
12842
|
agentConfigId: event.agentConfigId,
|
|
12738
12843
|
agentName: event.agentName,
|
|
12739
12844
|
prompt: event.prompt,
|
|
12740
|
-
|
|
12845
|
+
templateVars: event.templateVars
|
|
12741
12846
|
}
|
|
12742
12847
|
};
|
|
12743
12848
|
}
|
|
@@ -12748,7 +12853,8 @@ var ClaudeEventParser = class {
|
|
|
12748
12853
|
data: {
|
|
12749
12854
|
runId: event.runId,
|
|
12750
12855
|
checkpointId: event.checkpointId,
|
|
12751
|
-
|
|
12856
|
+
agentSessionId: event.agentSessionId,
|
|
12857
|
+
hasArtifact: event.hasArtifact
|
|
12752
12858
|
}
|
|
12753
12859
|
};
|
|
12754
12860
|
}
|
|
@@ -12879,9 +12985,11 @@ var EventRenderer = class {
|
|
|
12879
12985
|
console.log(
|
|
12880
12986
|
` Checkpoint: ${chalk3.gray(String(event.data.checkpointId || ""))}`
|
|
12881
12987
|
);
|
|
12882
|
-
|
|
12883
|
-
|
|
12884
|
-
|
|
12988
|
+
console.log(
|
|
12989
|
+
` Session: ${chalk3.gray(String(event.data.agentSessionId || ""))}`
|
|
12990
|
+
);
|
|
12991
|
+
if (event.data.hasArtifact) {
|
|
12992
|
+
console.log(` Artifact: ${chalk3.gray("saved")}`);
|
|
12885
12993
|
}
|
|
12886
12994
|
}
|
|
12887
12995
|
static renderVm0Error(event) {
|
|
@@ -12905,18 +13013,18 @@ var EventRenderer = class {
|
|
|
12905
13013
|
};
|
|
12906
13014
|
|
|
12907
13015
|
// src/commands/run.ts
|
|
12908
|
-
function
|
|
13016
|
+
function collectVars(value, previous) {
|
|
12909
13017
|
const [key, ...valueParts] = value.split("=");
|
|
12910
13018
|
const val = valueParts.join("=");
|
|
12911
13019
|
if (!key || val === void 0 || val === "") {
|
|
12912
|
-
throw new Error(`Invalid
|
|
13020
|
+
throw new Error(`Invalid variable format: ${value} (expected key=value)`);
|
|
12913
13021
|
}
|
|
12914
13022
|
return { ...previous, [key]: val };
|
|
12915
13023
|
}
|
|
12916
13024
|
function isUUID(str) {
|
|
12917
13025
|
return /^[0-9a-f-]{36}$/i.test(str);
|
|
12918
13026
|
}
|
|
12919
|
-
var DEFAULT_TIMEOUT_SECONDS =
|
|
13027
|
+
var DEFAULT_TIMEOUT_SECONDS = 120;
|
|
12920
13028
|
async function pollEvents(runId, timeoutSeconds) {
|
|
12921
13029
|
let nextSequence = -1;
|
|
12922
13030
|
let complete = false;
|
|
@@ -12958,16 +13066,16 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
12958
13066
|
"<identifier>",
|
|
12959
13067
|
"Agent name or config ID (e.g., 'my-agent' or 'cfg-abc-123')"
|
|
12960
13068
|
).argument("<prompt>", "Prompt for the agent").option(
|
|
12961
|
-
"
|
|
12962
|
-
"
|
|
12963
|
-
|
|
13069
|
+
"--vars <KEY=value>",
|
|
13070
|
+
"Template variables for config placeholders (repeatable)",
|
|
13071
|
+
collectVars,
|
|
12964
13072
|
{}
|
|
12965
|
-
).option(
|
|
12966
|
-
"
|
|
12967
|
-
"Artifact
|
|
13073
|
+
).option("--artifact-name <name>", "Artifact storage name (required for run)").option(
|
|
13074
|
+
"--artifact-version <hash>",
|
|
13075
|
+
"Artifact version hash (defaults to latest)"
|
|
12968
13076
|
).option(
|
|
12969
13077
|
"-t, --timeout <seconds>",
|
|
12970
|
-
"Polling timeout in seconds (default:
|
|
13078
|
+
"Polling timeout in seconds (default: 120)",
|
|
12971
13079
|
String(DEFAULT_TIMEOUT_SECONDS)
|
|
12972
13080
|
).action(
|
|
12973
13081
|
async (identifier, prompt, options) => {
|
|
@@ -12978,6 +13086,15 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
12978
13086
|
);
|
|
12979
13087
|
process.exit(1);
|
|
12980
13088
|
}
|
|
13089
|
+
if (!options.artifactName) {
|
|
13090
|
+
console.error(
|
|
13091
|
+
chalk4.red("\u2717 Missing required option: --artifact-name <name>")
|
|
13092
|
+
);
|
|
13093
|
+
console.error(
|
|
13094
|
+
chalk4.gray(" The artifact-name is required for new agent runs.")
|
|
13095
|
+
);
|
|
13096
|
+
process.exit(1);
|
|
13097
|
+
}
|
|
12981
13098
|
try {
|
|
12982
13099
|
let configId;
|
|
12983
13100
|
if (isUUID(identifier)) {
|
|
@@ -13003,13 +13120,16 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
13003
13120
|
}
|
|
13004
13121
|
console.log(chalk4.blue("\nCreating agent run..."));
|
|
13005
13122
|
console.log(chalk4.gray(` Prompt: ${prompt}`));
|
|
13006
|
-
if (Object.keys(options.
|
|
13123
|
+
if (Object.keys(options.vars).length > 0) {
|
|
13007
13124
|
console.log(
|
|
13008
|
-
chalk4.gray(` Variables: ${JSON.stringify(options.
|
|
13125
|
+
chalk4.gray(` Variables: ${JSON.stringify(options.vars)}`)
|
|
13009
13126
|
);
|
|
13010
13127
|
}
|
|
13011
|
-
|
|
13012
|
-
|
|
13128
|
+
console.log(chalk4.gray(` Artifact: ${options.artifactName}`));
|
|
13129
|
+
if (options.artifactVersion) {
|
|
13130
|
+
console.log(
|
|
13131
|
+
chalk4.gray(` Artifact version: ${options.artifactVersion}`)
|
|
13132
|
+
);
|
|
13013
13133
|
}
|
|
13014
13134
|
console.log();
|
|
13015
13135
|
console.log(chalk4.blue("Executing in sandbox..."));
|
|
@@ -13017,8 +13137,9 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
13017
13137
|
const response = await apiClient.createRun({
|
|
13018
13138
|
agentConfigId: configId,
|
|
13019
13139
|
prompt,
|
|
13020
|
-
|
|
13021
|
-
|
|
13140
|
+
templateVars: Object.keys(options.vars).length > 0 ? options.vars : void 0,
|
|
13141
|
+
artifactName: options.artifactName,
|
|
13142
|
+
artifactVersion: options.artifactVersion
|
|
13022
13143
|
});
|
|
13023
13144
|
await pollEvents(response.runId, timeoutSeconds);
|
|
13024
13145
|
} catch (error43) {
|
|
@@ -13043,9 +13164,9 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
13043
13164
|
}
|
|
13044
13165
|
}
|
|
13045
13166
|
);
|
|
13046
|
-
runCmd.command("resume").description("Resume an agent run from a checkpoint").argument("<checkpointId>", "Checkpoint ID to resume from").argument("<prompt>", "Prompt for the resumed agent").option(
|
|
13167
|
+
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(
|
|
13047
13168
|
"-t, --timeout <seconds>",
|
|
13048
|
-
"Polling timeout in seconds (default:
|
|
13169
|
+
"Polling timeout in seconds (default: 120)",
|
|
13049
13170
|
String(DEFAULT_TIMEOUT_SECONDS)
|
|
13050
13171
|
).action(
|
|
13051
13172
|
async (checkpointId, prompt, options) => {
|
|
@@ -13094,6 +13215,62 @@ runCmd.command("resume").description("Resume an agent run from a checkpoint").ar
|
|
|
13094
13215
|
}
|
|
13095
13216
|
}
|
|
13096
13217
|
);
|
|
13218
|
+
runCmd.command("continue").description(
|
|
13219
|
+
"Continue an agent run from a session (uses latest artifact version)"
|
|
13220
|
+
).argument("<agentSessionId>", "Agent session ID to continue from").argument("<prompt>", "Prompt for the continued agent").option(
|
|
13221
|
+
"-t, --timeout <seconds>",
|
|
13222
|
+
"Polling timeout in seconds (default: 120)",
|
|
13223
|
+
String(DEFAULT_TIMEOUT_SECONDS)
|
|
13224
|
+
).action(
|
|
13225
|
+
async (agentSessionId, prompt, options) => {
|
|
13226
|
+
const timeoutSeconds = parseInt(options.timeout, 10);
|
|
13227
|
+
if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
13228
|
+
console.error(
|
|
13229
|
+
chalk4.red("\u2717 Invalid timeout value. Must be a positive number.")
|
|
13230
|
+
);
|
|
13231
|
+
process.exit(1);
|
|
13232
|
+
}
|
|
13233
|
+
try {
|
|
13234
|
+
if (!isUUID(agentSessionId)) {
|
|
13235
|
+
console.error(
|
|
13236
|
+
chalk4.red(`\u2717 Invalid agent session ID format: ${agentSessionId}`)
|
|
13237
|
+
);
|
|
13238
|
+
console.error(chalk4.gray(" Agent session ID must be a valid UUID"));
|
|
13239
|
+
process.exit(1);
|
|
13240
|
+
}
|
|
13241
|
+
console.log(chalk4.blue("\nContinuing agent run from session..."));
|
|
13242
|
+
console.log(chalk4.gray(` Session ID: ${agentSessionId}`));
|
|
13243
|
+
console.log(chalk4.gray(` Prompt: ${prompt}`));
|
|
13244
|
+
console.log(chalk4.gray(` Note: Using latest artifact version`));
|
|
13245
|
+
console.log();
|
|
13246
|
+
console.log(chalk4.blue("Executing in sandbox..."));
|
|
13247
|
+
console.log();
|
|
13248
|
+
const response = await apiClient.continueSession({
|
|
13249
|
+
agentSessionId,
|
|
13250
|
+
prompt
|
|
13251
|
+
});
|
|
13252
|
+
await pollEvents(response.runId, timeoutSeconds);
|
|
13253
|
+
} catch (error43) {
|
|
13254
|
+
if (error43 instanceof Error) {
|
|
13255
|
+
if (error43.message.includes("Not authenticated")) {
|
|
13256
|
+
console.error(
|
|
13257
|
+
chalk4.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
13258
|
+
);
|
|
13259
|
+
} else if (error43.message.includes("not found")) {
|
|
13260
|
+
console.error(
|
|
13261
|
+
chalk4.red(`\u2717 Agent session not found: ${agentSessionId}`)
|
|
13262
|
+
);
|
|
13263
|
+
} else {
|
|
13264
|
+
console.error(chalk4.red("\u2717 Continue failed"));
|
|
13265
|
+
console.error(chalk4.gray(` ${error43.message}`));
|
|
13266
|
+
}
|
|
13267
|
+
} else {
|
|
13268
|
+
console.error(chalk4.red("\u2717 An unexpected error occurred"));
|
|
13269
|
+
}
|
|
13270
|
+
process.exit(1);
|
|
13271
|
+
}
|
|
13272
|
+
}
|
|
13273
|
+
);
|
|
13097
13274
|
var runCommand = runCmd;
|
|
13098
13275
|
|
|
13099
13276
|
// src/commands/volume/index.ts
|
|
@@ -13293,9 +13470,80 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
13293
13470
|
// src/commands/volume/pull.ts
|
|
13294
13471
|
import { Command as Command5 } from "commander";
|
|
13295
13472
|
import chalk7 from "chalk";
|
|
13296
|
-
import
|
|
13297
|
-
import * as
|
|
13473
|
+
import path5 from "path";
|
|
13474
|
+
import * as fs3 from "fs";
|
|
13298
13475
|
import AdmZip2 from "adm-zip";
|
|
13476
|
+
|
|
13477
|
+
// src/lib/file-utils.ts
|
|
13478
|
+
import * as fs2 from "fs";
|
|
13479
|
+
import * as path4 from "path";
|
|
13480
|
+
function getRemoteFilesFromZip(zipEntries) {
|
|
13481
|
+
const remoteFiles = /* @__PURE__ */ new Set();
|
|
13482
|
+
for (const entry of zipEntries) {
|
|
13483
|
+
if (!entry.isDirectory) {
|
|
13484
|
+
remoteFiles.add(entry.entryName.replace(/\\/g, "/"));
|
|
13485
|
+
}
|
|
13486
|
+
}
|
|
13487
|
+
return remoteFiles;
|
|
13488
|
+
}
|
|
13489
|
+
async function listLocalFiles(dir, excludeDirs = [".vm0"]) {
|
|
13490
|
+
const files = [];
|
|
13491
|
+
async function walkDir(currentDir, relativePath = "") {
|
|
13492
|
+
const entries = await fs2.promises.readdir(currentDir, {
|
|
13493
|
+
withFileTypes: true
|
|
13494
|
+
});
|
|
13495
|
+
for (const entry of entries) {
|
|
13496
|
+
const entryRelativePath = relativePath ? path4.join(relativePath, entry.name) : entry.name;
|
|
13497
|
+
if (entry.isDirectory()) {
|
|
13498
|
+
if (!excludeDirs.includes(entry.name)) {
|
|
13499
|
+
await walkDir(path4.join(currentDir, entry.name), entryRelativePath);
|
|
13500
|
+
}
|
|
13501
|
+
} else {
|
|
13502
|
+
files.push(entryRelativePath);
|
|
13503
|
+
}
|
|
13504
|
+
}
|
|
13505
|
+
}
|
|
13506
|
+
await walkDir(dir);
|
|
13507
|
+
return files;
|
|
13508
|
+
}
|
|
13509
|
+
async function removeExtraFiles(dir, remoteFiles, excludeDirs = [".vm0"]) {
|
|
13510
|
+
const localFiles = await listLocalFiles(dir, excludeDirs);
|
|
13511
|
+
let removedCount = 0;
|
|
13512
|
+
for (const localFile of localFiles) {
|
|
13513
|
+
const normalizedPath = localFile.replace(/\\/g, "/");
|
|
13514
|
+
if (!remoteFiles.has(normalizedPath)) {
|
|
13515
|
+
const fullPath = path4.join(dir, localFile);
|
|
13516
|
+
await fs2.promises.unlink(fullPath);
|
|
13517
|
+
removedCount++;
|
|
13518
|
+
}
|
|
13519
|
+
}
|
|
13520
|
+
await removeEmptyDirs(dir, excludeDirs);
|
|
13521
|
+
return removedCount;
|
|
13522
|
+
}
|
|
13523
|
+
async function removeEmptyDirs(dir, excludeDirs = [".vm0"]) {
|
|
13524
|
+
const entries = await fs2.promises.readdir(dir, { withFileTypes: true });
|
|
13525
|
+
let isEmpty = true;
|
|
13526
|
+
for (const entry of entries) {
|
|
13527
|
+
const fullPath = path4.join(dir, entry.name);
|
|
13528
|
+
if (entry.isDirectory()) {
|
|
13529
|
+
if (excludeDirs.includes(entry.name)) {
|
|
13530
|
+
isEmpty = false;
|
|
13531
|
+
} else {
|
|
13532
|
+
const subDirEmpty = await removeEmptyDirs(fullPath, excludeDirs);
|
|
13533
|
+
if (subDirEmpty) {
|
|
13534
|
+
await fs2.promises.rmdir(fullPath);
|
|
13535
|
+
} else {
|
|
13536
|
+
isEmpty = false;
|
|
13537
|
+
}
|
|
13538
|
+
}
|
|
13539
|
+
} else {
|
|
13540
|
+
isEmpty = false;
|
|
13541
|
+
}
|
|
13542
|
+
}
|
|
13543
|
+
return isEmpty;
|
|
13544
|
+
}
|
|
13545
|
+
|
|
13546
|
+
// src/commands/volume/pull.ts
|
|
13299
13547
|
function formatBytes2(bytes) {
|
|
13300
13548
|
if (bytes === 0) return "0 B";
|
|
13301
13549
|
const k = 1024;
|
|
@@ -13303,7 +13551,7 @@ function formatBytes2(bytes) {
|
|
|
13303
13551
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
13304
13552
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
13305
13553
|
}
|
|
13306
|
-
var pullCommand = new Command5().name("pull").description("Pull cloud files to local directory").action(async () => {
|
|
13554
|
+
var pullCommand = new Command5().name("pull").description("Pull cloud files to local directory").argument("[versionId]", "Version ID to pull (default: latest)").action(async (versionId) => {
|
|
13307
13555
|
try {
|
|
13308
13556
|
const cwd = process.cwd();
|
|
13309
13557
|
const config2 = await readStorageConfig(cwd);
|
|
@@ -13312,11 +13560,19 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
13312
13560
|
console.error(chalk7.gray(" Run: vm0 volume init"));
|
|
13313
13561
|
process.exit(1);
|
|
13314
13562
|
}
|
|
13315
|
-
|
|
13563
|
+
if (versionId) {
|
|
13564
|
+
console.log(
|
|
13565
|
+
chalk7.cyan(`Pulling volume: ${config2.name} (version: ${versionId})`)
|
|
13566
|
+
);
|
|
13567
|
+
} else {
|
|
13568
|
+
console.log(chalk7.cyan(`Pulling volume: ${config2.name}`));
|
|
13569
|
+
}
|
|
13316
13570
|
console.log(chalk7.gray("Downloading..."));
|
|
13317
|
-
|
|
13318
|
-
|
|
13319
|
-
|
|
13571
|
+
let url2 = `/api/storages?name=${encodeURIComponent(config2.name)}`;
|
|
13572
|
+
if (versionId) {
|
|
13573
|
+
url2 += `&version=${encodeURIComponent(versionId)}`;
|
|
13574
|
+
}
|
|
13575
|
+
const response = await apiClient.get(url2);
|
|
13320
13576
|
if (!response.ok) {
|
|
13321
13577
|
if (response.status === 404) {
|
|
13322
13578
|
console.error(chalk7.red(`\u2717 Volume "${config2.name}" not found`));
|
|
@@ -13340,14 +13596,22 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
13340
13596
|
console.log(chalk7.gray("Extracting files..."));
|
|
13341
13597
|
const zip = new AdmZip2(zipBuffer);
|
|
13342
13598
|
const zipEntries = zip.getEntries();
|
|
13599
|
+
const remoteFiles = getRemoteFilesFromZip(zipEntries);
|
|
13600
|
+
console.log(chalk7.gray("Syncing local files..."));
|
|
13601
|
+
const removedCount = await removeExtraFiles(cwd, remoteFiles);
|
|
13602
|
+
if (removedCount > 0) {
|
|
13603
|
+
console.log(
|
|
13604
|
+
chalk7.green(`\u2713 Removed ${removedCount} files not in remote`)
|
|
13605
|
+
);
|
|
13606
|
+
}
|
|
13343
13607
|
let extractedCount = 0;
|
|
13344
13608
|
for (const entry of zipEntries) {
|
|
13345
13609
|
if (!entry.isDirectory) {
|
|
13346
|
-
const targetPath =
|
|
13347
|
-
const dir =
|
|
13348
|
-
await
|
|
13610
|
+
const targetPath = path5.join(cwd, entry.entryName);
|
|
13611
|
+
const dir = path5.dirname(targetPath);
|
|
13612
|
+
await fs3.promises.mkdir(dir, { recursive: true });
|
|
13349
13613
|
const data = entry.getData();
|
|
13350
|
-
await
|
|
13614
|
+
await fs3.promises.writeFile(targetPath, data);
|
|
13351
13615
|
extractedCount++;
|
|
13352
13616
|
}
|
|
13353
13617
|
}
|
|
@@ -13370,11 +13634,11 @@ import { Command as Command10 } from "commander";
|
|
|
13370
13634
|
// src/commands/artifact/init.ts
|
|
13371
13635
|
import { Command as Command7 } from "commander";
|
|
13372
13636
|
import chalk8 from "chalk";
|
|
13373
|
-
import
|
|
13637
|
+
import path6 from "path";
|
|
13374
13638
|
var initCommand2 = new Command7().name("init").description("Initialize an artifact in the current directory").action(async () => {
|
|
13375
13639
|
try {
|
|
13376
13640
|
const cwd = process.cwd();
|
|
13377
|
-
const dirName =
|
|
13641
|
+
const dirName = path6.basename(cwd);
|
|
13378
13642
|
const existingConfig = await readStorageConfig(cwd);
|
|
13379
13643
|
if (existingConfig) {
|
|
13380
13644
|
if (existingConfig.type === "artifact") {
|
|
@@ -13396,7 +13660,7 @@ var initCommand2 = new Command7().name("init").description("Initialize an artifa
|
|
|
13396
13660
|
);
|
|
13397
13661
|
}
|
|
13398
13662
|
console.log(
|
|
13399
|
-
chalk8.gray(`Config file: ${
|
|
13663
|
+
chalk8.gray(`Config file: ${path6.join(cwd, ".vm0", "storage.yaml")}`)
|
|
13400
13664
|
);
|
|
13401
13665
|
return;
|
|
13402
13666
|
}
|
|
@@ -13417,7 +13681,7 @@ var initCommand2 = new Command7().name("init").description("Initialize an artifa
|
|
|
13417
13681
|
console.log(chalk8.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
13418
13682
|
console.log(
|
|
13419
13683
|
chalk8.gray(
|
|
13420
|
-
`\u2713 Config saved to ${
|
|
13684
|
+
`\u2713 Config saved to ${path6.join(cwd, ".vm0", "storage.yaml")}`
|
|
13421
13685
|
)
|
|
13422
13686
|
);
|
|
13423
13687
|
} catch (error43) {
|
|
@@ -13432,15 +13696,15 @@ var initCommand2 = new Command7().name("init").description("Initialize an artifa
|
|
|
13432
13696
|
// src/commands/artifact/push.ts
|
|
13433
13697
|
import { Command as Command8 } from "commander";
|
|
13434
13698
|
import chalk9 from "chalk";
|
|
13435
|
-
import
|
|
13436
|
-
import * as
|
|
13699
|
+
import path7 from "path";
|
|
13700
|
+
import * as fs4 from "fs";
|
|
13437
13701
|
import AdmZip3 from "adm-zip";
|
|
13438
13702
|
async function getAllFiles2(dirPath, baseDir = dirPath) {
|
|
13439
13703
|
const files = [];
|
|
13440
|
-
const entries = await
|
|
13704
|
+
const entries = await fs4.promises.readdir(dirPath, { withFileTypes: true });
|
|
13441
13705
|
for (const entry of entries) {
|
|
13442
|
-
const fullPath =
|
|
13443
|
-
const relativePath =
|
|
13706
|
+
const fullPath = path7.join(dirPath, entry.name);
|
|
13707
|
+
const relativePath = path7.relative(baseDir, fullPath);
|
|
13444
13708
|
if (relativePath.startsWith(".vm0")) {
|
|
13445
13709
|
continue;
|
|
13446
13710
|
}
|
|
@@ -13487,7 +13751,7 @@ var pushCommand2 = new Command8().name("push").description("Push local files to
|
|
|
13487
13751
|
}
|
|
13488
13752
|
let totalSize = 0;
|
|
13489
13753
|
for (const file2 of files) {
|
|
13490
|
-
const stats = await
|
|
13754
|
+
const stats = await fs4.promises.stat(file2);
|
|
13491
13755
|
totalSize += stats.size;
|
|
13492
13756
|
}
|
|
13493
13757
|
console.log(
|
|
@@ -13496,8 +13760,8 @@ var pushCommand2 = new Command8().name("push").description("Push local files to
|
|
|
13496
13760
|
console.log(chalk9.gray("Compressing files..."));
|
|
13497
13761
|
const zip = new AdmZip3();
|
|
13498
13762
|
for (const file2 of files) {
|
|
13499
|
-
const relativePath =
|
|
13500
|
-
zip.addLocalFile(file2,
|
|
13763
|
+
const relativePath = path7.relative(cwd, file2);
|
|
13764
|
+
zip.addLocalFile(file2, path7.dirname(relativePath));
|
|
13501
13765
|
}
|
|
13502
13766
|
const zipBuffer = zip.toBuffer();
|
|
13503
13767
|
console.log(
|
|
@@ -13536,8 +13800,8 @@ var pushCommand2 = new Command8().name("push").description("Push local files to
|
|
|
13536
13800
|
// src/commands/artifact/pull.ts
|
|
13537
13801
|
import { Command as Command9 } from "commander";
|
|
13538
13802
|
import chalk10 from "chalk";
|
|
13539
|
-
import
|
|
13540
|
-
import * as
|
|
13803
|
+
import path8 from "path";
|
|
13804
|
+
import * as fs5 from "fs";
|
|
13541
13805
|
import AdmZip4 from "adm-zip";
|
|
13542
13806
|
function formatBytes4(bytes) {
|
|
13543
13807
|
if (bytes === 0) return "0 B";
|
|
@@ -13546,7 +13810,7 @@ function formatBytes4(bytes) {
|
|
|
13546
13810
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
13547
13811
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
13548
13812
|
}
|
|
13549
|
-
var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact to local directory").action(async () => {
|
|
13813
|
+
var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact to local directory").argument("[versionId]", "Version ID to pull (default: latest)").action(async (versionId) => {
|
|
13550
13814
|
try {
|
|
13551
13815
|
const cwd = process.cwd();
|
|
13552
13816
|
const config2 = await readStorageConfig(cwd);
|
|
@@ -13564,11 +13828,21 @@ var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact
|
|
|
13564
13828
|
console.error(chalk10.gray(" Use: vm0 volume pull"));
|
|
13565
13829
|
process.exit(1);
|
|
13566
13830
|
}
|
|
13567
|
-
|
|
13831
|
+
if (versionId) {
|
|
13832
|
+
console.log(
|
|
13833
|
+
chalk10.cyan(
|
|
13834
|
+
`Pulling artifact: ${config2.name} (version: ${versionId})`
|
|
13835
|
+
)
|
|
13836
|
+
);
|
|
13837
|
+
} else {
|
|
13838
|
+
console.log(chalk10.cyan(`Pulling artifact: ${config2.name}`));
|
|
13839
|
+
}
|
|
13568
13840
|
console.log(chalk10.gray("Downloading..."));
|
|
13569
|
-
|
|
13570
|
-
|
|
13571
|
-
|
|
13841
|
+
let url2 = `/api/storages?name=${encodeURIComponent(config2.name)}`;
|
|
13842
|
+
if (versionId) {
|
|
13843
|
+
url2 += `&version=${encodeURIComponent(versionId)}`;
|
|
13844
|
+
}
|
|
13845
|
+
const response = await apiClient.get(url2);
|
|
13572
13846
|
if (!response.ok) {
|
|
13573
13847
|
if (response.status === 404) {
|
|
13574
13848
|
console.error(chalk10.red(`\u2717 Artifact "${config2.name}" not found`));
|
|
@@ -13592,14 +13866,22 @@ var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact
|
|
|
13592
13866
|
console.log(chalk10.gray("Extracting files..."));
|
|
13593
13867
|
const zip = new AdmZip4(zipBuffer);
|
|
13594
13868
|
const zipEntries = zip.getEntries();
|
|
13869
|
+
const remoteFiles = getRemoteFilesFromZip(zipEntries);
|
|
13870
|
+
console.log(chalk10.gray("Syncing local files..."));
|
|
13871
|
+
const removedCount = await removeExtraFiles(cwd, remoteFiles);
|
|
13872
|
+
if (removedCount > 0) {
|
|
13873
|
+
console.log(
|
|
13874
|
+
chalk10.green(`\u2713 Removed ${removedCount} files not in remote`)
|
|
13875
|
+
);
|
|
13876
|
+
}
|
|
13595
13877
|
let extractedCount = 0;
|
|
13596
13878
|
for (const entry of zipEntries) {
|
|
13597
13879
|
if (!entry.isDirectory) {
|
|
13598
|
-
const targetPath =
|
|
13599
|
-
const dir =
|
|
13600
|
-
await
|
|
13880
|
+
const targetPath = path8.join(cwd, entry.entryName);
|
|
13881
|
+
const dir = path8.dirname(targetPath);
|
|
13882
|
+
await fs5.promises.mkdir(dir, { recursive: true });
|
|
13601
13883
|
const data = entry.getData();
|
|
13602
|
-
await
|
|
13884
|
+
await fs5.promises.writeFile(targetPath, data);
|
|
13603
13885
|
extractedCount++;
|
|
13604
13886
|
}
|
|
13605
13887
|
}
|
|
@@ -13618,7 +13900,7 @@ var artifactCommand = new Command10().name("artifact").description("Manage cloud
|
|
|
13618
13900
|
|
|
13619
13901
|
// src/index.ts
|
|
13620
13902
|
var program = new Command11();
|
|
13621
|
-
program.name("vm0").description("VM0 CLI - A modern build tool").version("
|
|
13903
|
+
program.name("vm0").description("VM0 CLI - A modern build tool").version("1.9.0");
|
|
13622
13904
|
program.command("hello").description("Say hello from the App").action(() => {
|
|
13623
13905
|
console.log(chalk11.blue("Welcome to the VM0 CLI!"));
|
|
13624
13906
|
console.log(chalk11.green(`Core says: ${FOO}`));
|
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vm0/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "CLI application",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/vm0-ai/vm0",
|
|
8
|
+
"directory": "turbo/apps/cli"
|
|
9
|
+
},
|
|
5
10
|
"type": "module",
|
|
6
11
|
"bin": {
|
|
7
12
|
"vm0": "index.js"
|