@vm0/cli 1.2.0 → 1.3.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 +316 -17
- package/package.json +2 -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, path5) {
|
|
740
|
+
if (!path5)
|
|
741
741
|
return obj;
|
|
742
|
-
return
|
|
742
|
+
return path5.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 promises3 = keys.map((key) => promisesObj[key]);
|
|
747
|
+
return Promise.all(promises3).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(path5, 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(path5);
|
|
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, path5 = []) => {
|
|
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 = [...path5, ...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 path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1316
|
+
for (const seg of path5) {
|
|
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 Command7 } from "commander";
|
|
12151
|
+
import chalk8 from "chalk";
|
|
12152
12152
|
|
|
12153
12153
|
// src/lib/auth.ts
|
|
12154
12154
|
import chalk from "chalk";
|
|
@@ -12413,6 +12413,49 @@ var ApiClient = class {
|
|
|
12413
12413
|
}
|
|
12414
12414
|
return await response.json();
|
|
12415
12415
|
}
|
|
12416
|
+
/**
|
|
12417
|
+
* Generic GET request
|
|
12418
|
+
*/
|
|
12419
|
+
async get(path5) {
|
|
12420
|
+
const baseUrl = await this.getBaseUrl();
|
|
12421
|
+
const token = await getToken();
|
|
12422
|
+
if (!token) {
|
|
12423
|
+
throw new Error("Not authenticated. Run: vm0 auth login");
|
|
12424
|
+
}
|
|
12425
|
+
const headers = {
|
|
12426
|
+
Authorization: `Bearer ${token}`
|
|
12427
|
+
};
|
|
12428
|
+
const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
12429
|
+
if (bypassSecret) {
|
|
12430
|
+
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
12431
|
+
}
|
|
12432
|
+
return fetch(`${baseUrl}${path5}`, {
|
|
12433
|
+
method: "GET",
|
|
12434
|
+
headers
|
|
12435
|
+
});
|
|
12436
|
+
}
|
|
12437
|
+
/**
|
|
12438
|
+
* Generic POST request
|
|
12439
|
+
*/
|
|
12440
|
+
async post(path5, options) {
|
|
12441
|
+
const baseUrl = await this.getBaseUrl();
|
|
12442
|
+
const token = await getToken();
|
|
12443
|
+
if (!token) {
|
|
12444
|
+
throw new Error("Not authenticated. Run: vm0 auth login");
|
|
12445
|
+
}
|
|
12446
|
+
const headers = {
|
|
12447
|
+
Authorization: `Bearer ${token}`
|
|
12448
|
+
};
|
|
12449
|
+
const bypassSecret = process.env.VERCEL_AUTOMATION_BYPASS_SECRET;
|
|
12450
|
+
if (bypassSecret) {
|
|
12451
|
+
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
12452
|
+
}
|
|
12453
|
+
return fetch(`${baseUrl}${path5}`, {
|
|
12454
|
+
method: "POST",
|
|
12455
|
+
headers,
|
|
12456
|
+
body: options?.body
|
|
12457
|
+
});
|
|
12458
|
+
}
|
|
12416
12459
|
};
|
|
12417
12460
|
var apiClient = new ApiClient();
|
|
12418
12461
|
|
|
@@ -13027,15 +13070,270 @@ runCmd.command("resume").description("Resume an agent run from a checkpoint").ar
|
|
|
13027
13070
|
});
|
|
13028
13071
|
var runCommand = runCmd;
|
|
13029
13072
|
|
|
13073
|
+
// src/commands/volume/index.ts
|
|
13074
|
+
import { Command as Command6 } from "commander";
|
|
13075
|
+
|
|
13076
|
+
// src/commands/volume/init.ts
|
|
13077
|
+
import { Command as Command3 } from "commander";
|
|
13078
|
+
import chalk5 from "chalk";
|
|
13079
|
+
import path2 from "path";
|
|
13080
|
+
|
|
13081
|
+
// src/lib/volume-utils.ts
|
|
13082
|
+
import { readFile as readFile3, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
13083
|
+
import { existsSync as existsSync3 } from "fs";
|
|
13084
|
+
import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
|
|
13085
|
+
import path from "path";
|
|
13086
|
+
var CONFIG_DIR2 = ".vm0";
|
|
13087
|
+
var CONFIG_FILE2 = "volume.yaml";
|
|
13088
|
+
function isValidVolumeName(name) {
|
|
13089
|
+
if (name.length < 3 || name.length > 64) {
|
|
13090
|
+
return false;
|
|
13091
|
+
}
|
|
13092
|
+
const pattern = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/;
|
|
13093
|
+
return pattern.test(name) && !name.includes("--");
|
|
13094
|
+
}
|
|
13095
|
+
async function readVolumeConfig(basePath = process.cwd()) {
|
|
13096
|
+
const configPath = path.join(basePath, CONFIG_DIR2, CONFIG_FILE2);
|
|
13097
|
+
if (!existsSync3(configPath)) {
|
|
13098
|
+
return null;
|
|
13099
|
+
}
|
|
13100
|
+
const content = await readFile3(configPath, "utf8");
|
|
13101
|
+
const config2 = parseYaml2(content);
|
|
13102
|
+
return config2;
|
|
13103
|
+
}
|
|
13104
|
+
async function writeVolumeConfig(volumeName, basePath = process.cwd()) {
|
|
13105
|
+
const configDir = path.join(basePath, CONFIG_DIR2);
|
|
13106
|
+
const configPath = path.join(configDir, CONFIG_FILE2);
|
|
13107
|
+
if (!existsSync3(configDir)) {
|
|
13108
|
+
await mkdir2(configDir, { recursive: true });
|
|
13109
|
+
}
|
|
13110
|
+
const config2 = {
|
|
13111
|
+
name: volumeName
|
|
13112
|
+
};
|
|
13113
|
+
const yamlContent = stringifyYaml(config2);
|
|
13114
|
+
await writeFile2(configPath, yamlContent, "utf8");
|
|
13115
|
+
}
|
|
13116
|
+
|
|
13117
|
+
// src/commands/volume/init.ts
|
|
13118
|
+
var initCommand = new Command3().name("init").description("Initialize a volume in the current directory").action(async () => {
|
|
13119
|
+
try {
|
|
13120
|
+
const cwd = process.cwd();
|
|
13121
|
+
const dirName = path2.basename(cwd);
|
|
13122
|
+
const existingConfig = await readVolumeConfig(cwd);
|
|
13123
|
+
if (existingConfig) {
|
|
13124
|
+
console.log(
|
|
13125
|
+
chalk5.yellow(`Volume already initialized: ${existingConfig.name}`)
|
|
13126
|
+
);
|
|
13127
|
+
console.log(
|
|
13128
|
+
chalk5.gray(`Config file: ${path2.join(cwd, ".vm0", "volume.yaml")}`)
|
|
13129
|
+
);
|
|
13130
|
+
return;
|
|
13131
|
+
}
|
|
13132
|
+
const volumeName = dirName;
|
|
13133
|
+
if (!isValidVolumeName(volumeName)) {
|
|
13134
|
+
console.error(chalk5.red(`\u2717 Invalid volume name: "${dirName}"`));
|
|
13135
|
+
console.error(
|
|
13136
|
+
chalk5.gray(
|
|
13137
|
+
" Volume names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
13138
|
+
)
|
|
13139
|
+
);
|
|
13140
|
+
console.error(
|
|
13141
|
+
chalk5.gray(" Example: my-dataset, user-data-v2, training-set-2024")
|
|
13142
|
+
);
|
|
13143
|
+
process.exit(1);
|
|
13144
|
+
}
|
|
13145
|
+
await writeVolumeConfig(volumeName, cwd);
|
|
13146
|
+
console.log(chalk5.green(`\u2713 Initialized volume: ${volumeName}`));
|
|
13147
|
+
console.log(
|
|
13148
|
+
chalk5.gray(
|
|
13149
|
+
`\u2713 Config saved to ${path2.join(cwd, ".vm0", "volume.yaml")}`
|
|
13150
|
+
)
|
|
13151
|
+
);
|
|
13152
|
+
} catch (error43) {
|
|
13153
|
+
console.error(chalk5.red("\u2717 Failed to initialize volume"));
|
|
13154
|
+
if (error43 instanceof Error) {
|
|
13155
|
+
console.error(chalk5.gray(` ${error43.message}`));
|
|
13156
|
+
}
|
|
13157
|
+
process.exit(1);
|
|
13158
|
+
}
|
|
13159
|
+
});
|
|
13160
|
+
|
|
13161
|
+
// src/commands/volume/push.ts
|
|
13162
|
+
import { Command as Command4 } from "commander";
|
|
13163
|
+
import chalk6 from "chalk";
|
|
13164
|
+
import path3 from "path";
|
|
13165
|
+
import * as fs from "fs";
|
|
13166
|
+
import AdmZip from "adm-zip";
|
|
13167
|
+
async function getAllFiles(dirPath, baseDir = dirPath) {
|
|
13168
|
+
const files = [];
|
|
13169
|
+
const entries = await fs.promises.readdir(dirPath, { withFileTypes: true });
|
|
13170
|
+
for (const entry of entries) {
|
|
13171
|
+
const fullPath = path3.join(dirPath, entry.name);
|
|
13172
|
+
const relativePath = path3.relative(baseDir, fullPath);
|
|
13173
|
+
if (relativePath.startsWith(".vm0")) {
|
|
13174
|
+
continue;
|
|
13175
|
+
}
|
|
13176
|
+
if (entry.isDirectory()) {
|
|
13177
|
+
const subFiles = await getAllFiles(fullPath, baseDir);
|
|
13178
|
+
files.push(...subFiles);
|
|
13179
|
+
} else {
|
|
13180
|
+
files.push(fullPath);
|
|
13181
|
+
}
|
|
13182
|
+
}
|
|
13183
|
+
return files;
|
|
13184
|
+
}
|
|
13185
|
+
function formatBytes(bytes) {
|
|
13186
|
+
if (bytes === 0) return "0 B";
|
|
13187
|
+
const k = 1024;
|
|
13188
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
13189
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
13190
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
13191
|
+
}
|
|
13192
|
+
var pushCommand = new Command4().name("push").description("Push local files to cloud volume").action(async () => {
|
|
13193
|
+
try {
|
|
13194
|
+
const cwd = process.cwd();
|
|
13195
|
+
const config2 = await readVolumeConfig(cwd);
|
|
13196
|
+
if (!config2) {
|
|
13197
|
+
console.error(chalk6.red("\u2717 No volume initialized in this directory"));
|
|
13198
|
+
console.error(chalk6.gray(" Run: vm0 volume init"));
|
|
13199
|
+
process.exit(1);
|
|
13200
|
+
}
|
|
13201
|
+
console.log(chalk6.cyan(`Pushing volume: ${config2.name}`));
|
|
13202
|
+
console.log(chalk6.gray("Collecting files..."));
|
|
13203
|
+
const files = await getAllFiles(cwd);
|
|
13204
|
+
if (files.length === 0) {
|
|
13205
|
+
console.log(chalk6.yellow("No files to upload"));
|
|
13206
|
+
return;
|
|
13207
|
+
}
|
|
13208
|
+
let totalSize = 0;
|
|
13209
|
+
for (const file2 of files) {
|
|
13210
|
+
const stats = await fs.promises.stat(file2);
|
|
13211
|
+
totalSize += stats.size;
|
|
13212
|
+
}
|
|
13213
|
+
console.log(
|
|
13214
|
+
chalk6.gray(`Found ${files.length} files (${formatBytes(totalSize)})`)
|
|
13215
|
+
);
|
|
13216
|
+
console.log(chalk6.gray("Compressing files..."));
|
|
13217
|
+
const zip = new AdmZip();
|
|
13218
|
+
for (const file2 of files) {
|
|
13219
|
+
const relativePath = path3.relative(cwd, file2);
|
|
13220
|
+
zip.addLocalFile(file2, path3.dirname(relativePath));
|
|
13221
|
+
}
|
|
13222
|
+
const zipBuffer = zip.toBuffer();
|
|
13223
|
+
console.log(
|
|
13224
|
+
chalk6.green(`\u2713 Compressed to ${formatBytes(zipBuffer.length)}`)
|
|
13225
|
+
);
|
|
13226
|
+
console.log(chalk6.gray("Uploading..."));
|
|
13227
|
+
const formData = new FormData();
|
|
13228
|
+
formData.append("volumeName", config2.name);
|
|
13229
|
+
formData.append(
|
|
13230
|
+
"file",
|
|
13231
|
+
new Blob([zipBuffer], { type: "application/zip" }),
|
|
13232
|
+
"volume.zip"
|
|
13233
|
+
);
|
|
13234
|
+
const response = await apiClient.post("/api/volumes", {
|
|
13235
|
+
body: formData
|
|
13236
|
+
});
|
|
13237
|
+
if (!response.ok) {
|
|
13238
|
+
const error43 = await response.json();
|
|
13239
|
+
throw new Error(error43.error || "Upload failed");
|
|
13240
|
+
}
|
|
13241
|
+
const result = await response.json();
|
|
13242
|
+
console.log(chalk6.green("\u2713 Upload complete"));
|
|
13243
|
+
console.log(chalk6.gray(` Files: ${result.fileCount.toLocaleString()}`));
|
|
13244
|
+
console.log(chalk6.gray(` Size: ${formatBytes(result.size)}`));
|
|
13245
|
+
} catch (error43) {
|
|
13246
|
+
console.error(chalk6.red("\u2717 Push failed"));
|
|
13247
|
+
if (error43 instanceof Error) {
|
|
13248
|
+
console.error(chalk6.gray(` ${error43.message}`));
|
|
13249
|
+
}
|
|
13250
|
+
process.exit(1);
|
|
13251
|
+
}
|
|
13252
|
+
});
|
|
13253
|
+
|
|
13254
|
+
// src/commands/volume/pull.ts
|
|
13255
|
+
import { Command as Command5 } from "commander";
|
|
13256
|
+
import chalk7 from "chalk";
|
|
13257
|
+
import path4 from "path";
|
|
13258
|
+
import * as fs2 from "fs";
|
|
13259
|
+
import AdmZip2 from "adm-zip";
|
|
13260
|
+
function formatBytes2(bytes) {
|
|
13261
|
+
if (bytes === 0) return "0 B";
|
|
13262
|
+
const k = 1024;
|
|
13263
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
13264
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
13265
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
13266
|
+
}
|
|
13267
|
+
var pullCommand = new Command5().name("pull").description("Pull cloud files to local directory").action(async () => {
|
|
13268
|
+
try {
|
|
13269
|
+
const cwd = process.cwd();
|
|
13270
|
+
const config2 = await readVolumeConfig(cwd);
|
|
13271
|
+
if (!config2) {
|
|
13272
|
+
console.error(chalk7.red("\u2717 No volume initialized in this directory"));
|
|
13273
|
+
console.error(chalk7.gray(" Run: vm0 volume init"));
|
|
13274
|
+
process.exit(1);
|
|
13275
|
+
}
|
|
13276
|
+
console.log(chalk7.cyan(`Pulling volume: ${config2.name}`));
|
|
13277
|
+
console.log(chalk7.gray("Downloading..."));
|
|
13278
|
+
const response = await apiClient.get(
|
|
13279
|
+
`/api/volumes?name=${encodeURIComponent(config2.name)}`
|
|
13280
|
+
);
|
|
13281
|
+
if (!response.ok) {
|
|
13282
|
+
if (response.status === 404) {
|
|
13283
|
+
console.error(chalk7.red(`\u2717 Volume "${config2.name}" not found`));
|
|
13284
|
+
console.error(
|
|
13285
|
+
chalk7.gray(
|
|
13286
|
+
" Make sure the volume name is correct in .vm0/volume.yaml"
|
|
13287
|
+
)
|
|
13288
|
+
);
|
|
13289
|
+
console.error(
|
|
13290
|
+
chalk7.gray(" Or push the volume first with: vm0 volume push")
|
|
13291
|
+
);
|
|
13292
|
+
} else {
|
|
13293
|
+
const error43 = await response.json();
|
|
13294
|
+
throw new Error(error43.error || "Download failed");
|
|
13295
|
+
}
|
|
13296
|
+
process.exit(1);
|
|
13297
|
+
}
|
|
13298
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
13299
|
+
const zipBuffer = Buffer.from(arrayBuffer);
|
|
13300
|
+
console.log(chalk7.green(`\u2713 Downloaded ${formatBytes2(zipBuffer.length)}`));
|
|
13301
|
+
console.log(chalk7.gray("Extracting files..."));
|
|
13302
|
+
const zip = new AdmZip2(zipBuffer);
|
|
13303
|
+
const zipEntries = zip.getEntries();
|
|
13304
|
+
let extractedCount = 0;
|
|
13305
|
+
for (const entry of zipEntries) {
|
|
13306
|
+
if (!entry.isDirectory) {
|
|
13307
|
+
const targetPath = path4.join(cwd, entry.entryName);
|
|
13308
|
+
const dir = path4.dirname(targetPath);
|
|
13309
|
+
await fs2.promises.mkdir(dir, { recursive: true });
|
|
13310
|
+
const data = entry.getData();
|
|
13311
|
+
await fs2.promises.writeFile(targetPath, data);
|
|
13312
|
+
extractedCount++;
|
|
13313
|
+
}
|
|
13314
|
+
}
|
|
13315
|
+
console.log(chalk7.green(`\u2713 Extracted ${extractedCount} files`));
|
|
13316
|
+
} catch (error43) {
|
|
13317
|
+
console.error(chalk7.red("\u2717 Pull failed"));
|
|
13318
|
+
if (error43 instanceof Error) {
|
|
13319
|
+
console.error(chalk7.gray(` ${error43.message}`));
|
|
13320
|
+
}
|
|
13321
|
+
process.exit(1);
|
|
13322
|
+
}
|
|
13323
|
+
});
|
|
13324
|
+
|
|
13325
|
+
// src/commands/volume/index.ts
|
|
13326
|
+
var volumeCommand = new Command6().name("volume").description("Manage cloud volumes").addCommand(initCommand).addCommand(pushCommand).addCommand(pullCommand);
|
|
13327
|
+
|
|
13030
13328
|
// src/index.ts
|
|
13031
|
-
var program = new
|
|
13329
|
+
var program = new Command7();
|
|
13032
13330
|
program.name("vm0").description("VM0 CLI - A modern build tool").version("0.1.0");
|
|
13033
13331
|
program.command("hello").description("Say hello from the App").action(() => {
|
|
13034
|
-
console.log(
|
|
13035
|
-
console.log(
|
|
13332
|
+
console.log(chalk8.blue("Welcome to the VM0 CLI!"));
|
|
13333
|
+
console.log(chalk8.green(`Core says: ${FOO}`));
|
|
13036
13334
|
});
|
|
13037
13335
|
program.command("info").description("Display environment information").action(async () => {
|
|
13038
|
-
console.log(
|
|
13336
|
+
console.log(chalk8.cyan("System Information:"));
|
|
13039
13337
|
console.log(`Node Version: ${process.version}`);
|
|
13040
13338
|
console.log(`Platform: ${process.platform}`);
|
|
13041
13339
|
console.log(`Architecture: ${process.arch}`);
|
|
@@ -13054,6 +13352,7 @@ authCommand.command("status").description("Show current authentication status").
|
|
|
13054
13352
|
});
|
|
13055
13353
|
program.addCommand(buildCommand);
|
|
13056
13354
|
program.addCommand(runCommand);
|
|
13355
|
+
program.addCommand(volumeCommand);
|
|
13057
13356
|
if (process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("index.ts") || process.argv[1]?.endsWith("vm0")) {
|
|
13058
13357
|
program.parse();
|
|
13059
13358
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vm0/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "CLI application",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"."
|
|
11
11
|
],
|
|
12
12
|
"dependencies": {
|
|
13
|
+
"adm-zip": "^0.5.16",
|
|
13
14
|
"chalk": "^5.6.0",
|
|
14
15
|
"commander": "^14.0.0",
|
|
15
16
|
"yaml": "^2.3.4"
|