@vm0/cli 1.3.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +329 -64
- 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
|
|
@@ -12936,31 +12936,23 @@ async function pollEvents(runId) {
|
|
|
12936
12936
|
);
|
|
12937
12937
|
throw new Error("Agent execution timed out");
|
|
12938
12938
|
}
|
|
12939
|
-
|
|
12940
|
-
|
|
12941
|
-
|
|
12942
|
-
|
|
12943
|
-
|
|
12944
|
-
|
|
12945
|
-
|
|
12946
|
-
|
|
12947
|
-
|
|
12948
|
-
|
|
12949
|
-
|
|
12950
|
-
complete = true;
|
|
12951
|
-
}
|
|
12939
|
+
const response = await apiClient.getEvents(runId, {
|
|
12940
|
+
since: nextSequence
|
|
12941
|
+
});
|
|
12942
|
+
for (const event of response.events) {
|
|
12943
|
+
const parsed = ClaudeEventParser.parse(
|
|
12944
|
+
event.eventData
|
|
12945
|
+
);
|
|
12946
|
+
if (parsed) {
|
|
12947
|
+
EventRenderer.render(parsed);
|
|
12948
|
+
if (parsed.type === "vm0_result" || parsed.type === "vm0_error") {
|
|
12949
|
+
complete = true;
|
|
12952
12950
|
}
|
|
12953
12951
|
}
|
|
12954
|
-
|
|
12955
|
-
|
|
12956
|
-
|
|
12957
|
-
|
|
12958
|
-
} catch (error43) {
|
|
12959
|
-
console.error(
|
|
12960
|
-
chalk4.red("\u2717 Failed to poll events:"),
|
|
12961
|
-
error43 instanceof Error ? error43.message : "Unknown error"
|
|
12962
|
-
);
|
|
12963
|
-
throw error43;
|
|
12952
|
+
}
|
|
12953
|
+
nextSequence = response.nextSequence;
|
|
12954
|
+
if (response.events.length === 0 && !complete) {
|
|
12955
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
12964
12956
|
}
|
|
12965
12957
|
}
|
|
12966
12958
|
}
|
|
@@ -12972,6 +12964,9 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
12972
12964
|
"Environment variables (repeatable)",
|
|
12973
12965
|
collectEnvVars,
|
|
12974
12966
|
{}
|
|
12967
|
+
).option(
|
|
12968
|
+
"-a, --artifact <key>",
|
|
12969
|
+
"Artifact key to mount (for VM0 driver artifacts)"
|
|
12975
12970
|
).action(
|
|
12976
12971
|
async (identifier, prompt, options) => {
|
|
12977
12972
|
try {
|
|
@@ -13004,13 +12999,17 @@ var runCmd = new Command2().name("run").description("Execute an agent").argument
|
|
|
13004
12999
|
chalk4.gray(` Variables: ${JSON.stringify(options.env)}`)
|
|
13005
13000
|
);
|
|
13006
13001
|
}
|
|
13002
|
+
if (options.artifact) {
|
|
13003
|
+
console.log(chalk4.gray(` Artifact: ${options.artifact}`));
|
|
13004
|
+
}
|
|
13007
13005
|
console.log();
|
|
13008
13006
|
console.log(chalk4.blue("Executing in sandbox..."));
|
|
13009
13007
|
console.log();
|
|
13010
13008
|
const response = await apiClient.createRun({
|
|
13011
13009
|
agentConfigId: configId,
|
|
13012
13010
|
prompt,
|
|
13013
|
-
dynamicVars: Object.keys(options.env).length > 0 ? options.env : void 0
|
|
13011
|
+
dynamicVars: Object.keys(options.env).length > 0 ? options.env : void 0,
|
|
13012
|
+
artifactKey: options.artifact
|
|
13014
13013
|
});
|
|
13015
13014
|
await pollEvents(response.runId);
|
|
13016
13015
|
} catch (error43) {
|
|
@@ -13081,37 +13080,48 @@ import { Command as Command3 } from "commander";
|
|
|
13081
13080
|
import chalk5 from "chalk";
|
|
13082
13081
|
import path2 from "path";
|
|
13083
13082
|
|
|
13084
|
-
// src/lib/
|
|
13083
|
+
// src/lib/storage-utils.ts
|
|
13085
13084
|
import { readFile as readFile3, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
13086
13085
|
import { existsSync as existsSync3 } from "fs";
|
|
13087
13086
|
import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
|
|
13088
13087
|
import path from "path";
|
|
13089
13088
|
var CONFIG_DIR2 = ".vm0";
|
|
13090
|
-
var CONFIG_FILE2 = "
|
|
13091
|
-
function
|
|
13089
|
+
var CONFIG_FILE2 = "storage.yaml";
|
|
13090
|
+
function isValidStorageName(name) {
|
|
13092
13091
|
if (name.length < 3 || name.length > 64) {
|
|
13093
13092
|
return false;
|
|
13094
13093
|
}
|
|
13095
13094
|
const pattern = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/;
|
|
13096
13095
|
return pattern.test(name) && !name.includes("--");
|
|
13097
13096
|
}
|
|
13098
|
-
async function
|
|
13097
|
+
async function readStorageConfig(basePath = process.cwd()) {
|
|
13099
13098
|
const configPath = path.join(basePath, CONFIG_DIR2, CONFIG_FILE2);
|
|
13100
|
-
|
|
13099
|
+
const legacyConfigPath = path.join(basePath, CONFIG_DIR2, "volume.yaml");
|
|
13100
|
+
let actualPath = null;
|
|
13101
|
+
if (existsSync3(configPath)) {
|
|
13102
|
+
actualPath = configPath;
|
|
13103
|
+
} else if (existsSync3(legacyConfigPath)) {
|
|
13104
|
+
actualPath = legacyConfigPath;
|
|
13105
|
+
}
|
|
13106
|
+
if (!actualPath) {
|
|
13101
13107
|
return null;
|
|
13102
13108
|
}
|
|
13103
|
-
const content = await readFile3(
|
|
13109
|
+
const content = await readFile3(actualPath, "utf8");
|
|
13104
13110
|
const config2 = parseYaml2(content);
|
|
13111
|
+
if (!config2.type) {
|
|
13112
|
+
config2.type = "volume";
|
|
13113
|
+
}
|
|
13105
13114
|
return config2;
|
|
13106
13115
|
}
|
|
13107
|
-
async function
|
|
13116
|
+
async function writeStorageConfig(storageName, basePath = process.cwd(), type = "volume") {
|
|
13108
13117
|
const configDir = path.join(basePath, CONFIG_DIR2);
|
|
13109
13118
|
const configPath = path.join(configDir, CONFIG_FILE2);
|
|
13110
13119
|
if (!existsSync3(configDir)) {
|
|
13111
13120
|
await mkdir2(configDir, { recursive: true });
|
|
13112
13121
|
}
|
|
13113
13122
|
const config2 = {
|
|
13114
|
-
name:
|
|
13123
|
+
name: storageName,
|
|
13124
|
+
type
|
|
13115
13125
|
};
|
|
13116
13126
|
const yamlContent = stringifyYaml(config2);
|
|
13117
13127
|
await writeFile2(configPath, yamlContent, "utf8");
|
|
@@ -13122,18 +13132,18 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
13122
13132
|
try {
|
|
13123
13133
|
const cwd = process.cwd();
|
|
13124
13134
|
const dirName = path2.basename(cwd);
|
|
13125
|
-
const existingConfig = await
|
|
13135
|
+
const existingConfig = await readStorageConfig(cwd);
|
|
13126
13136
|
if (existingConfig) {
|
|
13127
13137
|
console.log(
|
|
13128
13138
|
chalk5.yellow(`Volume already initialized: ${existingConfig.name}`)
|
|
13129
13139
|
);
|
|
13130
13140
|
console.log(
|
|
13131
|
-
chalk5.gray(`Config file: ${path2.join(cwd, ".vm0", "
|
|
13141
|
+
chalk5.gray(`Config file: ${path2.join(cwd, ".vm0", "storage.yaml")}`)
|
|
13132
13142
|
);
|
|
13133
13143
|
return;
|
|
13134
13144
|
}
|
|
13135
13145
|
const volumeName = dirName;
|
|
13136
|
-
if (!
|
|
13146
|
+
if (!isValidStorageName(volumeName)) {
|
|
13137
13147
|
console.error(chalk5.red(`\u2717 Invalid volume name: "${dirName}"`));
|
|
13138
13148
|
console.error(
|
|
13139
13149
|
chalk5.gray(
|
|
@@ -13145,11 +13155,11 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
13145
13155
|
);
|
|
13146
13156
|
process.exit(1);
|
|
13147
13157
|
}
|
|
13148
|
-
await
|
|
13158
|
+
await writeStorageConfig(volumeName, cwd);
|
|
13149
13159
|
console.log(chalk5.green(`\u2713 Initialized volume: ${volumeName}`));
|
|
13150
13160
|
console.log(
|
|
13151
13161
|
chalk5.gray(
|
|
13152
|
-
`\u2713 Config saved to ${path2.join(cwd, ".vm0", "
|
|
13162
|
+
`\u2713 Config saved to ${path2.join(cwd, ".vm0", "storage.yaml")}`
|
|
13153
13163
|
)
|
|
13154
13164
|
);
|
|
13155
13165
|
} catch (error43) {
|
|
@@ -13195,7 +13205,7 @@ function formatBytes(bytes) {
|
|
|
13195
13205
|
var pushCommand = new Command4().name("push").description("Push local files to cloud volume").action(async () => {
|
|
13196
13206
|
try {
|
|
13197
13207
|
const cwd = process.cwd();
|
|
13198
|
-
const config2 = await
|
|
13208
|
+
const config2 = await readStorageConfig(cwd);
|
|
13199
13209
|
if (!config2) {
|
|
13200
13210
|
console.error(chalk6.red("\u2717 No volume initialized in this directory"));
|
|
13201
13211
|
console.error(chalk6.gray(" Run: vm0 volume init"));
|
|
@@ -13228,13 +13238,14 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
13228
13238
|
);
|
|
13229
13239
|
console.log(chalk6.gray("Uploading..."));
|
|
13230
13240
|
const formData = new FormData();
|
|
13231
|
-
formData.append("
|
|
13241
|
+
formData.append("name", config2.name);
|
|
13242
|
+
formData.append("type", "volume");
|
|
13232
13243
|
formData.append(
|
|
13233
13244
|
"file",
|
|
13234
13245
|
new Blob([zipBuffer], { type: "application/zip" }),
|
|
13235
13246
|
"volume.zip"
|
|
13236
13247
|
);
|
|
13237
|
-
const response = await apiClient.post("/api/
|
|
13248
|
+
const response = await apiClient.post("/api/storages", {
|
|
13238
13249
|
body: formData
|
|
13239
13250
|
});
|
|
13240
13251
|
if (!response.ok) {
|
|
@@ -13243,6 +13254,7 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
13243
13254
|
}
|
|
13244
13255
|
const result = await response.json();
|
|
13245
13256
|
console.log(chalk6.green("\u2713 Upload complete"));
|
|
13257
|
+
console.log(chalk6.gray(` Version: ${result.versionId}`));
|
|
13246
13258
|
console.log(chalk6.gray(` Files: ${result.fileCount.toLocaleString()}`));
|
|
13247
13259
|
console.log(chalk6.gray(` Size: ${formatBytes(result.size)}`));
|
|
13248
13260
|
} catch (error43) {
|
|
@@ -13270,7 +13282,7 @@ function formatBytes2(bytes) {
|
|
|
13270
13282
|
var pullCommand = new Command5().name("pull").description("Pull cloud files to local directory").action(async () => {
|
|
13271
13283
|
try {
|
|
13272
13284
|
const cwd = process.cwd();
|
|
13273
|
-
const config2 = await
|
|
13285
|
+
const config2 = await readStorageConfig(cwd);
|
|
13274
13286
|
if (!config2) {
|
|
13275
13287
|
console.error(chalk7.red("\u2717 No volume initialized in this directory"));
|
|
13276
13288
|
console.error(chalk7.gray(" Run: vm0 volume init"));
|
|
@@ -13279,14 +13291,14 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
13279
13291
|
console.log(chalk7.cyan(`Pulling volume: ${config2.name}`));
|
|
13280
13292
|
console.log(chalk7.gray("Downloading..."));
|
|
13281
13293
|
const response = await apiClient.get(
|
|
13282
|
-
`/api/
|
|
13294
|
+
`/api/storages?name=${encodeURIComponent(config2.name)}`
|
|
13283
13295
|
);
|
|
13284
13296
|
if (!response.ok) {
|
|
13285
13297
|
if (response.status === 404) {
|
|
13286
13298
|
console.error(chalk7.red(`\u2717 Volume "${config2.name}" not found`));
|
|
13287
13299
|
console.error(
|
|
13288
13300
|
chalk7.gray(
|
|
13289
|
-
" Make sure the volume name is correct in .vm0/
|
|
13301
|
+
" Make sure the volume name is correct in .vm0/storage.yaml"
|
|
13290
13302
|
)
|
|
13291
13303
|
);
|
|
13292
13304
|
console.error(
|
|
@@ -13328,15 +13340,267 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
13328
13340
|
// src/commands/volume/index.ts
|
|
13329
13341
|
var volumeCommand = new Command6().name("volume").description("Manage cloud volumes").addCommand(initCommand).addCommand(pushCommand).addCommand(pullCommand);
|
|
13330
13342
|
|
|
13343
|
+
// src/commands/artifact/index.ts
|
|
13344
|
+
import { Command as Command10 } from "commander";
|
|
13345
|
+
|
|
13346
|
+
// src/commands/artifact/init.ts
|
|
13347
|
+
import { Command as Command7 } from "commander";
|
|
13348
|
+
import chalk8 from "chalk";
|
|
13349
|
+
import path5 from "path";
|
|
13350
|
+
var initCommand2 = new Command7().name("init").description("Initialize an artifact in the current directory").action(async () => {
|
|
13351
|
+
try {
|
|
13352
|
+
const cwd = process.cwd();
|
|
13353
|
+
const dirName = path5.basename(cwd);
|
|
13354
|
+
const existingConfig = await readStorageConfig(cwd);
|
|
13355
|
+
if (existingConfig) {
|
|
13356
|
+
if (existingConfig.type === "artifact") {
|
|
13357
|
+
console.log(
|
|
13358
|
+
chalk8.yellow(
|
|
13359
|
+
`Artifact already initialized: ${existingConfig.name}`
|
|
13360
|
+
)
|
|
13361
|
+
);
|
|
13362
|
+
} else {
|
|
13363
|
+
console.log(
|
|
13364
|
+
chalk8.yellow(
|
|
13365
|
+
`Directory already initialized as volume: ${existingConfig.name}`
|
|
13366
|
+
)
|
|
13367
|
+
);
|
|
13368
|
+
console.log(
|
|
13369
|
+
chalk8.gray(
|
|
13370
|
+
" To change type, delete .vm0/storage.yaml and reinitialize"
|
|
13371
|
+
)
|
|
13372
|
+
);
|
|
13373
|
+
}
|
|
13374
|
+
console.log(
|
|
13375
|
+
chalk8.gray(`Config file: ${path5.join(cwd, ".vm0", "storage.yaml")}`)
|
|
13376
|
+
);
|
|
13377
|
+
return;
|
|
13378
|
+
}
|
|
13379
|
+
const artifactName = dirName;
|
|
13380
|
+
if (!isValidStorageName(artifactName)) {
|
|
13381
|
+
console.error(chalk8.red(`\u2717 Invalid artifact name: "${dirName}"`));
|
|
13382
|
+
console.error(
|
|
13383
|
+
chalk8.gray(
|
|
13384
|
+
" Artifact names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
13385
|
+
)
|
|
13386
|
+
);
|
|
13387
|
+
console.error(
|
|
13388
|
+
chalk8.gray(" Example: my-project, user-workspace, code-artifact")
|
|
13389
|
+
);
|
|
13390
|
+
process.exit(1);
|
|
13391
|
+
}
|
|
13392
|
+
await writeStorageConfig(artifactName, cwd, "artifact");
|
|
13393
|
+
console.log(chalk8.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
13394
|
+
console.log(
|
|
13395
|
+
chalk8.gray(
|
|
13396
|
+
`\u2713 Config saved to ${path5.join(cwd, ".vm0", "storage.yaml")}`
|
|
13397
|
+
)
|
|
13398
|
+
);
|
|
13399
|
+
} catch (error43) {
|
|
13400
|
+
console.error(chalk8.red("\u2717 Failed to initialize artifact"));
|
|
13401
|
+
if (error43 instanceof Error) {
|
|
13402
|
+
console.error(chalk8.gray(` ${error43.message}`));
|
|
13403
|
+
}
|
|
13404
|
+
process.exit(1);
|
|
13405
|
+
}
|
|
13406
|
+
});
|
|
13407
|
+
|
|
13408
|
+
// src/commands/artifact/push.ts
|
|
13409
|
+
import { Command as Command8 } from "commander";
|
|
13410
|
+
import chalk9 from "chalk";
|
|
13411
|
+
import path6 from "path";
|
|
13412
|
+
import * as fs3 from "fs";
|
|
13413
|
+
import AdmZip3 from "adm-zip";
|
|
13414
|
+
async function getAllFiles2(dirPath, baseDir = dirPath) {
|
|
13415
|
+
const files = [];
|
|
13416
|
+
const entries = await fs3.promises.readdir(dirPath, { withFileTypes: true });
|
|
13417
|
+
for (const entry of entries) {
|
|
13418
|
+
const fullPath = path6.join(dirPath, entry.name);
|
|
13419
|
+
const relativePath = path6.relative(baseDir, fullPath);
|
|
13420
|
+
if (relativePath.startsWith(".vm0")) {
|
|
13421
|
+
continue;
|
|
13422
|
+
}
|
|
13423
|
+
if (entry.isDirectory()) {
|
|
13424
|
+
const subFiles = await getAllFiles2(fullPath, baseDir);
|
|
13425
|
+
files.push(...subFiles);
|
|
13426
|
+
} else {
|
|
13427
|
+
files.push(fullPath);
|
|
13428
|
+
}
|
|
13429
|
+
}
|
|
13430
|
+
return files;
|
|
13431
|
+
}
|
|
13432
|
+
function formatBytes3(bytes) {
|
|
13433
|
+
if (bytes === 0) return "0 B";
|
|
13434
|
+
const k = 1024;
|
|
13435
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
13436
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
13437
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
13438
|
+
}
|
|
13439
|
+
var pushCommand2 = new Command8().name("push").description("Push local files to cloud artifact").action(async () => {
|
|
13440
|
+
try {
|
|
13441
|
+
const cwd = process.cwd();
|
|
13442
|
+
const config2 = await readStorageConfig(cwd);
|
|
13443
|
+
if (!config2) {
|
|
13444
|
+
console.error(chalk9.red("\u2717 No artifact initialized in this directory"));
|
|
13445
|
+
console.error(chalk9.gray(" Run: vm0 artifact init"));
|
|
13446
|
+
process.exit(1);
|
|
13447
|
+
}
|
|
13448
|
+
if (config2.type !== "artifact") {
|
|
13449
|
+
console.error(
|
|
13450
|
+
chalk9.red(
|
|
13451
|
+
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
13452
|
+
)
|
|
13453
|
+
);
|
|
13454
|
+
console.error(chalk9.gray(" Use: vm0 volume push"));
|
|
13455
|
+
process.exit(1);
|
|
13456
|
+
}
|
|
13457
|
+
console.log(chalk9.cyan(`Pushing artifact: ${config2.name}`));
|
|
13458
|
+
console.log(chalk9.gray("Collecting files..."));
|
|
13459
|
+
const files = await getAllFiles2(cwd);
|
|
13460
|
+
if (files.length === 0) {
|
|
13461
|
+
console.log(chalk9.yellow("No files to upload"));
|
|
13462
|
+
return;
|
|
13463
|
+
}
|
|
13464
|
+
let totalSize = 0;
|
|
13465
|
+
for (const file2 of files) {
|
|
13466
|
+
const stats = await fs3.promises.stat(file2);
|
|
13467
|
+
totalSize += stats.size;
|
|
13468
|
+
}
|
|
13469
|
+
console.log(
|
|
13470
|
+
chalk9.gray(`Found ${files.length} files (${formatBytes3(totalSize)})`)
|
|
13471
|
+
);
|
|
13472
|
+
console.log(chalk9.gray("Compressing files..."));
|
|
13473
|
+
const zip = new AdmZip3();
|
|
13474
|
+
for (const file2 of files) {
|
|
13475
|
+
const relativePath = path6.relative(cwd, file2);
|
|
13476
|
+
zip.addLocalFile(file2, path6.dirname(relativePath));
|
|
13477
|
+
}
|
|
13478
|
+
const zipBuffer = zip.toBuffer();
|
|
13479
|
+
console.log(
|
|
13480
|
+
chalk9.green(`\u2713 Compressed to ${formatBytes3(zipBuffer.length)}`)
|
|
13481
|
+
);
|
|
13482
|
+
console.log(chalk9.gray("Uploading..."));
|
|
13483
|
+
const formData = new FormData();
|
|
13484
|
+
formData.append("name", config2.name);
|
|
13485
|
+
formData.append("type", "artifact");
|
|
13486
|
+
formData.append(
|
|
13487
|
+
"file",
|
|
13488
|
+
new Blob([zipBuffer], { type: "application/zip" }),
|
|
13489
|
+
"artifact.zip"
|
|
13490
|
+
);
|
|
13491
|
+
const response = await apiClient.post("/api/storages", {
|
|
13492
|
+
body: formData
|
|
13493
|
+
});
|
|
13494
|
+
if (!response.ok) {
|
|
13495
|
+
const error43 = await response.json();
|
|
13496
|
+
throw new Error(error43.error || "Upload failed");
|
|
13497
|
+
}
|
|
13498
|
+
const result = await response.json();
|
|
13499
|
+
console.log(chalk9.green("\u2713 Upload complete"));
|
|
13500
|
+
console.log(chalk9.gray(` Version: ${result.versionId}`));
|
|
13501
|
+
console.log(chalk9.gray(` Files: ${result.fileCount.toLocaleString()}`));
|
|
13502
|
+
console.log(chalk9.gray(` Size: ${formatBytes3(result.size)}`));
|
|
13503
|
+
} catch (error43) {
|
|
13504
|
+
console.error(chalk9.red("\u2717 Push failed"));
|
|
13505
|
+
if (error43 instanceof Error) {
|
|
13506
|
+
console.error(chalk9.gray(` ${error43.message}`));
|
|
13507
|
+
}
|
|
13508
|
+
process.exit(1);
|
|
13509
|
+
}
|
|
13510
|
+
});
|
|
13511
|
+
|
|
13512
|
+
// src/commands/artifact/pull.ts
|
|
13513
|
+
import { Command as Command9 } from "commander";
|
|
13514
|
+
import chalk10 from "chalk";
|
|
13515
|
+
import path7 from "path";
|
|
13516
|
+
import * as fs4 from "fs";
|
|
13517
|
+
import AdmZip4 from "adm-zip";
|
|
13518
|
+
function formatBytes4(bytes) {
|
|
13519
|
+
if (bytes === 0) return "0 B";
|
|
13520
|
+
const k = 1024;
|
|
13521
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
13522
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
13523
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
13524
|
+
}
|
|
13525
|
+
var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact to local directory").action(async () => {
|
|
13526
|
+
try {
|
|
13527
|
+
const cwd = process.cwd();
|
|
13528
|
+
const config2 = await readStorageConfig(cwd);
|
|
13529
|
+
if (!config2) {
|
|
13530
|
+
console.error(chalk10.red("\u2717 No artifact initialized in this directory"));
|
|
13531
|
+
console.error(chalk10.gray(" Run: vm0 artifact init"));
|
|
13532
|
+
process.exit(1);
|
|
13533
|
+
}
|
|
13534
|
+
if (config2.type !== "artifact") {
|
|
13535
|
+
console.error(
|
|
13536
|
+
chalk10.red(
|
|
13537
|
+
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
13538
|
+
)
|
|
13539
|
+
);
|
|
13540
|
+
console.error(chalk10.gray(" Use: vm0 volume pull"));
|
|
13541
|
+
process.exit(1);
|
|
13542
|
+
}
|
|
13543
|
+
console.log(chalk10.cyan(`Pulling artifact: ${config2.name}`));
|
|
13544
|
+
console.log(chalk10.gray("Downloading..."));
|
|
13545
|
+
const response = await apiClient.get(
|
|
13546
|
+
`/api/storages?name=${encodeURIComponent(config2.name)}`
|
|
13547
|
+
);
|
|
13548
|
+
if (!response.ok) {
|
|
13549
|
+
if (response.status === 404) {
|
|
13550
|
+
console.error(chalk10.red(`\u2717 Artifact "${config2.name}" not found`));
|
|
13551
|
+
console.error(
|
|
13552
|
+
chalk10.gray(
|
|
13553
|
+
" Make sure the artifact name is correct in .vm0/storage.yaml"
|
|
13554
|
+
)
|
|
13555
|
+
);
|
|
13556
|
+
console.error(
|
|
13557
|
+
chalk10.gray(" Or push the artifact first with: vm0 artifact push")
|
|
13558
|
+
);
|
|
13559
|
+
} else {
|
|
13560
|
+
const error43 = await response.json();
|
|
13561
|
+
throw new Error(error43.error || "Download failed");
|
|
13562
|
+
}
|
|
13563
|
+
process.exit(1);
|
|
13564
|
+
}
|
|
13565
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
13566
|
+
const zipBuffer = Buffer.from(arrayBuffer);
|
|
13567
|
+
console.log(chalk10.green(`\u2713 Downloaded ${formatBytes4(zipBuffer.length)}`));
|
|
13568
|
+
console.log(chalk10.gray("Extracting files..."));
|
|
13569
|
+
const zip = new AdmZip4(zipBuffer);
|
|
13570
|
+
const zipEntries = zip.getEntries();
|
|
13571
|
+
let extractedCount = 0;
|
|
13572
|
+
for (const entry of zipEntries) {
|
|
13573
|
+
if (!entry.isDirectory) {
|
|
13574
|
+
const targetPath = path7.join(cwd, entry.entryName);
|
|
13575
|
+
const dir = path7.dirname(targetPath);
|
|
13576
|
+
await fs4.promises.mkdir(dir, { recursive: true });
|
|
13577
|
+
const data = entry.getData();
|
|
13578
|
+
await fs4.promises.writeFile(targetPath, data);
|
|
13579
|
+
extractedCount++;
|
|
13580
|
+
}
|
|
13581
|
+
}
|
|
13582
|
+
console.log(chalk10.green(`\u2713 Extracted ${extractedCount} files`));
|
|
13583
|
+
} catch (error43) {
|
|
13584
|
+
console.error(chalk10.red("\u2717 Pull failed"));
|
|
13585
|
+
if (error43 instanceof Error) {
|
|
13586
|
+
console.error(chalk10.gray(` ${error43.message}`));
|
|
13587
|
+
}
|
|
13588
|
+
process.exit(1);
|
|
13589
|
+
}
|
|
13590
|
+
});
|
|
13591
|
+
|
|
13592
|
+
// src/commands/artifact/index.ts
|
|
13593
|
+
var artifactCommand = new Command10().name("artifact").description("Manage cloud artifacts (work products)").addCommand(initCommand2).addCommand(pushCommand2).addCommand(pullCommand2);
|
|
13594
|
+
|
|
13331
13595
|
// src/index.ts
|
|
13332
|
-
var program = new
|
|
13596
|
+
var program = new Command11();
|
|
13333
13597
|
program.name("vm0").description("VM0 CLI - A modern build tool").version("0.1.0");
|
|
13334
13598
|
program.command("hello").description("Say hello from the App").action(() => {
|
|
13335
|
-
console.log(
|
|
13336
|
-
console.log(
|
|
13599
|
+
console.log(chalk11.blue("Welcome to the VM0 CLI!"));
|
|
13600
|
+
console.log(chalk11.green(`Core says: ${FOO}`));
|
|
13337
13601
|
});
|
|
13338
13602
|
program.command("info").description("Display environment information").action(async () => {
|
|
13339
|
-
console.log(
|
|
13603
|
+
console.log(chalk11.cyan("System Information:"));
|
|
13340
13604
|
console.log(`Node Version: ${process.version}`);
|
|
13341
13605
|
console.log(`Platform: ${process.platform}`);
|
|
13342
13606
|
console.log(`Architecture: ${process.arch}`);
|
|
@@ -13356,6 +13620,7 @@ authCommand.command("status").description("Show current authentication status").
|
|
|
13356
13620
|
program.addCommand(buildCommand);
|
|
13357
13621
|
program.addCommand(runCommand);
|
|
13358
13622
|
program.addCommand(volumeCommand);
|
|
13623
|
+
program.addCommand(artifactCommand);
|
|
13359
13624
|
if (process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("vm0")) {
|
|
13360
13625
|
program.parse();
|
|
13361
13626
|
}
|