@vm0/cli 1.4.0 → 1.6.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 +376 -80
- package/package.json +1 -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, path8) {
|
|
740
|
+
if (!path8)
|
|
741
741
|
return obj;
|
|
742
|
-
return
|
|
742
|
+
return path8.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 promises5 = keys.map((key) => promisesObj[key]);
|
|
747
|
+
return Promise.all(promises5).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(path8, 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(path8);
|
|
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, path8 = []) => {
|
|
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 = [...path8, ...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 path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1316
|
+
for (const seg of path8) {
|
|
1317
1317
|
if (typeof seg === "number")
|
|
1318
1318
|
segs.push(`[${seg}]`);
|
|
1319
1319
|
else if (typeof seg === "symbol")
|
|
@@ -12147,8 +12147,8 @@ var helloContract = c.router({
|
|
|
12147
12147
|
var FOO = "hello";
|
|
12148
12148
|
|
|
12149
12149
|
// src/index.ts
|
|
12150
|
-
import { Command as
|
|
12151
|
-
import
|
|
12150
|
+
import { Command as Command11 } from "commander";
|
|
12151
|
+
import chalk11 from "chalk";
|
|
12152
12152
|
|
|
12153
12153
|
// src/lib/auth.ts
|
|
12154
12154
|
import chalk from "chalk";
|
|
@@ -12416,7 +12416,7 @@ var ApiClient = class {
|
|
|
12416
12416
|
/**
|
|
12417
12417
|
* Generic GET request
|
|
12418
12418
|
*/
|
|
12419
|
-
async get(
|
|
12419
|
+
async get(path8) {
|
|
12420
12420
|
const baseUrl = await this.getBaseUrl();
|
|
12421
12421
|
const token = await getToken();
|
|
12422
12422
|
if (!token) {
|
|
@@ -12429,7 +12429,7 @@ var ApiClient = class {
|
|
|
12429
12429
|
if (bypassSecret) {
|
|
12430
12430
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
12431
12431
|
}
|
|
12432
|
-
return fetch(`${baseUrl}${
|
|
12432
|
+
return fetch(`${baseUrl}${path8}`, {
|
|
12433
12433
|
method: "GET",
|
|
12434
12434
|
headers
|
|
12435
12435
|
});
|
|
@@ -12437,7 +12437,7 @@ var ApiClient = class {
|
|
|
12437
12437
|
/**
|
|
12438
12438
|
* Generic POST request
|
|
12439
12439
|
*/
|
|
12440
|
-
async post(
|
|
12440
|
+
async post(path8, options) {
|
|
12441
12441
|
const baseUrl = await this.getBaseUrl();
|
|
12442
12442
|
const token = await getToken();
|
|
12443
12443
|
if (!token) {
|
|
@@ -12450,7 +12450,7 @@ var ApiClient = class {
|
|
|
12450
12450
|
if (bypassSecret) {
|
|
12451
12451
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
12452
12452
|
}
|
|
12453
|
-
return fetch(`${baseUrl}${
|
|
12453
|
+
return fetch(`${baseUrl}${path8}`, {
|
|
12454
12454
|
method: "POST",
|
|
12455
12455
|
headers,
|
|
12456
12456
|
body: options?.body
|
|
@@ -12821,9 +12821,7 @@ var EventRenderer = class {
|
|
|
12821
12821
|
if (input && typeof input === "object") {
|
|
12822
12822
|
for (const [key, value] of Object.entries(input)) {
|
|
12823
12823
|
if (value !== void 0 && value !== null) {
|
|
12824
|
-
|
|
12825
|
-
const displayValue = valueStr.length > 100 ? valueStr.substring(0, 100) + "..." : valueStr;
|
|
12826
|
-
console.log(` ${key}: ${chalk3.gray(displayValue)}`);
|
|
12824
|
+
console.log(` ${key}: ${chalk3.gray(String(value))}`);
|
|
12827
12825
|
}
|
|
12828
12826
|
}
|
|
12829
12827
|
}
|
|
@@ -12834,8 +12832,7 @@ var EventRenderer = class {
|
|
|
12834
12832
|
const color = isError ? chalk3.red : chalk3.green;
|
|
12835
12833
|
console.log(color("[tool_result]") + " " + status);
|
|
12836
12834
|
const result = String(event.data.result || "");
|
|
12837
|
-
|
|
12838
|
-
console.log(` ${chalk3.gray(displayResult)}`);
|
|
12835
|
+
console.log(` ${chalk3.gray(result)}`);
|
|
12839
12836
|
}
|
|
12840
12837
|
static renderResult(event) {
|
|
12841
12838
|
const success2 = Boolean(event.data.success);
|
|
@@ -12872,8 +12869,7 @@ var EventRenderer = class {
|
|
|
12872
12869
|
console.log(` Run ID: ${chalk3.gray(String(event.data.runId))}`);
|
|
12873
12870
|
}
|
|
12874
12871
|
const prompt = String(event.data.prompt || "");
|
|
12875
|
-
|
|
12876
|
-
console.log(` Prompt: ${chalk3.gray(displayPrompt)}`);
|
|
12872
|
+
console.log(` Prompt: ${chalk3.gray(prompt)}`);
|
|
12877
12873
|
if (event.data.agentName) {
|
|
12878
12874
|
console.log(` Agent: ${chalk3.gray(String(event.data.agentName))}`);
|
|
12879
12875
|
}
|
|
@@ -12920,18 +12916,20 @@ function collectEnvVars(value, previous) {
|
|
|
12920
12916
|
function isUUID(str) {
|
|
12921
12917
|
return /^[0-9a-f-]{36}$/i.test(str);
|
|
12922
12918
|
}
|
|
12923
|
-
|
|
12919
|
+
var DEFAULT_TIMEOUT_SECONDS = 60;
|
|
12920
|
+
async function pollEvents(runId, timeoutSeconds) {
|
|
12924
12921
|
let nextSequence = -1;
|
|
12925
12922
|
let complete = false;
|
|
12926
12923
|
const pollIntervalMs = 500;
|
|
12927
|
-
const timeoutMs =
|
|
12924
|
+
const timeoutMs = timeoutSeconds * 1e3;
|
|
12928
12925
|
const startTime = Date.now();
|
|
12929
12926
|
while (!complete) {
|
|
12930
12927
|
const elapsed = Date.now() - startTime;
|
|
12931
12928
|
if (elapsed > timeoutMs) {
|
|
12932
12929
|
console.error(
|
|
12933
12930
|
chalk4.red(
|
|
12934
|
-
|
|
12931
|
+
`
|
|
12932
|
+
\u2717 Agent execution timed out after ${timeoutSeconds} seconds without receiving events`
|
|
12935
12933
|
)
|
|
12936
12934
|
);
|
|
12937
12935
|
throw new Error("Agent execution timed out");
|
|
@@ -12964,8 +12962,22 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
12964
12962
|
"Environment variables (repeatable)",
|
|
12965
12963
|
collectEnvVars,
|
|
12966
12964
|
{}
|
|
12965
|
+
).option(
|
|
12966
|
+
"-a, --artifact <key>",
|
|
12967
|
+
"Artifact key to mount (for VM0 driver artifacts)"
|
|
12968
|
+
).option(
|
|
12969
|
+
"-t, --timeout <seconds>",
|
|
12970
|
+
"Polling timeout in seconds (default: 60)",
|
|
12971
|
+
String(DEFAULT_TIMEOUT_SECONDS)
|
|
12967
12972
|
).action(
|
|
12968
12973
|
async (identifier, prompt, options) => {
|
|
12974
|
+
const timeoutSeconds = parseInt(options.timeout, 10);
|
|
12975
|
+
if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
12976
|
+
console.error(
|
|
12977
|
+
chalk4.red("\u2717 Invalid timeout value. Must be a positive number.")
|
|
12978
|
+
);
|
|
12979
|
+
process.exit(1);
|
|
12980
|
+
}
|
|
12969
12981
|
try {
|
|
12970
12982
|
let configId;
|
|
12971
12983
|
if (isUUID(identifier)) {
|
|
@@ -12996,15 +13008,19 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
12996
13008
|
chalk4.gray(` Variables: ${JSON.stringify(options.env)}`)
|
|
12997
13009
|
);
|
|
12998
13010
|
}
|
|
13011
|
+
if (options.artifact) {
|
|
13012
|
+
console.log(chalk4.gray(` Artifact: ${options.artifact}`));
|
|
13013
|
+
}
|
|
12999
13014
|
console.log();
|
|
13000
13015
|
console.log(chalk4.blue("Executing in sandbox..."));
|
|
13001
13016
|
console.log();
|
|
13002
13017
|
const response = await apiClient.createRun({
|
|
13003
13018
|
agentConfigId: configId,
|
|
13004
13019
|
prompt,
|
|
13005
|
-
dynamicVars: Object.keys(options.env).length > 0 ? options.env : void 0
|
|
13020
|
+
dynamicVars: Object.keys(options.env).length > 0 ? options.env : void 0,
|
|
13021
|
+
artifactKey: options.artifact
|
|
13006
13022
|
});
|
|
13007
|
-
await pollEvents(response.runId);
|
|
13023
|
+
await pollEvents(response.runId, timeoutSeconds);
|
|
13008
13024
|
} catch (error43) {
|
|
13009
13025
|
if (error43 instanceof Error) {
|
|
13010
13026
|
if (error43.message.includes("Not authenticated")) {
|
|
@@ -13027,42 +13043,57 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
13027
13043
|
}
|
|
13028
13044
|
}
|
|
13029
13045
|
);
|
|
13030
|
-
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").
|
|
13031
|
-
|
|
13032
|
-
|
|
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(
|
|
13047
|
+
"-t, --timeout <seconds>",
|
|
13048
|
+
"Polling timeout in seconds (default: 60)",
|
|
13049
|
+
String(DEFAULT_TIMEOUT_SECONDS)
|
|
13050
|
+
).action(
|
|
13051
|
+
async (checkpointId, prompt, options) => {
|
|
13052
|
+
const timeoutSeconds = parseInt(options.timeout, 10);
|
|
13053
|
+
if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
13033
13054
|
console.error(
|
|
13034
|
-
chalk4.red(
|
|
13055
|
+
chalk4.red("\u2717 Invalid timeout value. Must be a positive number.")
|
|
13035
13056
|
);
|
|
13036
|
-
console.error(chalk4.gray(" Checkpoint ID must be a valid UUID"));
|
|
13037
13057
|
process.exit(1);
|
|
13038
13058
|
}
|
|
13039
|
-
|
|
13040
|
-
|
|
13041
|
-
|
|
13042
|
-
|
|
13043
|
-
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
|
|
13048
|
-
|
|
13049
|
-
|
|
13050
|
-
|
|
13051
|
-
|
|
13052
|
-
|
|
13053
|
-
|
|
13054
|
-
|
|
13055
|
-
|
|
13059
|
+
try {
|
|
13060
|
+
if (!isUUID(checkpointId)) {
|
|
13061
|
+
console.error(
|
|
13062
|
+
chalk4.red(`\u2717 Invalid checkpoint ID format: ${checkpointId}`)
|
|
13063
|
+
);
|
|
13064
|
+
console.error(chalk4.gray(" Checkpoint ID must be a valid UUID"));
|
|
13065
|
+
process.exit(1);
|
|
13066
|
+
}
|
|
13067
|
+
console.log(chalk4.blue("\nResuming agent run from checkpoint..."));
|
|
13068
|
+
console.log(chalk4.gray(` Checkpoint ID: ${checkpointId}`));
|
|
13069
|
+
console.log(chalk4.gray(` Prompt: ${prompt}`));
|
|
13070
|
+
console.log();
|
|
13071
|
+
console.log(chalk4.blue("Executing in sandbox..."));
|
|
13072
|
+
console.log();
|
|
13073
|
+
const response = await apiClient.resumeRun({
|
|
13074
|
+
checkpointId,
|
|
13075
|
+
prompt
|
|
13076
|
+
});
|
|
13077
|
+
await pollEvents(response.runId, timeoutSeconds);
|
|
13078
|
+
} catch (error43) {
|
|
13079
|
+
if (error43 instanceof Error) {
|
|
13080
|
+
if (error43.message.includes("Not authenticated")) {
|
|
13081
|
+
console.error(
|
|
13082
|
+
chalk4.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
13083
|
+
);
|
|
13084
|
+
} else if (error43.message.includes("not found")) {
|
|
13085
|
+
console.error(chalk4.red(`\u2717 Checkpoint not found: ${checkpointId}`));
|
|
13086
|
+
} else {
|
|
13087
|
+
console.error(chalk4.red("\u2717 Resume failed"));
|
|
13088
|
+
console.error(chalk4.gray(` ${error43.message}`));
|
|
13089
|
+
}
|
|
13056
13090
|
} else {
|
|
13057
|
-
console.error(chalk4.red("\u2717
|
|
13058
|
-
console.error(chalk4.gray(` ${error43.message}`));
|
|
13091
|
+
console.error(chalk4.red("\u2717 An unexpected error occurred"));
|
|
13059
13092
|
}
|
|
13060
|
-
|
|
13061
|
-
console.error(chalk4.red("\u2717 An unexpected error occurred"));
|
|
13093
|
+
process.exit(1);
|
|
13062
13094
|
}
|
|
13063
|
-
process.exit(1);
|
|
13064
13095
|
}
|
|
13065
|
-
|
|
13096
|
+
);
|
|
13066
13097
|
var runCommand = runCmd;
|
|
13067
13098
|
|
|
13068
13099
|
// src/commands/volume/index.ts
|
|
@@ -13073,37 +13104,48 @@ import { Command as Command3 } from "commander";
|
|
|
13073
13104
|
import chalk5 from "chalk";
|
|
13074
13105
|
import path2 from "path";
|
|
13075
13106
|
|
|
13076
|
-
// src/lib/
|
|
13107
|
+
// src/lib/storage-utils.ts
|
|
13077
13108
|
import { readFile as readFile3, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
13078
13109
|
import { existsSync as existsSync3 } from "fs";
|
|
13079
13110
|
import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
|
|
13080
13111
|
import path from "path";
|
|
13081
13112
|
var CONFIG_DIR2 = ".vm0";
|
|
13082
|
-
var CONFIG_FILE2 = "
|
|
13083
|
-
function
|
|
13113
|
+
var CONFIG_FILE2 = "storage.yaml";
|
|
13114
|
+
function isValidStorageName(name) {
|
|
13084
13115
|
if (name.length < 3 || name.length > 64) {
|
|
13085
13116
|
return false;
|
|
13086
13117
|
}
|
|
13087
13118
|
const pattern = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/;
|
|
13088
13119
|
return pattern.test(name) && !name.includes("--");
|
|
13089
13120
|
}
|
|
13090
|
-
async function
|
|
13121
|
+
async function readStorageConfig(basePath = process.cwd()) {
|
|
13091
13122
|
const configPath = path.join(basePath, CONFIG_DIR2, CONFIG_FILE2);
|
|
13092
|
-
|
|
13123
|
+
const legacyConfigPath = path.join(basePath, CONFIG_DIR2, "volume.yaml");
|
|
13124
|
+
let actualPath = null;
|
|
13125
|
+
if (existsSync3(configPath)) {
|
|
13126
|
+
actualPath = configPath;
|
|
13127
|
+
} else if (existsSync3(legacyConfigPath)) {
|
|
13128
|
+
actualPath = legacyConfigPath;
|
|
13129
|
+
}
|
|
13130
|
+
if (!actualPath) {
|
|
13093
13131
|
return null;
|
|
13094
13132
|
}
|
|
13095
|
-
const content = await readFile3(
|
|
13133
|
+
const content = await readFile3(actualPath, "utf8");
|
|
13096
13134
|
const config2 = parseYaml2(content);
|
|
13135
|
+
if (!config2.type) {
|
|
13136
|
+
config2.type = "volume";
|
|
13137
|
+
}
|
|
13097
13138
|
return config2;
|
|
13098
13139
|
}
|
|
13099
|
-
async function
|
|
13140
|
+
async function writeStorageConfig(storageName, basePath = process.cwd(), type = "volume") {
|
|
13100
13141
|
const configDir = path.join(basePath, CONFIG_DIR2);
|
|
13101
13142
|
const configPath = path.join(configDir, CONFIG_FILE2);
|
|
13102
13143
|
if (!existsSync3(configDir)) {
|
|
13103
13144
|
await mkdir2(configDir, { recursive: true });
|
|
13104
13145
|
}
|
|
13105
13146
|
const config2 = {
|
|
13106
|
-
name:
|
|
13147
|
+
name: storageName,
|
|
13148
|
+
type
|
|
13107
13149
|
};
|
|
13108
13150
|
const yamlContent = stringifyYaml(config2);
|
|
13109
13151
|
await writeFile2(configPath, yamlContent, "utf8");
|
|
@@ -13114,18 +13156,18 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
13114
13156
|
try {
|
|
13115
13157
|
const cwd = process.cwd();
|
|
13116
13158
|
const dirName = path2.basename(cwd);
|
|
13117
|
-
const existingConfig = await
|
|
13159
|
+
const existingConfig = await readStorageConfig(cwd);
|
|
13118
13160
|
if (existingConfig) {
|
|
13119
13161
|
console.log(
|
|
13120
13162
|
chalk5.yellow(`Volume already initialized: ${existingConfig.name}`)
|
|
13121
13163
|
);
|
|
13122
13164
|
console.log(
|
|
13123
|
-
chalk5.gray(`Config file: ${path2.join(cwd, ".vm0", "
|
|
13165
|
+
chalk5.gray(`Config file: ${path2.join(cwd, ".vm0", "storage.yaml")}`)
|
|
13124
13166
|
);
|
|
13125
13167
|
return;
|
|
13126
13168
|
}
|
|
13127
13169
|
const volumeName = dirName;
|
|
13128
|
-
if (!
|
|
13170
|
+
if (!isValidStorageName(volumeName)) {
|
|
13129
13171
|
console.error(chalk5.red(`\u2717 Invalid volume name: "${dirName}"`));
|
|
13130
13172
|
console.error(
|
|
13131
13173
|
chalk5.gray(
|
|
@@ -13137,11 +13179,11 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
13137
13179
|
);
|
|
13138
13180
|
process.exit(1);
|
|
13139
13181
|
}
|
|
13140
|
-
await
|
|
13182
|
+
await writeStorageConfig(volumeName, cwd);
|
|
13141
13183
|
console.log(chalk5.green(`\u2713 Initialized volume: ${volumeName}`));
|
|
13142
13184
|
console.log(
|
|
13143
13185
|
chalk5.gray(
|
|
13144
|
-
`\u2713 Config saved to ${path2.join(cwd, ".vm0", "
|
|
13186
|
+
`\u2713 Config saved to ${path2.join(cwd, ".vm0", "storage.yaml")}`
|
|
13145
13187
|
)
|
|
13146
13188
|
);
|
|
13147
13189
|
} catch (error43) {
|
|
@@ -13187,7 +13229,7 @@ function formatBytes(bytes) {
|
|
|
13187
13229
|
var pushCommand = new Command4().name("push").description("Push local files to cloud volume").action(async () => {
|
|
13188
13230
|
try {
|
|
13189
13231
|
const cwd = process.cwd();
|
|
13190
|
-
const config2 = await
|
|
13232
|
+
const config2 = await readStorageConfig(cwd);
|
|
13191
13233
|
if (!config2) {
|
|
13192
13234
|
console.error(chalk6.red("\u2717 No volume initialized in this directory"));
|
|
13193
13235
|
console.error(chalk6.gray(" Run: vm0 volume init"));
|
|
@@ -13220,13 +13262,14 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
13220
13262
|
);
|
|
13221
13263
|
console.log(chalk6.gray("Uploading..."));
|
|
13222
13264
|
const formData = new FormData();
|
|
13223
|
-
formData.append("
|
|
13265
|
+
formData.append("name", config2.name);
|
|
13266
|
+
formData.append("type", "volume");
|
|
13224
13267
|
formData.append(
|
|
13225
13268
|
"file",
|
|
13226
13269
|
new Blob([zipBuffer], { type: "application/zip" }),
|
|
13227
13270
|
"volume.zip"
|
|
13228
13271
|
);
|
|
13229
|
-
const response = await apiClient.post("/api/
|
|
13272
|
+
const response = await apiClient.post("/api/storages", {
|
|
13230
13273
|
body: formData
|
|
13231
13274
|
});
|
|
13232
13275
|
if (!response.ok) {
|
|
@@ -13263,7 +13306,7 @@ function formatBytes2(bytes) {
|
|
|
13263
13306
|
var pullCommand = new Command5().name("pull").description("Pull cloud files to local directory").action(async () => {
|
|
13264
13307
|
try {
|
|
13265
13308
|
const cwd = process.cwd();
|
|
13266
|
-
const config2 = await
|
|
13309
|
+
const config2 = await readStorageConfig(cwd);
|
|
13267
13310
|
if (!config2) {
|
|
13268
13311
|
console.error(chalk7.red("\u2717 No volume initialized in this directory"));
|
|
13269
13312
|
console.error(chalk7.gray(" Run: vm0 volume init"));
|
|
@@ -13272,14 +13315,14 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
13272
13315
|
console.log(chalk7.cyan(`Pulling volume: ${config2.name}`));
|
|
13273
13316
|
console.log(chalk7.gray("Downloading..."));
|
|
13274
13317
|
const response = await apiClient.get(
|
|
13275
|
-
`/api/
|
|
13318
|
+
`/api/storages?name=${encodeURIComponent(config2.name)}`
|
|
13276
13319
|
);
|
|
13277
13320
|
if (!response.ok) {
|
|
13278
13321
|
if (response.status === 404) {
|
|
13279
13322
|
console.error(chalk7.red(`\u2717 Volume "${config2.name}" not found`));
|
|
13280
13323
|
console.error(
|
|
13281
13324
|
chalk7.gray(
|
|
13282
|
-
" Make sure the volume name is correct in .vm0/
|
|
13325
|
+
" Make sure the volume name is correct in .vm0/storage.yaml"
|
|
13283
13326
|
)
|
|
13284
13327
|
);
|
|
13285
13328
|
console.error(
|
|
@@ -13321,15 +13364,267 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
13321
13364
|
// src/commands/volume/index.ts
|
|
13322
13365
|
var volumeCommand = new Command6().name("volume").description("Manage cloud volumes").addCommand(initCommand).addCommand(pushCommand).addCommand(pullCommand);
|
|
13323
13366
|
|
|
13367
|
+
// src/commands/artifact/index.ts
|
|
13368
|
+
import { Command as Command10 } from "commander";
|
|
13369
|
+
|
|
13370
|
+
// src/commands/artifact/init.ts
|
|
13371
|
+
import { Command as Command7 } from "commander";
|
|
13372
|
+
import chalk8 from "chalk";
|
|
13373
|
+
import path5 from "path";
|
|
13374
|
+
var initCommand2 = new Command7().name("init").description("Initialize an artifact in the current directory").action(async () => {
|
|
13375
|
+
try {
|
|
13376
|
+
const cwd = process.cwd();
|
|
13377
|
+
const dirName = path5.basename(cwd);
|
|
13378
|
+
const existingConfig = await readStorageConfig(cwd);
|
|
13379
|
+
if (existingConfig) {
|
|
13380
|
+
if (existingConfig.type === "artifact") {
|
|
13381
|
+
console.log(
|
|
13382
|
+
chalk8.yellow(
|
|
13383
|
+
`Artifact already initialized: ${existingConfig.name}`
|
|
13384
|
+
)
|
|
13385
|
+
);
|
|
13386
|
+
} else {
|
|
13387
|
+
console.log(
|
|
13388
|
+
chalk8.yellow(
|
|
13389
|
+
`Directory already initialized as volume: ${existingConfig.name}`
|
|
13390
|
+
)
|
|
13391
|
+
);
|
|
13392
|
+
console.log(
|
|
13393
|
+
chalk8.gray(
|
|
13394
|
+
" To change type, delete .vm0/storage.yaml and reinitialize"
|
|
13395
|
+
)
|
|
13396
|
+
);
|
|
13397
|
+
}
|
|
13398
|
+
console.log(
|
|
13399
|
+
chalk8.gray(`Config file: ${path5.join(cwd, ".vm0", "storage.yaml")}`)
|
|
13400
|
+
);
|
|
13401
|
+
return;
|
|
13402
|
+
}
|
|
13403
|
+
const artifactName = dirName;
|
|
13404
|
+
if (!isValidStorageName(artifactName)) {
|
|
13405
|
+
console.error(chalk8.red(`\u2717 Invalid artifact name: "${dirName}"`));
|
|
13406
|
+
console.error(
|
|
13407
|
+
chalk8.gray(
|
|
13408
|
+
" Artifact names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
13409
|
+
)
|
|
13410
|
+
);
|
|
13411
|
+
console.error(
|
|
13412
|
+
chalk8.gray(" Example: my-project, user-workspace, code-artifact")
|
|
13413
|
+
);
|
|
13414
|
+
process.exit(1);
|
|
13415
|
+
}
|
|
13416
|
+
await writeStorageConfig(artifactName, cwd, "artifact");
|
|
13417
|
+
console.log(chalk8.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
13418
|
+
console.log(
|
|
13419
|
+
chalk8.gray(
|
|
13420
|
+
`\u2713 Config saved to ${path5.join(cwd, ".vm0", "storage.yaml")}`
|
|
13421
|
+
)
|
|
13422
|
+
);
|
|
13423
|
+
} catch (error43) {
|
|
13424
|
+
console.error(chalk8.red("\u2717 Failed to initialize artifact"));
|
|
13425
|
+
if (error43 instanceof Error) {
|
|
13426
|
+
console.error(chalk8.gray(` ${error43.message}`));
|
|
13427
|
+
}
|
|
13428
|
+
process.exit(1);
|
|
13429
|
+
}
|
|
13430
|
+
});
|
|
13431
|
+
|
|
13432
|
+
// src/commands/artifact/push.ts
|
|
13433
|
+
import { Command as Command8 } from "commander";
|
|
13434
|
+
import chalk9 from "chalk";
|
|
13435
|
+
import path6 from "path";
|
|
13436
|
+
import * as fs3 from "fs";
|
|
13437
|
+
import AdmZip3 from "adm-zip";
|
|
13438
|
+
async function getAllFiles2(dirPath, baseDir = dirPath) {
|
|
13439
|
+
const files = [];
|
|
13440
|
+
const entries = await fs3.promises.readdir(dirPath, { withFileTypes: true });
|
|
13441
|
+
for (const entry of entries) {
|
|
13442
|
+
const fullPath = path6.join(dirPath, entry.name);
|
|
13443
|
+
const relativePath = path6.relative(baseDir, fullPath);
|
|
13444
|
+
if (relativePath.startsWith(".vm0")) {
|
|
13445
|
+
continue;
|
|
13446
|
+
}
|
|
13447
|
+
if (entry.isDirectory()) {
|
|
13448
|
+
const subFiles = await getAllFiles2(fullPath, baseDir);
|
|
13449
|
+
files.push(...subFiles);
|
|
13450
|
+
} else {
|
|
13451
|
+
files.push(fullPath);
|
|
13452
|
+
}
|
|
13453
|
+
}
|
|
13454
|
+
return files;
|
|
13455
|
+
}
|
|
13456
|
+
function formatBytes3(bytes) {
|
|
13457
|
+
if (bytes === 0) return "0 B";
|
|
13458
|
+
const k = 1024;
|
|
13459
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
13460
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
13461
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
13462
|
+
}
|
|
13463
|
+
var pushCommand2 = new Command8().name("push").description("Push local files to cloud artifact").action(async () => {
|
|
13464
|
+
try {
|
|
13465
|
+
const cwd = process.cwd();
|
|
13466
|
+
const config2 = await readStorageConfig(cwd);
|
|
13467
|
+
if (!config2) {
|
|
13468
|
+
console.error(chalk9.red("\u2717 No artifact initialized in this directory"));
|
|
13469
|
+
console.error(chalk9.gray(" Run: vm0 artifact init"));
|
|
13470
|
+
process.exit(1);
|
|
13471
|
+
}
|
|
13472
|
+
if (config2.type !== "artifact") {
|
|
13473
|
+
console.error(
|
|
13474
|
+
chalk9.red(
|
|
13475
|
+
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
13476
|
+
)
|
|
13477
|
+
);
|
|
13478
|
+
console.error(chalk9.gray(" Use: vm0 volume push"));
|
|
13479
|
+
process.exit(1);
|
|
13480
|
+
}
|
|
13481
|
+
console.log(chalk9.cyan(`Pushing artifact: ${config2.name}`));
|
|
13482
|
+
console.log(chalk9.gray("Collecting files..."));
|
|
13483
|
+
const files = await getAllFiles2(cwd);
|
|
13484
|
+
if (files.length === 0) {
|
|
13485
|
+
console.log(chalk9.yellow("No files to upload"));
|
|
13486
|
+
return;
|
|
13487
|
+
}
|
|
13488
|
+
let totalSize = 0;
|
|
13489
|
+
for (const file2 of files) {
|
|
13490
|
+
const stats = await fs3.promises.stat(file2);
|
|
13491
|
+
totalSize += stats.size;
|
|
13492
|
+
}
|
|
13493
|
+
console.log(
|
|
13494
|
+
chalk9.gray(`Found ${files.length} files (${formatBytes3(totalSize)})`)
|
|
13495
|
+
);
|
|
13496
|
+
console.log(chalk9.gray("Compressing files..."));
|
|
13497
|
+
const zip = new AdmZip3();
|
|
13498
|
+
for (const file2 of files) {
|
|
13499
|
+
const relativePath = path6.relative(cwd, file2);
|
|
13500
|
+
zip.addLocalFile(file2, path6.dirname(relativePath));
|
|
13501
|
+
}
|
|
13502
|
+
const zipBuffer = zip.toBuffer();
|
|
13503
|
+
console.log(
|
|
13504
|
+
chalk9.green(`\u2713 Compressed to ${formatBytes3(zipBuffer.length)}`)
|
|
13505
|
+
);
|
|
13506
|
+
console.log(chalk9.gray("Uploading..."));
|
|
13507
|
+
const formData = new FormData();
|
|
13508
|
+
formData.append("name", config2.name);
|
|
13509
|
+
formData.append("type", "artifact");
|
|
13510
|
+
formData.append(
|
|
13511
|
+
"file",
|
|
13512
|
+
new Blob([zipBuffer], { type: "application/zip" }),
|
|
13513
|
+
"artifact.zip"
|
|
13514
|
+
);
|
|
13515
|
+
const response = await apiClient.post("/api/storages", {
|
|
13516
|
+
body: formData
|
|
13517
|
+
});
|
|
13518
|
+
if (!response.ok) {
|
|
13519
|
+
const error43 = await response.json();
|
|
13520
|
+
throw new Error(error43.error || "Upload failed");
|
|
13521
|
+
}
|
|
13522
|
+
const result = await response.json();
|
|
13523
|
+
console.log(chalk9.green("\u2713 Upload complete"));
|
|
13524
|
+
console.log(chalk9.gray(` Version: ${result.versionId}`));
|
|
13525
|
+
console.log(chalk9.gray(` Files: ${result.fileCount.toLocaleString()}`));
|
|
13526
|
+
console.log(chalk9.gray(` Size: ${formatBytes3(result.size)}`));
|
|
13527
|
+
} catch (error43) {
|
|
13528
|
+
console.error(chalk9.red("\u2717 Push failed"));
|
|
13529
|
+
if (error43 instanceof Error) {
|
|
13530
|
+
console.error(chalk9.gray(` ${error43.message}`));
|
|
13531
|
+
}
|
|
13532
|
+
process.exit(1);
|
|
13533
|
+
}
|
|
13534
|
+
});
|
|
13535
|
+
|
|
13536
|
+
// src/commands/artifact/pull.ts
|
|
13537
|
+
import { Command as Command9 } from "commander";
|
|
13538
|
+
import chalk10 from "chalk";
|
|
13539
|
+
import path7 from "path";
|
|
13540
|
+
import * as fs4 from "fs";
|
|
13541
|
+
import AdmZip4 from "adm-zip";
|
|
13542
|
+
function formatBytes4(bytes) {
|
|
13543
|
+
if (bytes === 0) return "0 B";
|
|
13544
|
+
const k = 1024;
|
|
13545
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
13546
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
13547
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
13548
|
+
}
|
|
13549
|
+
var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact to local directory").action(async () => {
|
|
13550
|
+
try {
|
|
13551
|
+
const cwd = process.cwd();
|
|
13552
|
+
const config2 = await readStorageConfig(cwd);
|
|
13553
|
+
if (!config2) {
|
|
13554
|
+
console.error(chalk10.red("\u2717 No artifact initialized in this directory"));
|
|
13555
|
+
console.error(chalk10.gray(" Run: vm0 artifact init"));
|
|
13556
|
+
process.exit(1);
|
|
13557
|
+
}
|
|
13558
|
+
if (config2.type !== "artifact") {
|
|
13559
|
+
console.error(
|
|
13560
|
+
chalk10.red(
|
|
13561
|
+
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
13562
|
+
)
|
|
13563
|
+
);
|
|
13564
|
+
console.error(chalk10.gray(" Use: vm0 volume pull"));
|
|
13565
|
+
process.exit(1);
|
|
13566
|
+
}
|
|
13567
|
+
console.log(chalk10.cyan(`Pulling artifact: ${config2.name}`));
|
|
13568
|
+
console.log(chalk10.gray("Downloading..."));
|
|
13569
|
+
const response = await apiClient.get(
|
|
13570
|
+
`/api/storages?name=${encodeURIComponent(config2.name)}`
|
|
13571
|
+
);
|
|
13572
|
+
if (!response.ok) {
|
|
13573
|
+
if (response.status === 404) {
|
|
13574
|
+
console.error(chalk10.red(`\u2717 Artifact "${config2.name}" not found`));
|
|
13575
|
+
console.error(
|
|
13576
|
+
chalk10.gray(
|
|
13577
|
+
" Make sure the artifact name is correct in .vm0/storage.yaml"
|
|
13578
|
+
)
|
|
13579
|
+
);
|
|
13580
|
+
console.error(
|
|
13581
|
+
chalk10.gray(" Or push the artifact first with: vm0 artifact push")
|
|
13582
|
+
);
|
|
13583
|
+
} else {
|
|
13584
|
+
const error43 = await response.json();
|
|
13585
|
+
throw new Error(error43.error || "Download failed");
|
|
13586
|
+
}
|
|
13587
|
+
process.exit(1);
|
|
13588
|
+
}
|
|
13589
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
13590
|
+
const zipBuffer = Buffer.from(arrayBuffer);
|
|
13591
|
+
console.log(chalk10.green(`\u2713 Downloaded ${formatBytes4(zipBuffer.length)}`));
|
|
13592
|
+
console.log(chalk10.gray("Extracting files..."));
|
|
13593
|
+
const zip = new AdmZip4(zipBuffer);
|
|
13594
|
+
const zipEntries = zip.getEntries();
|
|
13595
|
+
let extractedCount = 0;
|
|
13596
|
+
for (const entry of zipEntries) {
|
|
13597
|
+
if (!entry.isDirectory) {
|
|
13598
|
+
const targetPath = path7.join(cwd, entry.entryName);
|
|
13599
|
+
const dir = path7.dirname(targetPath);
|
|
13600
|
+
await fs4.promises.mkdir(dir, { recursive: true });
|
|
13601
|
+
const data = entry.getData();
|
|
13602
|
+
await fs4.promises.writeFile(targetPath, data);
|
|
13603
|
+
extractedCount++;
|
|
13604
|
+
}
|
|
13605
|
+
}
|
|
13606
|
+
console.log(chalk10.green(`\u2713 Extracted ${extractedCount} files`));
|
|
13607
|
+
} catch (error43) {
|
|
13608
|
+
console.error(chalk10.red("\u2717 Pull failed"));
|
|
13609
|
+
if (error43 instanceof Error) {
|
|
13610
|
+
console.error(chalk10.gray(` ${error43.message}`));
|
|
13611
|
+
}
|
|
13612
|
+
process.exit(1);
|
|
13613
|
+
}
|
|
13614
|
+
});
|
|
13615
|
+
|
|
13616
|
+
// src/commands/artifact/index.ts
|
|
13617
|
+
var artifactCommand = new Command10().name("artifact").description("Manage cloud artifacts (work products)").addCommand(initCommand2).addCommand(pushCommand2).addCommand(pullCommand2);
|
|
13618
|
+
|
|
13324
13619
|
// src/index.ts
|
|
13325
|
-
var program = new
|
|
13620
|
+
var program = new Command11();
|
|
13326
13621
|
program.name("vm0").description("VM0 CLI - A modern build tool").version("0.1.0");
|
|
13327
13622
|
program.command("hello").description("Say hello from the App").action(() => {
|
|
13328
|
-
console.log(
|
|
13329
|
-
console.log(
|
|
13623
|
+
console.log(chalk11.blue("Welcome to the VM0 CLI!"));
|
|
13624
|
+
console.log(chalk11.green(`Core says: ${FOO}`));
|
|
13330
13625
|
});
|
|
13331
13626
|
program.command("info").description("Display environment information").action(async () => {
|
|
13332
|
-
console.log(
|
|
13627
|
+
console.log(chalk11.cyan("System Information:"));
|
|
13333
13628
|
console.log(`Node Version: ${process.version}`);
|
|
13334
13629
|
console.log(`Platform: ${process.platform}`);
|
|
13335
13630
|
console.log(`Architecture: ${process.arch}`);
|
|
@@ -13349,6 +13644,7 @@ authCommand.command("status").description("Show current authentication status").
|
|
|
13349
13644
|
program.addCommand(buildCommand);
|
|
13350
13645
|
program.addCommand(runCommand);
|
|
13351
13646
|
program.addCommand(volumeCommand);
|
|
13647
|
+
program.addCommand(artifactCommand);
|
|
13352
13648
|
if (process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("vm0")) {
|
|
13353
13649
|
program.parse();
|
|
13354
13650
|
}
|