@vm0/cli 4.31.1 → 4.32.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 +832 -437
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -6,8 +6,8 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
-
import { Command as
|
|
10
|
-
import
|
|
9
|
+
import { Command as Command29 } from "commander";
|
|
10
|
+
import chalk31 from "chalk";
|
|
11
11
|
|
|
12
12
|
// src/lib/auth.ts
|
|
13
13
|
import chalk from "chalk";
|
|
@@ -984,15 +984,15 @@ function mergeDefs(...defs) {
|
|
|
984
984
|
function cloneDef(schema) {
|
|
985
985
|
return mergeDefs(schema._zod.def);
|
|
986
986
|
}
|
|
987
|
-
function getElementAtPath(obj,
|
|
988
|
-
if (!
|
|
987
|
+
function getElementAtPath(obj, path14) {
|
|
988
|
+
if (!path14)
|
|
989
989
|
return obj;
|
|
990
|
-
return
|
|
990
|
+
return path14.reduce((acc, key) => acc?.[key], obj);
|
|
991
991
|
}
|
|
992
992
|
function promiseAllObject(promisesObj) {
|
|
993
993
|
const keys = Object.keys(promisesObj);
|
|
994
|
-
const
|
|
995
|
-
return Promise.all(
|
|
994
|
+
const promises6 = keys.map((key) => promisesObj[key]);
|
|
995
|
+
return Promise.all(promises6).then((results) => {
|
|
996
996
|
const resolvedObj = {};
|
|
997
997
|
for (let i = 0; i < keys.length; i++) {
|
|
998
998
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -1346,11 +1346,11 @@ function aborted(x, startIndex = 0) {
|
|
|
1346
1346
|
}
|
|
1347
1347
|
return false;
|
|
1348
1348
|
}
|
|
1349
|
-
function prefixIssues(
|
|
1349
|
+
function prefixIssues(path14, issues) {
|
|
1350
1350
|
return issues.map((iss) => {
|
|
1351
1351
|
var _a;
|
|
1352
1352
|
(_a = iss).path ?? (_a.path = []);
|
|
1353
|
-
iss.path.unshift(
|
|
1353
|
+
iss.path.unshift(path14);
|
|
1354
1354
|
return iss;
|
|
1355
1355
|
});
|
|
1356
1356
|
}
|
|
@@ -1518,7 +1518,7 @@ function treeifyError(error43, _mapper) {
|
|
|
1518
1518
|
return issue2.message;
|
|
1519
1519
|
};
|
|
1520
1520
|
const result = { errors: [] };
|
|
1521
|
-
const processError = (error44,
|
|
1521
|
+
const processError = (error44, path14 = []) => {
|
|
1522
1522
|
var _a, _b;
|
|
1523
1523
|
for (const issue2 of error44.issues) {
|
|
1524
1524
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -1528,7 +1528,7 @@ function treeifyError(error43, _mapper) {
|
|
|
1528
1528
|
} else if (issue2.code === "invalid_element") {
|
|
1529
1529
|
processError({ issues: issue2.issues }, issue2.path);
|
|
1530
1530
|
} else {
|
|
1531
|
-
const fullpath = [...
|
|
1531
|
+
const fullpath = [...path14, ...issue2.path];
|
|
1532
1532
|
if (fullpath.length === 0) {
|
|
1533
1533
|
result.errors.push(mapper(issue2));
|
|
1534
1534
|
continue;
|
|
@@ -1560,8 +1560,8 @@ function treeifyError(error43, _mapper) {
|
|
|
1560
1560
|
}
|
|
1561
1561
|
function toDotPath(_path) {
|
|
1562
1562
|
const segs = [];
|
|
1563
|
-
const
|
|
1564
|
-
for (const seg of
|
|
1563
|
+
const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
1564
|
+
for (const seg of path14) {
|
|
1565
1565
|
if (typeof seg === "number")
|
|
1566
1566
|
segs.push(`[${seg}]`);
|
|
1567
1567
|
else if (typeof seg === "symbol")
|
|
@@ -12879,6 +12879,28 @@ var storagesDownloadContract = c3.router({
|
|
|
12879
12879
|
summary: "Get presigned download URL"
|
|
12880
12880
|
}
|
|
12881
12881
|
});
|
|
12882
|
+
var storagesListContract = c3.router({
|
|
12883
|
+
list: {
|
|
12884
|
+
method: "GET",
|
|
12885
|
+
path: "/api/storages/list",
|
|
12886
|
+
query: external_exports.object({
|
|
12887
|
+
type: storageTypeSchema
|
|
12888
|
+
}),
|
|
12889
|
+
responses: {
|
|
12890
|
+
200: external_exports.array(
|
|
12891
|
+
external_exports.object({
|
|
12892
|
+
name: external_exports.string(),
|
|
12893
|
+
size: external_exports.number(),
|
|
12894
|
+
fileCount: external_exports.number(),
|
|
12895
|
+
updatedAt: external_exports.string()
|
|
12896
|
+
})
|
|
12897
|
+
),
|
|
12898
|
+
401: apiErrorSchema,
|
|
12899
|
+
500: apiErrorSchema
|
|
12900
|
+
},
|
|
12901
|
+
summary: "List user storages by type"
|
|
12902
|
+
}
|
|
12903
|
+
});
|
|
12882
12904
|
|
|
12883
12905
|
// ../../packages/core/src/contracts/webhooks.ts
|
|
12884
12906
|
var c4 = initContract();
|
|
@@ -13911,7 +13933,7 @@ var ApiClient = class {
|
|
|
13911
13933
|
/**
|
|
13912
13934
|
* Generic GET request
|
|
13913
13935
|
*/
|
|
13914
|
-
async get(
|
|
13936
|
+
async get(path14) {
|
|
13915
13937
|
const baseUrl = await this.getBaseUrl();
|
|
13916
13938
|
const token = await getToken();
|
|
13917
13939
|
if (!token) {
|
|
@@ -13924,7 +13946,7 @@ var ApiClient = class {
|
|
|
13924
13946
|
if (bypassSecret) {
|
|
13925
13947
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
13926
13948
|
}
|
|
13927
|
-
return fetch(`${baseUrl}${
|
|
13949
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
13928
13950
|
method: "GET",
|
|
13929
13951
|
headers
|
|
13930
13952
|
});
|
|
@@ -13932,7 +13954,7 @@ var ApiClient = class {
|
|
|
13932
13954
|
/**
|
|
13933
13955
|
* Generic POST request
|
|
13934
13956
|
*/
|
|
13935
|
-
async post(
|
|
13957
|
+
async post(path14, options) {
|
|
13936
13958
|
const baseUrl = await this.getBaseUrl();
|
|
13937
13959
|
const token = await getToken();
|
|
13938
13960
|
if (!token) {
|
|
@@ -13948,7 +13970,7 @@ var ApiClient = class {
|
|
|
13948
13970
|
if (bypassSecret) {
|
|
13949
13971
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
13950
13972
|
}
|
|
13951
|
-
return fetch(`${baseUrl}${
|
|
13973
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
13952
13974
|
method: "POST",
|
|
13953
13975
|
headers,
|
|
13954
13976
|
body: options?.body
|
|
@@ -13957,7 +13979,7 @@ var ApiClient = class {
|
|
|
13957
13979
|
/**
|
|
13958
13980
|
* Generic DELETE request
|
|
13959
13981
|
*/
|
|
13960
|
-
async delete(
|
|
13982
|
+
async delete(path14) {
|
|
13961
13983
|
const baseUrl = await this.getBaseUrl();
|
|
13962
13984
|
const token = await getToken();
|
|
13963
13985
|
if (!token) {
|
|
@@ -13970,7 +13992,7 @@ var ApiClient = class {
|
|
|
13970
13992
|
if (bypassSecret) {
|
|
13971
13993
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
13972
13994
|
}
|
|
13973
|
-
return fetch(`${baseUrl}${
|
|
13995
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
13974
13996
|
method: "DELETE",
|
|
13975
13997
|
headers
|
|
13976
13998
|
});
|
|
@@ -14340,6 +14362,28 @@ import * as tar2 from "tar";
|
|
|
14340
14362
|
import * as fs2 from "fs";
|
|
14341
14363
|
import * as path2 from "path";
|
|
14342
14364
|
import * as tar from "tar";
|
|
14365
|
+
function formatBytes(bytes) {
|
|
14366
|
+
if (bytes === 0) return "0 B";
|
|
14367
|
+
const k = 1024;
|
|
14368
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
14369
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
14370
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
14371
|
+
}
|
|
14372
|
+
function formatRelativeTime(isoDate) {
|
|
14373
|
+
const date5 = new Date(isoDate);
|
|
14374
|
+
const now = /* @__PURE__ */ new Date();
|
|
14375
|
+
const diffMs = now.getTime() - date5.getTime();
|
|
14376
|
+
const diffSec = Math.floor(diffMs / 1e3);
|
|
14377
|
+
const diffMin = Math.floor(diffSec / 60);
|
|
14378
|
+
const diffHour = Math.floor(diffMin / 60);
|
|
14379
|
+
const diffDay = Math.floor(diffHour / 24);
|
|
14380
|
+
const diffWeek = Math.floor(diffDay / 7);
|
|
14381
|
+
if (diffSec < 60) return "just now";
|
|
14382
|
+
if (diffMin < 60) return `${diffMin} minute${diffMin === 1 ? "" : "s"} ago`;
|
|
14383
|
+
if (diffHour < 24) return `${diffHour} hour${diffHour === 1 ? "" : "s"} ago`;
|
|
14384
|
+
if (diffDay < 7) return `${diffDay} day${diffDay === 1 ? "" : "s"} ago`;
|
|
14385
|
+
return `${diffWeek} week${diffWeek === 1 ? "" : "s"} ago`;
|
|
14386
|
+
}
|
|
14343
14387
|
function excludeVm0Filter(filePath) {
|
|
14344
14388
|
const shouldExclude = filePath === ".vm0" || filePath.startsWith(".vm0/") || filePath.startsWith("./.vm0");
|
|
14345
14389
|
return !shouldExclude;
|
|
@@ -14679,6 +14723,11 @@ async function uploadSkill(skillUrl) {
|
|
|
14679
14723
|
}
|
|
14680
14724
|
|
|
14681
14725
|
// src/commands/compose.ts
|
|
14726
|
+
function getSecretsFromComposeContent(content) {
|
|
14727
|
+
const refs = extractVariableReferences(content);
|
|
14728
|
+
const grouped = groupVariablesBySource(refs);
|
|
14729
|
+
return new Set(grouped.secrets.map((r) => r.name));
|
|
14730
|
+
}
|
|
14682
14731
|
function transformExperimentalShorthand(agent) {
|
|
14683
14732
|
const experimentalSecrets = agent.experimental_secrets;
|
|
14684
14733
|
const experimentalVars = agent.experimental_vars;
|
|
@@ -14843,6 +14892,15 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
14843
14892
|
const newVars = [...skillVars.entries()].filter(
|
|
14844
14893
|
([name]) => !(name in environment)
|
|
14845
14894
|
);
|
|
14895
|
+
let headSecrets = /* @__PURE__ */ new Set();
|
|
14896
|
+
try {
|
|
14897
|
+
const existingCompose = await apiClient.getComposeByName(agentName);
|
|
14898
|
+
if (existingCompose.content) {
|
|
14899
|
+
headSecrets = getSecretsFromComposeContent(existingCompose.content);
|
|
14900
|
+
}
|
|
14901
|
+
} catch {
|
|
14902
|
+
}
|
|
14903
|
+
const trulyNewSecrets = newSecrets.map(([name]) => name).filter((name) => !headSecrets.has(name));
|
|
14846
14904
|
if (newSecrets.length > 0 || newVars.length > 0) {
|
|
14847
14905
|
console.log();
|
|
14848
14906
|
console.log(
|
|
@@ -14852,7 +14910,11 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
14852
14910
|
if (newSecrets.length > 0) {
|
|
14853
14911
|
console.log(chalk2.cyan(" Secrets:"));
|
|
14854
14912
|
for (const [name, skills] of newSecrets) {
|
|
14855
|
-
|
|
14913
|
+
const isNew = trulyNewSecrets.includes(name);
|
|
14914
|
+
const newMarker = isNew ? chalk2.yellow(" (new)") : "";
|
|
14915
|
+
console.log(
|
|
14916
|
+
` ${name.padEnd(24)}${newMarker} <- ${skills.join(", ")}`
|
|
14917
|
+
);
|
|
14856
14918
|
}
|
|
14857
14919
|
}
|
|
14858
14920
|
if (newVars.length > 0) {
|
|
@@ -14862,24 +14924,31 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
14862
14924
|
}
|
|
14863
14925
|
}
|
|
14864
14926
|
console.log();
|
|
14865
|
-
if (
|
|
14866
|
-
if (!
|
|
14867
|
-
|
|
14868
|
-
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14872
|
-
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
14927
|
+
if (trulyNewSecrets.length > 0) {
|
|
14928
|
+
if (!options.yes) {
|
|
14929
|
+
if (!process.stdin.isTTY) {
|
|
14930
|
+
console.error(
|
|
14931
|
+
chalk2.red(
|
|
14932
|
+
`\u2717 New secrets detected: ${trulyNewSecrets.join(", ")}`
|
|
14933
|
+
)
|
|
14934
|
+
);
|
|
14935
|
+
console.error(
|
|
14936
|
+
chalk2.dim(
|
|
14937
|
+
" Use --yes flag to approve new secrets in non-interactive mode."
|
|
14938
|
+
)
|
|
14939
|
+
);
|
|
14940
|
+
process.exit(1);
|
|
14941
|
+
}
|
|
14942
|
+
const response2 = await prompts({
|
|
14943
|
+
type: "confirm",
|
|
14944
|
+
name: "value",
|
|
14945
|
+
message: `Approve ${trulyNewSecrets.length} new secret(s)?`,
|
|
14946
|
+
initial: true
|
|
14947
|
+
});
|
|
14948
|
+
if (!response2.value) {
|
|
14949
|
+
console.log(chalk2.yellow("Compose cancelled."));
|
|
14950
|
+
process.exit(0);
|
|
14951
|
+
}
|
|
14883
14952
|
}
|
|
14884
14953
|
}
|
|
14885
14954
|
for (const [name] of newSecrets) {
|
|
@@ -16127,7 +16196,7 @@ runCmd.command("continue").description(
|
|
|
16127
16196
|
var runCommand = runCmd;
|
|
16128
16197
|
|
|
16129
16198
|
// src/commands/volume/index.ts
|
|
16130
|
-
import { Command as
|
|
16199
|
+
import { Command as Command9 } from "commander";
|
|
16131
16200
|
|
|
16132
16201
|
// src/commands/volume/init.ts
|
|
16133
16202
|
import { Command as Command3 } from "commander";
|
|
@@ -16181,8 +16250,53 @@ async function writeStorageConfig(storageName, basePath = process.cwd(), type =
|
|
|
16181
16250
|
await writeFile4(configPath, yamlContent, "utf8");
|
|
16182
16251
|
}
|
|
16183
16252
|
|
|
16253
|
+
// src/lib/prompt-utils.ts
|
|
16254
|
+
import prompts2 from "prompts";
|
|
16255
|
+
function isInteractive() {
|
|
16256
|
+
return process.stdout.isTTY === true;
|
|
16257
|
+
}
|
|
16258
|
+
async function promptText(message, initial, validate) {
|
|
16259
|
+
if (!isInteractive()) {
|
|
16260
|
+
return void 0;
|
|
16261
|
+
}
|
|
16262
|
+
const response = await prompts2(
|
|
16263
|
+
{
|
|
16264
|
+
type: "text",
|
|
16265
|
+
name: "value",
|
|
16266
|
+
message,
|
|
16267
|
+
initial,
|
|
16268
|
+
validate
|
|
16269
|
+
},
|
|
16270
|
+
{
|
|
16271
|
+
onCancel: () => {
|
|
16272
|
+
return false;
|
|
16273
|
+
}
|
|
16274
|
+
}
|
|
16275
|
+
);
|
|
16276
|
+
return response.value;
|
|
16277
|
+
}
|
|
16278
|
+
async function promptConfirm(message, initial = true) {
|
|
16279
|
+
if (!isInteractive()) {
|
|
16280
|
+
return void 0;
|
|
16281
|
+
}
|
|
16282
|
+
const response = await prompts2(
|
|
16283
|
+
{
|
|
16284
|
+
type: "confirm",
|
|
16285
|
+
name: "value",
|
|
16286
|
+
message,
|
|
16287
|
+
initial
|
|
16288
|
+
},
|
|
16289
|
+
{
|
|
16290
|
+
onCancel: () => {
|
|
16291
|
+
return false;
|
|
16292
|
+
}
|
|
16293
|
+
}
|
|
16294
|
+
);
|
|
16295
|
+
return response.value;
|
|
16296
|
+
}
|
|
16297
|
+
|
|
16184
16298
|
// src/commands/volume/init.ts
|
|
16185
|
-
var initCommand = new Command3().name("init").description("Initialize a volume in the current directory").action(async () => {
|
|
16299
|
+
var initCommand = new Command3().name("init").description("Initialize a volume in the current directory").option("-n, --name <name>", "Volume name (required in non-interactive mode)").action(async (options) => {
|
|
16186
16300
|
try {
|
|
16187
16301
|
const cwd = process.cwd();
|
|
16188
16302
|
const dirName = path7.basename(cwd);
|
|
@@ -16196,9 +16310,37 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
16196
16310
|
);
|
|
16197
16311
|
return;
|
|
16198
16312
|
}
|
|
16199
|
-
|
|
16313
|
+
let volumeName;
|
|
16314
|
+
if (options.name) {
|
|
16315
|
+
volumeName = options.name;
|
|
16316
|
+
} else if (!isInteractive()) {
|
|
16317
|
+
console.error(
|
|
16318
|
+
chalk6.red("\u2717 --name flag is required in non-interactive mode")
|
|
16319
|
+
);
|
|
16320
|
+
console.error(
|
|
16321
|
+
chalk6.dim(" Usage: vm0 volume init --name <volume-name>")
|
|
16322
|
+
);
|
|
16323
|
+
process.exit(1);
|
|
16324
|
+
} else {
|
|
16325
|
+
const defaultName = isValidStorageName(dirName) ? dirName : void 0;
|
|
16326
|
+
const name = await promptText(
|
|
16327
|
+
"Enter volume name",
|
|
16328
|
+
defaultName,
|
|
16329
|
+
(value) => {
|
|
16330
|
+
if (!isValidStorageName(value)) {
|
|
16331
|
+
return "Must be 3-64 characters, lowercase alphanumeric with hyphens";
|
|
16332
|
+
}
|
|
16333
|
+
return true;
|
|
16334
|
+
}
|
|
16335
|
+
);
|
|
16336
|
+
if (name === void 0) {
|
|
16337
|
+
console.log(chalk6.dim("Cancelled"));
|
|
16338
|
+
return;
|
|
16339
|
+
}
|
|
16340
|
+
volumeName = name;
|
|
16341
|
+
}
|
|
16200
16342
|
if (!isValidStorageName(volumeName)) {
|
|
16201
|
-
console.error(chalk6.red(`\u2717 Invalid volume name: "${
|
|
16343
|
+
console.error(chalk6.red(`\u2717 Invalid volume name: "${volumeName}"`));
|
|
16202
16344
|
console.error(
|
|
16203
16345
|
chalk6.dim(
|
|
16204
16346
|
" Volume names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
@@ -16228,7 +16370,7 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
16228
16370
|
// src/commands/volume/push.ts
|
|
16229
16371
|
import { Command as Command4 } from "commander";
|
|
16230
16372
|
import chalk7 from "chalk";
|
|
16231
|
-
function
|
|
16373
|
+
function formatBytes2(bytes) {
|
|
16232
16374
|
if (bytes === 0) return "0 B";
|
|
16233
16375
|
const k = 1024;
|
|
16234
16376
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -16264,7 +16406,7 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
16264
16406
|
}
|
|
16265
16407
|
console.log(chalk7.dim(` Version: ${shortVersion}`));
|
|
16266
16408
|
console.log(chalk7.dim(` Files: ${result.fileCount.toLocaleString()}`));
|
|
16267
|
-
console.log(chalk7.dim(` Size: ${
|
|
16409
|
+
console.log(chalk7.dim(` Size: ${formatBytes2(result.size)}`));
|
|
16268
16410
|
} catch (error43) {
|
|
16269
16411
|
console.error(chalk7.red("\u2717 Push failed"));
|
|
16270
16412
|
if (error43 instanceof Error) {
|
|
@@ -16295,7 +16437,7 @@ async function handleEmptyStorageResponse(cwd) {
|
|
|
16295
16437
|
}
|
|
16296
16438
|
|
|
16297
16439
|
// src/commands/volume/pull.ts
|
|
16298
|
-
function
|
|
16440
|
+
function formatBytes3(bytes) {
|
|
16299
16441
|
if (bytes === 0) return "0 B";
|
|
16300
16442
|
const k = 1024;
|
|
16301
16443
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -16354,7 +16496,7 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
16354
16496
|
}
|
|
16355
16497
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
16356
16498
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
16357
|
-
console.log(chalk9.green(`\u2713 Downloaded ${
|
|
16499
|
+
console.log(chalk9.green(`\u2713 Downloaded ${formatBytes3(tarBuffer.length)}`));
|
|
16358
16500
|
const tmpDir = fs6.mkdtempSync(path8.join(os4.tmpdir(), "vm0-"));
|
|
16359
16501
|
const tarPath = path8.join(tmpDir, "volume.tar.gz");
|
|
16360
16502
|
await fs6.promises.writeFile(tarPath, tarBuffer);
|
|
@@ -16390,7 +16532,7 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
16390
16532
|
// src/commands/volume/status.ts
|
|
16391
16533
|
import { Command as Command6 } from "commander";
|
|
16392
16534
|
import chalk10 from "chalk";
|
|
16393
|
-
function
|
|
16535
|
+
function formatBytes4(bytes) {
|
|
16394
16536
|
if (bytes === 0) return "0 B";
|
|
16395
16537
|
const k = 1024;
|
|
16396
16538
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -16437,7 +16579,7 @@ var statusCommand = new Command6().name("status").description("Show status of cl
|
|
|
16437
16579
|
console.log(chalk10.green("\u2713 Found"));
|
|
16438
16580
|
console.log(chalk10.dim(` Version: ${shortVersion}`));
|
|
16439
16581
|
console.log(chalk10.dim(` Files: ${info.fileCount.toLocaleString()}`));
|
|
16440
|
-
console.log(chalk10.dim(` Size: ${
|
|
16582
|
+
console.log(chalk10.dim(` Size: ${formatBytes4(info.size)}`));
|
|
16441
16583
|
}
|
|
16442
16584
|
} catch (error43) {
|
|
16443
16585
|
console.error(chalk10.red("\u2717 Status check failed"));
|
|
@@ -16448,85 +16590,275 @@ var statusCommand = new Command6().name("status").description("Show status of cl
|
|
|
16448
16590
|
}
|
|
16449
16591
|
});
|
|
16450
16592
|
|
|
16593
|
+
// src/commands/volume/list.ts
|
|
16594
|
+
import { Command as Command7 } from "commander";
|
|
16595
|
+
import chalk11 from "chalk";
|
|
16596
|
+
var listCommand = new Command7().name("list").alias("ls").description("List all remote volumes").action(async () => {
|
|
16597
|
+
try {
|
|
16598
|
+
const url2 = "/api/storages/list?type=volume";
|
|
16599
|
+
const response = await apiClient.get(url2);
|
|
16600
|
+
if (!response.ok) {
|
|
16601
|
+
const error43 = await response.json();
|
|
16602
|
+
throw new Error(error43.error?.message || "List failed");
|
|
16603
|
+
}
|
|
16604
|
+
const items = await response.json();
|
|
16605
|
+
if (items.length === 0) {
|
|
16606
|
+
console.log(chalk11.dim("No volumes found"));
|
|
16607
|
+
console.log(
|
|
16608
|
+
chalk11.dim(" Create one with: vm0 volume init && vm0 volume push")
|
|
16609
|
+
);
|
|
16610
|
+
return;
|
|
16611
|
+
}
|
|
16612
|
+
const nameWidth = Math.max(4, ...items.map((i) => i.name.length));
|
|
16613
|
+
const sizeWidth = Math.max(
|
|
16614
|
+
4,
|
|
16615
|
+
...items.map((i) => formatBytes(i.size).length)
|
|
16616
|
+
);
|
|
16617
|
+
const filesWidth = Math.max(
|
|
16618
|
+
5,
|
|
16619
|
+
...items.map((i) => i.fileCount.toString().length)
|
|
16620
|
+
);
|
|
16621
|
+
const header = [
|
|
16622
|
+
"NAME".padEnd(nameWidth),
|
|
16623
|
+
"SIZE".padStart(sizeWidth),
|
|
16624
|
+
"FILES".padStart(filesWidth),
|
|
16625
|
+
"UPDATED"
|
|
16626
|
+
].join(" ");
|
|
16627
|
+
console.log(chalk11.dim(header));
|
|
16628
|
+
for (const item of items) {
|
|
16629
|
+
const row = [
|
|
16630
|
+
item.name.padEnd(nameWidth),
|
|
16631
|
+
formatBytes(item.size).padStart(sizeWidth),
|
|
16632
|
+
item.fileCount.toString().padStart(filesWidth),
|
|
16633
|
+
formatRelativeTime(item.updatedAt)
|
|
16634
|
+
].join(" ");
|
|
16635
|
+
console.log(row);
|
|
16636
|
+
}
|
|
16637
|
+
} catch (error43) {
|
|
16638
|
+
console.error(chalk11.red("\u2717 Failed to list volumes"));
|
|
16639
|
+
if (error43 instanceof Error) {
|
|
16640
|
+
if (error43.message.includes("Not authenticated")) {
|
|
16641
|
+
console.error(chalk11.dim(" Run: vm0 auth login"));
|
|
16642
|
+
} else {
|
|
16643
|
+
console.error(chalk11.dim(` ${error43.message}`));
|
|
16644
|
+
}
|
|
16645
|
+
}
|
|
16646
|
+
process.exit(1);
|
|
16647
|
+
}
|
|
16648
|
+
});
|
|
16649
|
+
|
|
16650
|
+
// src/commands/volume/clone.ts
|
|
16651
|
+
import { Command as Command8 } from "commander";
|
|
16652
|
+
import chalk13 from "chalk";
|
|
16653
|
+
|
|
16654
|
+
// src/lib/clone-utils.ts
|
|
16655
|
+
import chalk12 from "chalk";
|
|
16656
|
+
import path9 from "path";
|
|
16657
|
+
import * as fs7 from "fs";
|
|
16658
|
+
import * as os5 from "os";
|
|
16659
|
+
import * as tar4 from "tar";
|
|
16660
|
+
async function cloneStorage(name, type, destination, options = {}) {
|
|
16661
|
+
const typeLabel = type === "artifact" ? "artifact" : "volume";
|
|
16662
|
+
if (fs7.existsSync(destination)) {
|
|
16663
|
+
throw new Error(`Directory "${destination}" already exists`);
|
|
16664
|
+
}
|
|
16665
|
+
console.log(chalk12.dim(`Checking remote ${typeLabel}...`));
|
|
16666
|
+
let url2 = `/api/storages/download?name=${encodeURIComponent(name)}&type=${type}`;
|
|
16667
|
+
if (options.version) {
|
|
16668
|
+
url2 += `&version=${encodeURIComponent(options.version)}`;
|
|
16669
|
+
}
|
|
16670
|
+
const response = await apiClient.get(url2);
|
|
16671
|
+
if (!response.ok) {
|
|
16672
|
+
if (response.status === 404) {
|
|
16673
|
+
throw new Error(
|
|
16674
|
+
`${typeLabel.charAt(0).toUpperCase() + typeLabel.slice(1)} "${name}" not found`
|
|
16675
|
+
);
|
|
16676
|
+
}
|
|
16677
|
+
const error43 = await response.json();
|
|
16678
|
+
throw new Error(error43.error?.message || "Clone failed");
|
|
16679
|
+
}
|
|
16680
|
+
const downloadInfo = await response.json();
|
|
16681
|
+
console.log(chalk12.dim(`Creating directory: ${destination}/`));
|
|
16682
|
+
await fs7.promises.mkdir(destination, { recursive: true });
|
|
16683
|
+
if (downloadInfo.empty) {
|
|
16684
|
+
await writeStorageConfig(name, destination, type);
|
|
16685
|
+
console.log(chalk12.green(`\u2713 Cloned empty ${typeLabel}: ${name}`));
|
|
16686
|
+
console.log(chalk12.dim(`\u2713 Initialized .vm0/storage.yaml`));
|
|
16687
|
+
return {
|
|
16688
|
+
success: true,
|
|
16689
|
+
fileCount: 0,
|
|
16690
|
+
size: 0,
|
|
16691
|
+
versionId: downloadInfo.versionId
|
|
16692
|
+
};
|
|
16693
|
+
}
|
|
16694
|
+
if (!downloadInfo.url) {
|
|
16695
|
+
throw new Error("No download URL returned");
|
|
16696
|
+
}
|
|
16697
|
+
console.log(chalk12.dim("Downloading from S3..."));
|
|
16698
|
+
const s3Response = await fetch(downloadInfo.url);
|
|
16699
|
+
if (!s3Response.ok) {
|
|
16700
|
+
await fs7.promises.rm(destination, { recursive: true, force: true });
|
|
16701
|
+
throw new Error(`S3 download failed: ${s3Response.status}`);
|
|
16702
|
+
}
|
|
16703
|
+
const arrayBuffer = await s3Response.arrayBuffer();
|
|
16704
|
+
const tarBuffer = Buffer.from(arrayBuffer);
|
|
16705
|
+
console.log(chalk12.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
|
|
16706
|
+
const tmpDir = fs7.mkdtempSync(path9.join(os5.tmpdir(), "vm0-clone-"));
|
|
16707
|
+
const tarPath = path9.join(tmpDir, "archive.tar.gz");
|
|
16708
|
+
await fs7.promises.writeFile(tarPath, tarBuffer);
|
|
16709
|
+
const files = await listTarFiles(tarPath);
|
|
16710
|
+
console.log(chalk12.dim("Extracting files..."));
|
|
16711
|
+
await tar4.extract({
|
|
16712
|
+
file: tarPath,
|
|
16713
|
+
cwd: destination,
|
|
16714
|
+
gzip: true
|
|
16715
|
+
});
|
|
16716
|
+
await fs7.promises.unlink(tarPath);
|
|
16717
|
+
await fs7.promises.rmdir(tmpDir);
|
|
16718
|
+
console.log(chalk12.green(`\u2713 Extracted ${files.length} files`));
|
|
16719
|
+
await writeStorageConfig(name, destination, type);
|
|
16720
|
+
console.log(chalk12.green(`\u2713 Initialized .vm0/storage.yaml`));
|
|
16721
|
+
return {
|
|
16722
|
+
success: true,
|
|
16723
|
+
fileCount: downloadInfo.fileCount,
|
|
16724
|
+
size: downloadInfo.size,
|
|
16725
|
+
versionId: downloadInfo.versionId
|
|
16726
|
+
};
|
|
16727
|
+
}
|
|
16728
|
+
|
|
16729
|
+
// src/commands/volume/clone.ts
|
|
16730
|
+
var cloneCommand = new Command8().name("clone").description("Clone a remote volume to local directory (latest version)").argument("<name>", "Volume name to clone").argument("[destination]", "Destination directory (default: volume name)").action(async (name, destination) => {
|
|
16731
|
+
try {
|
|
16732
|
+
const targetDir = destination || name;
|
|
16733
|
+
console.log(`Cloning volume: ${name}`);
|
|
16734
|
+
const result = await cloneStorage(name, "volume", targetDir);
|
|
16735
|
+
console.log(chalk13.green(`
|
|
16736
|
+
\u2713 Successfully cloned volume: ${name}`));
|
|
16737
|
+
console.log(chalk13.dim(` Location: ${targetDir}/`));
|
|
16738
|
+
console.log(chalk13.dim(` Version: ${result.versionId.slice(0, 8)}`));
|
|
16739
|
+
} catch (error43) {
|
|
16740
|
+
console.error(chalk13.red("\u2717 Clone failed"));
|
|
16741
|
+
if (error43 instanceof Error) {
|
|
16742
|
+
if (error43.message.includes("Not authenticated")) {
|
|
16743
|
+
console.error(chalk13.dim(" Run: vm0 auth login"));
|
|
16744
|
+
} else {
|
|
16745
|
+
console.error(chalk13.dim(` ${error43.message}`));
|
|
16746
|
+
}
|
|
16747
|
+
}
|
|
16748
|
+
process.exit(1);
|
|
16749
|
+
}
|
|
16750
|
+
});
|
|
16751
|
+
|
|
16451
16752
|
// src/commands/volume/index.ts
|
|
16452
|
-
var volumeCommand = new
|
|
16753
|
+
var volumeCommand = new Command9().name("volume").description("Manage cloud volumes").addCommand(initCommand).addCommand(pushCommand).addCommand(pullCommand).addCommand(statusCommand).addCommand(listCommand).addCommand(cloneCommand);
|
|
16453
16754
|
|
|
16454
16755
|
// src/commands/artifact/index.ts
|
|
16455
|
-
import { Command as
|
|
16756
|
+
import { Command as Command16 } from "commander";
|
|
16456
16757
|
|
|
16457
16758
|
// src/commands/artifact/init.ts
|
|
16458
|
-
import { Command as
|
|
16459
|
-
import
|
|
16460
|
-
import
|
|
16461
|
-
var initCommand2 = new
|
|
16759
|
+
import { Command as Command10 } from "commander";
|
|
16760
|
+
import chalk14 from "chalk";
|
|
16761
|
+
import path10 from "path";
|
|
16762
|
+
var initCommand2 = new Command10().name("init").description("Initialize an artifact in the current directory").option(
|
|
16763
|
+
"-n, --name <name>",
|
|
16764
|
+
"Artifact name (required in non-interactive mode)"
|
|
16765
|
+
).action(async (options) => {
|
|
16462
16766
|
try {
|
|
16463
16767
|
const cwd = process.cwd();
|
|
16464
|
-
const dirName =
|
|
16768
|
+
const dirName = path10.basename(cwd);
|
|
16465
16769
|
const existingConfig = await readStorageConfig(cwd);
|
|
16466
16770
|
if (existingConfig) {
|
|
16467
16771
|
if (existingConfig.type === "artifact") {
|
|
16468
16772
|
console.log(
|
|
16469
|
-
|
|
16773
|
+
chalk14.yellow(
|
|
16470
16774
|
`Artifact already initialized: ${existingConfig.name}`
|
|
16471
16775
|
)
|
|
16472
16776
|
);
|
|
16473
16777
|
} else {
|
|
16474
16778
|
console.log(
|
|
16475
|
-
|
|
16779
|
+
chalk14.yellow(
|
|
16476
16780
|
`Directory already initialized as volume: ${existingConfig.name}`
|
|
16477
16781
|
)
|
|
16478
16782
|
);
|
|
16479
16783
|
console.log(
|
|
16480
|
-
|
|
16784
|
+
chalk14.dim(
|
|
16481
16785
|
" To change type, delete .vm0/storage.yaml and reinitialize"
|
|
16482
16786
|
)
|
|
16483
16787
|
);
|
|
16484
16788
|
}
|
|
16485
16789
|
console.log(
|
|
16486
|
-
|
|
16790
|
+
chalk14.dim(`Config file: ${path10.join(cwd, ".vm0", "storage.yaml")}`)
|
|
16487
16791
|
);
|
|
16488
16792
|
return;
|
|
16489
16793
|
}
|
|
16490
|
-
|
|
16794
|
+
let artifactName;
|
|
16795
|
+
if (options.name) {
|
|
16796
|
+
artifactName = options.name;
|
|
16797
|
+
} else if (!isInteractive()) {
|
|
16798
|
+
console.error(
|
|
16799
|
+
chalk14.red("\u2717 --name flag is required in non-interactive mode")
|
|
16800
|
+
);
|
|
16801
|
+
console.error(
|
|
16802
|
+
chalk14.dim(" Usage: vm0 artifact init --name <artifact-name>")
|
|
16803
|
+
);
|
|
16804
|
+
process.exit(1);
|
|
16805
|
+
} else {
|
|
16806
|
+
const defaultName = isValidStorageName(dirName) ? dirName : void 0;
|
|
16807
|
+
const name = await promptText(
|
|
16808
|
+
"Enter artifact name",
|
|
16809
|
+
defaultName,
|
|
16810
|
+
(value) => {
|
|
16811
|
+
if (!isValidStorageName(value)) {
|
|
16812
|
+
return "Must be 3-64 characters, lowercase alphanumeric with hyphens";
|
|
16813
|
+
}
|
|
16814
|
+
return true;
|
|
16815
|
+
}
|
|
16816
|
+
);
|
|
16817
|
+
if (name === void 0) {
|
|
16818
|
+
console.log(chalk14.dim("Cancelled"));
|
|
16819
|
+
return;
|
|
16820
|
+
}
|
|
16821
|
+
artifactName = name;
|
|
16822
|
+
}
|
|
16491
16823
|
if (!isValidStorageName(artifactName)) {
|
|
16492
|
-
console.error(
|
|
16824
|
+
console.error(chalk14.red(`\u2717 Invalid artifact name: "${artifactName}"`));
|
|
16493
16825
|
console.error(
|
|
16494
|
-
|
|
16826
|
+
chalk14.dim(
|
|
16495
16827
|
" Artifact names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
16496
16828
|
)
|
|
16497
16829
|
);
|
|
16498
16830
|
console.error(
|
|
16499
|
-
|
|
16831
|
+
chalk14.dim(" Example: my-project, user-workspace, code-artifact")
|
|
16500
16832
|
);
|
|
16501
16833
|
process.exit(1);
|
|
16502
16834
|
}
|
|
16503
16835
|
await writeStorageConfig(artifactName, cwd, "artifact");
|
|
16504
|
-
console.log(
|
|
16836
|
+
console.log(chalk14.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
16505
16837
|
console.log(
|
|
16506
|
-
|
|
16507
|
-
`\u2713 Config saved to ${
|
|
16838
|
+
chalk14.dim(
|
|
16839
|
+
`\u2713 Config saved to ${path10.join(cwd, ".vm0", "storage.yaml")}`
|
|
16508
16840
|
)
|
|
16509
16841
|
);
|
|
16510
16842
|
} catch (error43) {
|
|
16511
|
-
console.error(
|
|
16843
|
+
console.error(chalk14.red("\u2717 Failed to initialize artifact"));
|
|
16512
16844
|
if (error43 instanceof Error) {
|
|
16513
|
-
console.error(
|
|
16845
|
+
console.error(chalk14.dim(` ${error43.message}`));
|
|
16514
16846
|
}
|
|
16515
16847
|
process.exit(1);
|
|
16516
16848
|
}
|
|
16517
16849
|
});
|
|
16518
16850
|
|
|
16519
16851
|
// src/commands/artifact/push.ts
|
|
16520
|
-
import { Command as
|
|
16521
|
-
import
|
|
16522
|
-
function
|
|
16852
|
+
import { Command as Command11 } from "commander";
|
|
16853
|
+
import chalk15 from "chalk";
|
|
16854
|
+
function formatBytes5(bytes) {
|
|
16523
16855
|
if (bytes === 0) return "0 B";
|
|
16524
16856
|
const k = 1024;
|
|
16525
16857
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
16526
16858
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
16527
16859
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
16528
16860
|
}
|
|
16529
|
-
var pushCommand2 = new
|
|
16861
|
+
var pushCommand2 = new Command11().name("push").description("Push local files to cloud artifact").option(
|
|
16530
16862
|
"-f, --force",
|
|
16531
16863
|
"Force upload even if content unchanged (recreate archive)"
|
|
16532
16864
|
).action(async (options) => {
|
|
@@ -16534,76 +16866,76 @@ var pushCommand2 = new Command9().name("push").description("Push local files to
|
|
|
16534
16866
|
const cwd = process.cwd();
|
|
16535
16867
|
const config2 = await readStorageConfig(cwd);
|
|
16536
16868
|
if (!config2) {
|
|
16537
|
-
console.error(
|
|
16538
|
-
console.error(
|
|
16869
|
+
console.error(chalk15.red("\u2717 No artifact initialized in this directory"));
|
|
16870
|
+
console.error(chalk15.dim(" Run: vm0 artifact init"));
|
|
16539
16871
|
process.exit(1);
|
|
16540
16872
|
}
|
|
16541
16873
|
if (config2.type !== "artifact") {
|
|
16542
16874
|
console.error(
|
|
16543
|
-
|
|
16875
|
+
chalk15.red(
|
|
16544
16876
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
16545
16877
|
)
|
|
16546
16878
|
);
|
|
16547
|
-
console.error(
|
|
16879
|
+
console.error(chalk15.dim(" Use: vm0 volume push"));
|
|
16548
16880
|
process.exit(1);
|
|
16549
16881
|
}
|
|
16550
16882
|
console.log(`Pushing artifact: ${config2.name}`);
|
|
16551
16883
|
const result = await directUpload(config2.name, "artifact", cwd, {
|
|
16552
16884
|
onProgress: (message) => {
|
|
16553
|
-
console.log(
|
|
16885
|
+
console.log(chalk15.dim(message));
|
|
16554
16886
|
},
|
|
16555
16887
|
force: options.force
|
|
16556
16888
|
});
|
|
16557
16889
|
const shortVersion = result.versionId.slice(0, 8);
|
|
16558
16890
|
if (result.empty) {
|
|
16559
|
-
console.log(
|
|
16891
|
+
console.log(chalk15.yellow("No files found (empty artifact)"));
|
|
16560
16892
|
} else if (result.deduplicated) {
|
|
16561
|
-
console.log(
|
|
16893
|
+
console.log(chalk15.green("\u2713 Content unchanged (deduplicated)"));
|
|
16562
16894
|
} else {
|
|
16563
|
-
console.log(
|
|
16895
|
+
console.log(chalk15.green("\u2713 Upload complete"));
|
|
16564
16896
|
}
|
|
16565
|
-
console.log(
|
|
16566
|
-
console.log(
|
|
16567
|
-
console.log(
|
|
16897
|
+
console.log(chalk15.dim(` Version: ${shortVersion}`));
|
|
16898
|
+
console.log(chalk15.dim(` Files: ${result.fileCount.toLocaleString()}`));
|
|
16899
|
+
console.log(chalk15.dim(` Size: ${formatBytes5(result.size)}`));
|
|
16568
16900
|
} catch (error43) {
|
|
16569
|
-
console.error(
|
|
16901
|
+
console.error(chalk15.red("\u2717 Push failed"));
|
|
16570
16902
|
if (error43 instanceof Error) {
|
|
16571
|
-
console.error(
|
|
16903
|
+
console.error(chalk15.dim(` ${error43.message}`));
|
|
16572
16904
|
}
|
|
16573
16905
|
process.exit(1);
|
|
16574
16906
|
}
|
|
16575
16907
|
});
|
|
16576
16908
|
|
|
16577
16909
|
// src/commands/artifact/pull.ts
|
|
16578
|
-
import { Command as
|
|
16579
|
-
import
|
|
16580
|
-
import
|
|
16581
|
-
import * as
|
|
16582
|
-
import * as
|
|
16583
|
-
import * as
|
|
16584
|
-
function
|
|
16910
|
+
import { Command as Command12 } from "commander";
|
|
16911
|
+
import chalk16 from "chalk";
|
|
16912
|
+
import path11 from "path";
|
|
16913
|
+
import * as fs8 from "fs";
|
|
16914
|
+
import * as os6 from "os";
|
|
16915
|
+
import * as tar5 from "tar";
|
|
16916
|
+
function formatBytes6(bytes) {
|
|
16585
16917
|
if (bytes === 0) return "0 B";
|
|
16586
16918
|
const k = 1024;
|
|
16587
16919
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
16588
16920
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
16589
16921
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
16590
16922
|
}
|
|
16591
|
-
var pullCommand2 = new
|
|
16923
|
+
var pullCommand2 = new Command12().name("pull").description("Pull cloud artifact to local directory").argument("[versionId]", "Version ID to pull (default: latest)").action(async (versionId) => {
|
|
16592
16924
|
try {
|
|
16593
16925
|
const cwd = process.cwd();
|
|
16594
16926
|
const config2 = await readStorageConfig(cwd);
|
|
16595
16927
|
if (!config2) {
|
|
16596
|
-
console.error(
|
|
16597
|
-
console.error(
|
|
16928
|
+
console.error(chalk16.red("\u2717 No artifact initialized in this directory"));
|
|
16929
|
+
console.error(chalk16.dim(" Run: vm0 artifact init"));
|
|
16598
16930
|
process.exit(1);
|
|
16599
16931
|
}
|
|
16600
16932
|
if (config2.type !== "artifact") {
|
|
16601
16933
|
console.error(
|
|
16602
|
-
|
|
16934
|
+
chalk16.red(
|
|
16603
16935
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
16604
16936
|
)
|
|
16605
16937
|
);
|
|
16606
|
-
console.error(
|
|
16938
|
+
console.error(chalk16.dim(" Use: vm0 volume pull"));
|
|
16607
16939
|
process.exit(1);
|
|
16608
16940
|
}
|
|
16609
16941
|
if (versionId) {
|
|
@@ -16611,7 +16943,7 @@ var pullCommand2 = new Command10().name("pull").description("Pull cloud artifact
|
|
|
16611
16943
|
} else {
|
|
16612
16944
|
console.log(`Pulling artifact: ${config2.name}`);
|
|
16613
16945
|
}
|
|
16614
|
-
console.log(
|
|
16946
|
+
console.log(chalk16.dim("Getting download URL..."));
|
|
16615
16947
|
let url2 = `/api/storages/download?name=${encodeURIComponent(config2.name)}&type=artifact`;
|
|
16616
16948
|
if (versionId) {
|
|
16617
16949
|
url2 += `&version=${encodeURIComponent(versionId)}`;
|
|
@@ -16619,14 +16951,14 @@ var pullCommand2 = new Command10().name("pull").description("Pull cloud artifact
|
|
|
16619
16951
|
const response = await apiClient.get(url2);
|
|
16620
16952
|
if (!response.ok) {
|
|
16621
16953
|
if (response.status === 404) {
|
|
16622
|
-
console.error(
|
|
16954
|
+
console.error(chalk16.red(`\u2717 Artifact "${config2.name}" not found`));
|
|
16623
16955
|
console.error(
|
|
16624
|
-
|
|
16956
|
+
chalk16.dim(
|
|
16625
16957
|
" Make sure the artifact name is correct in .vm0/storage.yaml"
|
|
16626
16958
|
)
|
|
16627
16959
|
);
|
|
16628
16960
|
console.error(
|
|
16629
|
-
|
|
16961
|
+
chalk16.dim(" Or push the artifact first with: vm0 artifact push")
|
|
16630
16962
|
);
|
|
16631
16963
|
} else {
|
|
16632
16964
|
const error43 = await response.json();
|
|
@@ -16642,18 +16974,18 @@ var pullCommand2 = new Command10().name("pull").description("Pull cloud artifact
|
|
|
16642
16974
|
if (!downloadInfo.url) {
|
|
16643
16975
|
throw new Error("No download URL returned");
|
|
16644
16976
|
}
|
|
16645
|
-
console.log(
|
|
16977
|
+
console.log(chalk16.dim("Downloading from S3..."));
|
|
16646
16978
|
const s3Response = await fetch(downloadInfo.url);
|
|
16647
16979
|
if (!s3Response.ok) {
|
|
16648
16980
|
throw new Error(`S3 download failed: ${s3Response.status}`);
|
|
16649
16981
|
}
|
|
16650
16982
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
16651
16983
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
16652
|
-
console.log(
|
|
16653
|
-
const tmpDir =
|
|
16654
|
-
const tarPath =
|
|
16655
|
-
await
|
|
16656
|
-
console.log(
|
|
16984
|
+
console.log(chalk16.green(`\u2713 Downloaded ${formatBytes6(tarBuffer.length)}`));
|
|
16985
|
+
const tmpDir = fs8.mkdtempSync(path11.join(os6.tmpdir(), "vm0-"));
|
|
16986
|
+
const tarPath = path11.join(tmpDir, "artifact.tar.gz");
|
|
16987
|
+
await fs8.promises.writeFile(tarPath, tarBuffer);
|
|
16988
|
+
console.log(chalk16.dim("Syncing local files..."));
|
|
16657
16989
|
const remoteFiles = await listTarFiles(tarPath);
|
|
16658
16990
|
const remoteFilesSet = new Set(
|
|
16659
16991
|
remoteFiles.map((f) => f.replace(/\\/g, "/"))
|
|
@@ -16661,53 +16993,53 @@ var pullCommand2 = new Command10().name("pull").description("Pull cloud artifact
|
|
|
16661
16993
|
const removedCount = await removeExtraFiles(cwd, remoteFilesSet);
|
|
16662
16994
|
if (removedCount > 0) {
|
|
16663
16995
|
console.log(
|
|
16664
|
-
|
|
16996
|
+
chalk16.green(`\u2713 Removed ${removedCount} files not in remote`)
|
|
16665
16997
|
);
|
|
16666
16998
|
}
|
|
16667
|
-
console.log(
|
|
16668
|
-
await
|
|
16999
|
+
console.log(chalk16.dim("Extracting files..."));
|
|
17000
|
+
await tar5.extract({
|
|
16669
17001
|
file: tarPath,
|
|
16670
17002
|
cwd,
|
|
16671
17003
|
gzip: true
|
|
16672
17004
|
});
|
|
16673
|
-
await
|
|
16674
|
-
await
|
|
16675
|
-
console.log(
|
|
17005
|
+
await fs8.promises.unlink(tarPath);
|
|
17006
|
+
await fs8.promises.rmdir(tmpDir);
|
|
17007
|
+
console.log(chalk16.green(`\u2713 Extracted ${remoteFiles.length} files`));
|
|
16676
17008
|
} catch (error43) {
|
|
16677
|
-
console.error(
|
|
17009
|
+
console.error(chalk16.red("\u2717 Pull failed"));
|
|
16678
17010
|
if (error43 instanceof Error) {
|
|
16679
|
-
console.error(
|
|
17011
|
+
console.error(chalk16.dim(` ${error43.message}`));
|
|
16680
17012
|
}
|
|
16681
17013
|
process.exit(1);
|
|
16682
17014
|
}
|
|
16683
17015
|
});
|
|
16684
17016
|
|
|
16685
17017
|
// src/commands/artifact/status.ts
|
|
16686
|
-
import { Command as
|
|
16687
|
-
import
|
|
16688
|
-
function
|
|
17018
|
+
import { Command as Command13 } from "commander";
|
|
17019
|
+
import chalk17 from "chalk";
|
|
17020
|
+
function formatBytes7(bytes) {
|
|
16689
17021
|
if (bytes === 0) return "0 B";
|
|
16690
17022
|
const k = 1024;
|
|
16691
17023
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
16692
17024
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
16693
17025
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
16694
17026
|
}
|
|
16695
|
-
var statusCommand2 = new
|
|
17027
|
+
var statusCommand2 = new Command13().name("status").description("Show status of cloud artifact").action(async () => {
|
|
16696
17028
|
try {
|
|
16697
17029
|
const cwd = process.cwd();
|
|
16698
17030
|
const config2 = await readStorageConfig(cwd);
|
|
16699
17031
|
if (!config2) {
|
|
16700
|
-
console.error(
|
|
16701
|
-
console.error(
|
|
17032
|
+
console.error(chalk17.red("\u2717 No artifact initialized in this directory"));
|
|
17033
|
+
console.error(chalk17.dim(" Run: vm0 artifact init"));
|
|
16702
17034
|
process.exit(1);
|
|
16703
17035
|
}
|
|
16704
17036
|
if (config2.type !== "artifact") {
|
|
16705
17037
|
console.error(
|
|
16706
|
-
|
|
17038
|
+
chalk17.red(
|
|
16707
17039
|
"\u2717 This directory is initialized as a volume, not an artifact"
|
|
16708
17040
|
)
|
|
16709
17041
|
);
|
|
16710
|
-
console.error(
|
|
17042
|
+
console.error(chalk17.dim(" Use: vm0 volume status"));
|
|
16711
17043
|
process.exit(1);
|
|
16712
17044
|
}
|
|
16713
17045
|
console.log(`Checking artifact: ${config2.name}`);
|
|
@@ -16715,8 +17047,8 @@ var statusCommand2 = new Command11().name("status").description("Show status of
|
|
|
16715
17047
|
const response = await apiClient.get(url2);
|
|
16716
17048
|
if (!response.ok) {
|
|
16717
17049
|
if (response.status === 404) {
|
|
16718
|
-
console.error(
|
|
16719
|
-
console.error(
|
|
17050
|
+
console.error(chalk17.red("\u2717 Not found on remote"));
|
|
17051
|
+
console.error(chalk17.dim(" Run: vm0 artifact push"));
|
|
16720
17052
|
} else {
|
|
16721
17053
|
const error43 = await response.json();
|
|
16722
17054
|
throw new Error(error43.error?.message || "Status check failed");
|
|
@@ -16726,32 +17058,116 @@ var statusCommand2 = new Command11().name("status").description("Show status of
|
|
|
16726
17058
|
const info = await response.json();
|
|
16727
17059
|
const shortVersion = info.versionId.slice(0, 8);
|
|
16728
17060
|
if (info.empty) {
|
|
16729
|
-
console.log(
|
|
16730
|
-
console.log(
|
|
17061
|
+
console.log(chalk17.green("\u2713 Found (empty)"));
|
|
17062
|
+
console.log(chalk17.dim(` Version: ${shortVersion}`));
|
|
16731
17063
|
} else {
|
|
16732
|
-
console.log(
|
|
16733
|
-
console.log(
|
|
16734
|
-
console.log(
|
|
16735
|
-
console.log(
|
|
17064
|
+
console.log(chalk17.green("\u2713 Found"));
|
|
17065
|
+
console.log(chalk17.dim(` Version: ${shortVersion}`));
|
|
17066
|
+
console.log(chalk17.dim(` Files: ${info.fileCount.toLocaleString()}`));
|
|
17067
|
+
console.log(chalk17.dim(` Size: ${formatBytes7(info.size)}`));
|
|
16736
17068
|
}
|
|
16737
17069
|
} catch (error43) {
|
|
16738
|
-
console.error(
|
|
17070
|
+
console.error(chalk17.red("\u2717 Status check failed"));
|
|
16739
17071
|
if (error43 instanceof Error) {
|
|
16740
|
-
console.error(
|
|
17072
|
+
console.error(chalk17.dim(` ${error43.message}`));
|
|
17073
|
+
}
|
|
17074
|
+
process.exit(1);
|
|
17075
|
+
}
|
|
17076
|
+
});
|
|
17077
|
+
|
|
17078
|
+
// src/commands/artifact/list.ts
|
|
17079
|
+
import { Command as Command14 } from "commander";
|
|
17080
|
+
import chalk18 from "chalk";
|
|
17081
|
+
var listCommand2 = new Command14().name("list").alias("ls").description("List all remote artifacts").action(async () => {
|
|
17082
|
+
try {
|
|
17083
|
+
const url2 = "/api/storages/list?type=artifact";
|
|
17084
|
+
const response = await apiClient.get(url2);
|
|
17085
|
+
if (!response.ok) {
|
|
17086
|
+
const error43 = await response.json();
|
|
17087
|
+
throw new Error(error43.error?.message || "List failed");
|
|
17088
|
+
}
|
|
17089
|
+
const items = await response.json();
|
|
17090
|
+
if (items.length === 0) {
|
|
17091
|
+
console.log(chalk18.dim("No artifacts found"));
|
|
17092
|
+
console.log(
|
|
17093
|
+
chalk18.dim(
|
|
17094
|
+
" Create one with: vm0 artifact init && vm0 artifact push"
|
|
17095
|
+
)
|
|
17096
|
+
);
|
|
17097
|
+
return;
|
|
17098
|
+
}
|
|
17099
|
+
const nameWidth = Math.max(4, ...items.map((i) => i.name.length));
|
|
17100
|
+
const sizeWidth = Math.max(
|
|
17101
|
+
4,
|
|
17102
|
+
...items.map((i) => formatBytes(i.size).length)
|
|
17103
|
+
);
|
|
17104
|
+
const filesWidth = Math.max(
|
|
17105
|
+
5,
|
|
17106
|
+
...items.map((i) => i.fileCount.toString().length)
|
|
17107
|
+
);
|
|
17108
|
+
const header = [
|
|
17109
|
+
"NAME".padEnd(nameWidth),
|
|
17110
|
+
"SIZE".padStart(sizeWidth),
|
|
17111
|
+
"FILES".padStart(filesWidth),
|
|
17112
|
+
"UPDATED"
|
|
17113
|
+
].join(" ");
|
|
17114
|
+
console.log(chalk18.dim(header));
|
|
17115
|
+
for (const item of items) {
|
|
17116
|
+
const row = [
|
|
17117
|
+
item.name.padEnd(nameWidth),
|
|
17118
|
+
formatBytes(item.size).padStart(sizeWidth),
|
|
17119
|
+
item.fileCount.toString().padStart(filesWidth),
|
|
17120
|
+
formatRelativeTime(item.updatedAt)
|
|
17121
|
+
].join(" ");
|
|
17122
|
+
console.log(row);
|
|
17123
|
+
}
|
|
17124
|
+
} catch (error43) {
|
|
17125
|
+
console.error(chalk18.red("\u2717 Failed to list artifacts"));
|
|
17126
|
+
if (error43 instanceof Error) {
|
|
17127
|
+
if (error43.message.includes("Not authenticated")) {
|
|
17128
|
+
console.error(chalk18.dim(" Run: vm0 auth login"));
|
|
17129
|
+
} else {
|
|
17130
|
+
console.error(chalk18.dim(` ${error43.message}`));
|
|
17131
|
+
}
|
|
17132
|
+
}
|
|
17133
|
+
process.exit(1);
|
|
17134
|
+
}
|
|
17135
|
+
});
|
|
17136
|
+
|
|
17137
|
+
// src/commands/artifact/clone.ts
|
|
17138
|
+
import { Command as Command15 } from "commander";
|
|
17139
|
+
import chalk19 from "chalk";
|
|
17140
|
+
var cloneCommand2 = new Command15().name("clone").description("Clone a remote artifact to local directory (latest version)").argument("<name>", "Artifact name to clone").argument("[destination]", "Destination directory (default: artifact name)").action(async (name, destination) => {
|
|
17141
|
+
try {
|
|
17142
|
+
const targetDir = destination || name;
|
|
17143
|
+
console.log(`Cloning artifact: ${name}`);
|
|
17144
|
+
const result = await cloneStorage(name, "artifact", targetDir);
|
|
17145
|
+
console.log(chalk19.green(`
|
|
17146
|
+
\u2713 Successfully cloned artifact: ${name}`));
|
|
17147
|
+
console.log(chalk19.dim(` Location: ${targetDir}/`));
|
|
17148
|
+
console.log(chalk19.dim(` Version: ${result.versionId.slice(0, 8)}`));
|
|
17149
|
+
} catch (error43) {
|
|
17150
|
+
console.error(chalk19.red("\u2717 Clone failed"));
|
|
17151
|
+
if (error43 instanceof Error) {
|
|
17152
|
+
if (error43.message.includes("Not authenticated")) {
|
|
17153
|
+
console.error(chalk19.dim(" Run: vm0 auth login"));
|
|
17154
|
+
} else {
|
|
17155
|
+
console.error(chalk19.dim(` ${error43.message}`));
|
|
17156
|
+
}
|
|
16741
17157
|
}
|
|
16742
17158
|
process.exit(1);
|
|
16743
17159
|
}
|
|
16744
17160
|
});
|
|
16745
17161
|
|
|
16746
17162
|
// src/commands/artifact/index.ts
|
|
16747
|
-
var artifactCommand = new
|
|
17163
|
+
var artifactCommand = new Command16().name("artifact").description("Manage cloud artifacts (work products)").addCommand(initCommand2).addCommand(pushCommand2).addCommand(pullCommand2).addCommand(statusCommand2).addCommand(listCommand2).addCommand(cloneCommand2);
|
|
16748
17164
|
|
|
16749
17165
|
// src/commands/cook.ts
|
|
16750
|
-
import { Command as
|
|
16751
|
-
import
|
|
17166
|
+
import { Command as Command17 } from "commander";
|
|
17167
|
+
import chalk21 from "chalk";
|
|
16752
17168
|
import { readFile as readFile7, mkdir as mkdir6, writeFile as writeFile6, appendFile } from "fs/promises";
|
|
16753
|
-
import { existsSync as
|
|
16754
|
-
import
|
|
17169
|
+
import { existsSync as existsSync8, readFileSync } from "fs";
|
|
17170
|
+
import path12 from "path";
|
|
16755
17171
|
import { spawn as spawn2 } from "child_process";
|
|
16756
17172
|
import { parse as parseYaml4 } from "yaml";
|
|
16757
17173
|
import { config as dotenvConfig2 } from "dotenv";
|
|
@@ -16759,7 +17175,7 @@ import { config as dotenvConfig2 } from "dotenv";
|
|
|
16759
17175
|
// src/lib/update-checker.ts
|
|
16760
17176
|
import https from "https";
|
|
16761
17177
|
import { spawn } from "child_process";
|
|
16762
|
-
import
|
|
17178
|
+
import chalk20 from "chalk";
|
|
16763
17179
|
var PACKAGE_NAME = "@vm0/cli";
|
|
16764
17180
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`;
|
|
16765
17181
|
var TIMEOUT_MS = 5e3;
|
|
@@ -16824,21 +17240,21 @@ function performUpgrade(packageManager) {
|
|
|
16824
17240
|
async function checkAndUpgrade(currentVersion, prompt) {
|
|
16825
17241
|
const latestVersion = await getLatestVersion();
|
|
16826
17242
|
if (latestVersion === null) {
|
|
16827
|
-
console.log(
|
|
17243
|
+
console.log(chalk20.yellow("Warning: Could not check for updates"));
|
|
16828
17244
|
console.log();
|
|
16829
17245
|
return false;
|
|
16830
17246
|
}
|
|
16831
17247
|
if (latestVersion === currentVersion) {
|
|
16832
17248
|
return false;
|
|
16833
17249
|
}
|
|
16834
|
-
console.log(
|
|
17250
|
+
console.log(chalk20.yellow("vm0 is currently in Early Access (EA)."));
|
|
16835
17251
|
console.log(
|
|
16836
|
-
|
|
17252
|
+
chalk20.yellow(
|
|
16837
17253
|
`Current version: ${currentVersion} -> Latest version: ${latestVersion}`
|
|
16838
17254
|
)
|
|
16839
17255
|
);
|
|
16840
17256
|
console.log(
|
|
16841
|
-
|
|
17257
|
+
chalk20.yellow(
|
|
16842
17258
|
"Please always use the latest version for best compatibility."
|
|
16843
17259
|
)
|
|
16844
17260
|
);
|
|
@@ -16847,20 +17263,20 @@ async function checkAndUpgrade(currentVersion, prompt) {
|
|
|
16847
17263
|
console.log(`Upgrading via ${packageManager}...`);
|
|
16848
17264
|
const success2 = await performUpgrade(packageManager);
|
|
16849
17265
|
if (success2) {
|
|
16850
|
-
console.log(
|
|
17266
|
+
console.log(chalk20.green(`Upgraded to ${latestVersion}`));
|
|
16851
17267
|
console.log();
|
|
16852
17268
|
console.log("To continue, run:");
|
|
16853
|
-
console.log(
|
|
17269
|
+
console.log(chalk20.cyan(` ${buildRerunCommand(prompt)}`));
|
|
16854
17270
|
return true;
|
|
16855
17271
|
}
|
|
16856
17272
|
console.log();
|
|
16857
|
-
console.log(
|
|
16858
|
-
console.log(
|
|
16859
|
-
console.log(
|
|
16860
|
-
console.log(
|
|
17273
|
+
console.log(chalk20.red("Upgrade failed. Please run manually:"));
|
|
17274
|
+
console.log(chalk20.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
17275
|
+
console.log(chalk20.dim(" # or"));
|
|
17276
|
+
console.log(chalk20.cyan(` pnpm add -g ${PACKAGE_NAME}@latest`));
|
|
16861
17277
|
console.log();
|
|
16862
17278
|
console.log("Then re-run:");
|
|
16863
|
-
console.log(
|
|
17279
|
+
console.log(chalk20.cyan(` ${buildRerunCommand(prompt)}`));
|
|
16864
17280
|
return true;
|
|
16865
17281
|
}
|
|
16866
17282
|
|
|
@@ -16868,12 +17284,12 @@ async function checkAndUpgrade(currentVersion, prompt) {
|
|
|
16868
17284
|
import { homedir as homedir2 } from "os";
|
|
16869
17285
|
import { join as join6 } from "path";
|
|
16870
17286
|
import { readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
|
|
16871
|
-
import { existsSync as
|
|
17287
|
+
import { existsSync as existsSync7 } from "fs";
|
|
16872
17288
|
var CONFIG_DIR3 = join6(homedir2(), ".vm0");
|
|
16873
17289
|
var COOK_STATE_FILE = join6(CONFIG_DIR3, "cook.json");
|
|
16874
17290
|
var STALE_THRESHOLD_MS = 48 * 60 * 60 * 1e3;
|
|
16875
17291
|
async function loadCookStateFile() {
|
|
16876
|
-
if (!
|
|
17292
|
+
if (!existsSync7(COOK_STATE_FILE)) {
|
|
16877
17293
|
return { ppid: {} };
|
|
16878
17294
|
}
|
|
16879
17295
|
try {
|
|
@@ -16933,7 +17349,7 @@ async function saveCookState(state) {
|
|
|
16933
17349
|
var CONFIG_FILE3 = "vm0.yaml";
|
|
16934
17350
|
var ARTIFACT_DIR = "artifact";
|
|
16935
17351
|
function printCommand(cmd) {
|
|
16936
|
-
console.log(
|
|
17352
|
+
console.log(chalk21.dim(`> ${cmd}`));
|
|
16937
17353
|
}
|
|
16938
17354
|
function execVm0Command(args, options = {}) {
|
|
16939
17355
|
return new Promise((resolve2, reject) => {
|
|
@@ -17034,7 +17450,7 @@ function extractRequiredVarNames(config2) {
|
|
|
17034
17450
|
}
|
|
17035
17451
|
function checkMissingVariables(varNames, envFilePath) {
|
|
17036
17452
|
let dotenvValues = {};
|
|
17037
|
-
if (
|
|
17453
|
+
if (existsSync8(envFilePath)) {
|
|
17038
17454
|
const result = dotenvConfig2({ path: envFilePath, quiet: true });
|
|
17039
17455
|
if (result.parsed) {
|
|
17040
17456
|
dotenvValues = result.parsed;
|
|
@@ -17052,7 +17468,7 @@ function checkMissingVariables(varNames, envFilePath) {
|
|
|
17052
17468
|
}
|
|
17053
17469
|
async function generateEnvPlaceholders(missingVars, envFilePath) {
|
|
17054
17470
|
const placeholders = missingVars.map((name) => `${name}=`).join("\n");
|
|
17055
|
-
if (
|
|
17471
|
+
if (existsSync8(envFilePath)) {
|
|
17056
17472
|
const existingContent = readFileSync(envFilePath, "utf8");
|
|
17057
17473
|
const needsNewline = existingContent.length > 0 && !existingContent.endsWith("\n");
|
|
17058
17474
|
const prefix = needsNewline ? "\n" : "";
|
|
@@ -17068,9 +17484,9 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
17068
17484
|
runOutput,
|
|
17069
17485
|
ARTIFACT_DIR
|
|
17070
17486
|
);
|
|
17071
|
-
if (serverVersion &&
|
|
17487
|
+
if (serverVersion && existsSync8(artifactDir)) {
|
|
17072
17488
|
console.log();
|
|
17073
|
-
console.log(
|
|
17489
|
+
console.log(chalk21.bold("Pulling updated artifact:"));
|
|
17074
17490
|
printCommand(`cd ${ARTIFACT_DIR}`);
|
|
17075
17491
|
printCommand(`vm0 artifact pull ${serverVersion}`);
|
|
17076
17492
|
try {
|
|
@@ -17080,23 +17496,23 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
17080
17496
|
});
|
|
17081
17497
|
printCommand("cd ..");
|
|
17082
17498
|
} catch (error43) {
|
|
17083
|
-
console.error(
|
|
17499
|
+
console.error(chalk21.red(`\u2717 Artifact pull failed`));
|
|
17084
17500
|
if (error43 instanceof Error) {
|
|
17085
|
-
console.error(
|
|
17501
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17086
17502
|
}
|
|
17087
17503
|
}
|
|
17088
17504
|
}
|
|
17089
17505
|
}
|
|
17090
|
-
var cookCmd = new
|
|
17506
|
+
var cookCmd = new Command17().name("cook").description("One-click agent preparation and execution from vm0.yaml");
|
|
17091
17507
|
cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
17092
|
-
const shouldExit = await checkAndUpgrade("4.
|
|
17508
|
+
const shouldExit = await checkAndUpgrade("4.32.0", prompt);
|
|
17093
17509
|
if (shouldExit) {
|
|
17094
17510
|
process.exit(0);
|
|
17095
17511
|
}
|
|
17096
17512
|
const cwd = process.cwd();
|
|
17097
|
-
console.log(
|
|
17098
|
-
if (!
|
|
17099
|
-
console.error(
|
|
17513
|
+
console.log(chalk21.bold(`Reading config: ${CONFIG_FILE3}`));
|
|
17514
|
+
if (!existsSync8(CONFIG_FILE3)) {
|
|
17515
|
+
console.error(chalk21.red(`\u2717 Config file not found: ${CONFIG_FILE3}`));
|
|
17100
17516
|
process.exit(1);
|
|
17101
17517
|
}
|
|
17102
17518
|
let config2;
|
|
@@ -17104,49 +17520,49 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
17104
17520
|
const content = await readFile7(CONFIG_FILE3, "utf8");
|
|
17105
17521
|
config2 = parseYaml4(content);
|
|
17106
17522
|
} catch (error43) {
|
|
17107
|
-
console.error(
|
|
17523
|
+
console.error(chalk21.red("\u2717 Invalid YAML format"));
|
|
17108
17524
|
if (error43 instanceof Error) {
|
|
17109
|
-
console.error(
|
|
17525
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17110
17526
|
}
|
|
17111
17527
|
process.exit(1);
|
|
17112
17528
|
}
|
|
17113
17529
|
const validation = validateAgentCompose(config2);
|
|
17114
17530
|
if (!validation.valid) {
|
|
17115
|
-
console.error(
|
|
17531
|
+
console.error(chalk21.red(`\u2717 ${validation.error}`));
|
|
17116
17532
|
process.exit(1);
|
|
17117
17533
|
}
|
|
17118
17534
|
const agentNames = Object.keys(config2.agents);
|
|
17119
17535
|
const agentName = agentNames[0];
|
|
17120
17536
|
const volumeCount = config2.volumes ? Object.keys(config2.volumes).length : 0;
|
|
17121
17537
|
console.log(
|
|
17122
|
-
|
|
17538
|
+
chalk21.green(`\u2713 Config validated: 1 agent, ${volumeCount} volume(s)`)
|
|
17123
17539
|
);
|
|
17124
17540
|
const requiredVarNames = extractRequiredVarNames(config2);
|
|
17125
17541
|
if (requiredVarNames.length > 0) {
|
|
17126
|
-
const envFilePath =
|
|
17542
|
+
const envFilePath = path12.join(cwd, ".env");
|
|
17127
17543
|
const missingVars = checkMissingVariables(requiredVarNames, envFilePath);
|
|
17128
17544
|
if (missingVars.length > 0) {
|
|
17129
17545
|
await generateEnvPlaceholders(missingVars, envFilePath);
|
|
17130
17546
|
console.log();
|
|
17131
17547
|
console.log(
|
|
17132
|
-
|
|
17548
|
+
chalk21.yellow(
|
|
17133
17549
|
`\u26A0 Missing environment variables. Please fill in values in .env file:`
|
|
17134
17550
|
)
|
|
17135
17551
|
);
|
|
17136
17552
|
for (const varName of missingVars) {
|
|
17137
|
-
console.log(
|
|
17553
|
+
console.log(chalk21.yellow(` ${varName}`));
|
|
17138
17554
|
}
|
|
17139
17555
|
process.exit(1);
|
|
17140
17556
|
}
|
|
17141
17557
|
}
|
|
17142
17558
|
if (config2.volumes && Object.keys(config2.volumes).length > 0) {
|
|
17143
17559
|
console.log();
|
|
17144
|
-
console.log(
|
|
17560
|
+
console.log(chalk21.bold("Processing volumes:"));
|
|
17145
17561
|
for (const volumeConfig of Object.values(config2.volumes)) {
|
|
17146
|
-
const volumeDir =
|
|
17147
|
-
if (!
|
|
17562
|
+
const volumeDir = path12.join(cwd, volumeConfig.name);
|
|
17563
|
+
if (!existsSync8(volumeDir)) {
|
|
17148
17564
|
console.error(
|
|
17149
|
-
|
|
17565
|
+
chalk21.red(
|
|
17150
17566
|
`\u2717 Directory not found: ${volumeConfig.name}. Create the directory and add files first.`
|
|
17151
17567
|
)
|
|
17152
17568
|
);
|
|
@@ -17156,11 +17572,14 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
17156
17572
|
printCommand(`cd ${volumeConfig.name}`);
|
|
17157
17573
|
const existingConfig = await readStorageConfig(volumeDir);
|
|
17158
17574
|
if (!existingConfig) {
|
|
17159
|
-
printCommand(
|
|
17160
|
-
await execVm0Command(
|
|
17161
|
-
|
|
17162
|
-
|
|
17163
|
-
|
|
17575
|
+
printCommand(`vm0 volume init --name ${volumeConfig.name}`);
|
|
17576
|
+
await execVm0Command(
|
|
17577
|
+
["volume", "init", "--name", volumeConfig.name],
|
|
17578
|
+
{
|
|
17579
|
+
cwd: volumeDir,
|
|
17580
|
+
silent: true
|
|
17581
|
+
}
|
|
17582
|
+
);
|
|
17164
17583
|
}
|
|
17165
17584
|
printCommand("vm0 volume push");
|
|
17166
17585
|
await execVm0Command(["volume", "push"], {
|
|
@@ -17169,27 +17588,27 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
17169
17588
|
});
|
|
17170
17589
|
printCommand("cd ..");
|
|
17171
17590
|
} catch (error43) {
|
|
17172
|
-
console.error(
|
|
17591
|
+
console.error(chalk21.red(`\u2717 Failed`));
|
|
17173
17592
|
if (error43 instanceof Error) {
|
|
17174
|
-
console.error(
|
|
17593
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17175
17594
|
}
|
|
17176
17595
|
process.exit(1);
|
|
17177
17596
|
}
|
|
17178
17597
|
}
|
|
17179
17598
|
}
|
|
17180
17599
|
console.log();
|
|
17181
|
-
console.log(
|
|
17182
|
-
const artifactDir =
|
|
17600
|
+
console.log(chalk21.bold("Processing artifact:"));
|
|
17601
|
+
const artifactDir = path12.join(cwd, ARTIFACT_DIR);
|
|
17183
17602
|
try {
|
|
17184
|
-
if (!
|
|
17603
|
+
if (!existsSync8(artifactDir)) {
|
|
17185
17604
|
printCommand(`mkdir ${ARTIFACT_DIR}`);
|
|
17186
17605
|
await mkdir6(artifactDir, { recursive: true });
|
|
17187
17606
|
}
|
|
17188
17607
|
printCommand(`cd ${ARTIFACT_DIR}`);
|
|
17189
17608
|
const existingConfig = await readStorageConfig(artifactDir);
|
|
17190
17609
|
if (!existingConfig) {
|
|
17191
|
-
printCommand(
|
|
17192
|
-
await execVm0Command(["artifact", "init"], {
|
|
17610
|
+
printCommand(`vm0 artifact init --name ${ARTIFACT_DIR}`);
|
|
17611
|
+
await execVm0Command(["artifact", "init", "--name", ARTIFACT_DIR], {
|
|
17193
17612
|
cwd: artifactDir,
|
|
17194
17613
|
silent: true
|
|
17195
17614
|
});
|
|
@@ -17201,29 +17620,29 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
17201
17620
|
});
|
|
17202
17621
|
printCommand("cd ..");
|
|
17203
17622
|
} catch (error43) {
|
|
17204
|
-
console.error(
|
|
17623
|
+
console.error(chalk21.red(`\u2717 Failed`));
|
|
17205
17624
|
if (error43 instanceof Error) {
|
|
17206
|
-
console.error(
|
|
17625
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17207
17626
|
}
|
|
17208
17627
|
process.exit(1);
|
|
17209
17628
|
}
|
|
17210
17629
|
console.log();
|
|
17211
|
-
console.log(
|
|
17630
|
+
console.log(chalk21.bold("Composing agent:"));
|
|
17212
17631
|
printCommand(`vm0 compose ${CONFIG_FILE3}`);
|
|
17213
17632
|
try {
|
|
17214
17633
|
await execVm0Command(["compose", CONFIG_FILE3], {
|
|
17215
17634
|
cwd
|
|
17216
17635
|
});
|
|
17217
17636
|
} catch (error43) {
|
|
17218
|
-
console.error(
|
|
17637
|
+
console.error(chalk21.red(`\u2717 Compose failed`));
|
|
17219
17638
|
if (error43 instanceof Error) {
|
|
17220
|
-
console.error(
|
|
17639
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17221
17640
|
}
|
|
17222
17641
|
process.exit(1);
|
|
17223
17642
|
}
|
|
17224
17643
|
if (prompt) {
|
|
17225
17644
|
console.log();
|
|
17226
|
-
console.log(
|
|
17645
|
+
console.log(chalk21.bold("Running agent:"));
|
|
17227
17646
|
printCommand(
|
|
17228
17647
|
`vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "${prompt}"`
|
|
17229
17648
|
);
|
|
@@ -17265,8 +17684,8 @@ cookCmd.command("logs").description("View logs from the last cook run").option("
|
|
|
17265
17684
|
async (options) => {
|
|
17266
17685
|
const state = await loadCookState();
|
|
17267
17686
|
if (!state.lastRunId) {
|
|
17268
|
-
console.error(
|
|
17269
|
-
console.error(
|
|
17687
|
+
console.error(chalk21.red("\u2717 No previous run found"));
|
|
17688
|
+
console.error(chalk21.dim(" Run 'vm0 cook <prompt>' first"));
|
|
17270
17689
|
process.exit(1);
|
|
17271
17690
|
}
|
|
17272
17691
|
const args = ["logs", state.lastRunId];
|
|
@@ -17308,12 +17727,12 @@ cookCmd.command("continue").description(
|
|
|
17308
17727
|
).argument("<prompt>", "Prompt for the continued agent").action(async (prompt) => {
|
|
17309
17728
|
const state = await loadCookState();
|
|
17310
17729
|
if (!state.lastSessionId) {
|
|
17311
|
-
console.error(
|
|
17312
|
-
console.error(
|
|
17730
|
+
console.error(chalk21.red("\u2717 No previous session found"));
|
|
17731
|
+
console.error(chalk21.dim(" Run 'vm0 cook <prompt>' first"));
|
|
17313
17732
|
process.exit(1);
|
|
17314
17733
|
}
|
|
17315
17734
|
const cwd = process.cwd();
|
|
17316
|
-
const artifactDir =
|
|
17735
|
+
const artifactDir = path12.join(cwd, ARTIFACT_DIR);
|
|
17317
17736
|
printCommand(`vm0 run continue ${state.lastSessionId} "${prompt}"`);
|
|
17318
17737
|
console.log();
|
|
17319
17738
|
let runOutput;
|
|
@@ -17340,12 +17759,12 @@ cookCmd.command("resume").description(
|
|
|
17340
17759
|
).argument("<prompt>", "Prompt for the resumed agent").action(async (prompt) => {
|
|
17341
17760
|
const state = await loadCookState();
|
|
17342
17761
|
if (!state.lastCheckpointId) {
|
|
17343
|
-
console.error(
|
|
17344
|
-
console.error(
|
|
17762
|
+
console.error(chalk21.red("\u2717 No previous checkpoint found"));
|
|
17763
|
+
console.error(chalk21.dim(" Run 'vm0 cook <prompt>' first"));
|
|
17345
17764
|
process.exit(1);
|
|
17346
17765
|
}
|
|
17347
17766
|
const cwd = process.cwd();
|
|
17348
|
-
const artifactDir =
|
|
17767
|
+
const artifactDir = path12.join(cwd, ARTIFACT_DIR);
|
|
17349
17768
|
printCommand(`vm0 run resume ${state.lastCheckpointId} "${prompt}"`);
|
|
17350
17769
|
console.log();
|
|
17351
17770
|
let runOutput;
|
|
@@ -17370,13 +17789,13 @@ cookCmd.command("resume").description(
|
|
|
17370
17789
|
var cookCommand = cookCmd;
|
|
17371
17790
|
|
|
17372
17791
|
// src/commands/image/index.ts
|
|
17373
|
-
import { Command as
|
|
17792
|
+
import { Command as Command22 } from "commander";
|
|
17374
17793
|
|
|
17375
17794
|
// src/commands/image/build.ts
|
|
17376
|
-
import { Command as
|
|
17377
|
-
import
|
|
17795
|
+
import { Command as Command18 } from "commander";
|
|
17796
|
+
import chalk22 from "chalk";
|
|
17378
17797
|
import { readFile as readFile8 } from "fs/promises";
|
|
17379
|
-
import { existsSync as
|
|
17798
|
+
import { existsSync as existsSync9 } from "fs";
|
|
17380
17799
|
|
|
17381
17800
|
// src/lib/dockerfile-validator.ts
|
|
17382
17801
|
var ALLOWED_INSTRUCTIONS = /* @__PURE__ */ new Set(["FROM", "RUN"]);
|
|
@@ -17410,17 +17829,17 @@ function validateDockerfile(content) {
|
|
|
17410
17829
|
|
|
17411
17830
|
// src/commands/image/build.ts
|
|
17412
17831
|
var sleep2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
17413
|
-
var buildCommand = new
|
|
17832
|
+
var buildCommand = new Command18().name("build").description("Build a custom image from a Dockerfile").requiredOption("-f, --file <path>", "Path to Dockerfile").requiredOption("-n, --name <name>", "Name for the image").option("--delete-existing", "Delete existing image before building").action(
|
|
17414
17833
|
async (options) => {
|
|
17415
17834
|
const { file: file2, name, deleteExisting } = options;
|
|
17416
|
-
if (!
|
|
17417
|
-
console.error(
|
|
17835
|
+
if (!existsSync9(file2)) {
|
|
17836
|
+
console.error(chalk22.red(`\u2717 Dockerfile not found: ${file2}`));
|
|
17418
17837
|
process.exit(1);
|
|
17419
17838
|
}
|
|
17420
17839
|
const nameRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,62}[a-zA-Z0-9]$/;
|
|
17421
17840
|
if (!nameRegex.test(name)) {
|
|
17422
17841
|
console.error(
|
|
17423
|
-
|
|
17842
|
+
chalk22.red(
|
|
17424
17843
|
"\u2717 Invalid name format. Must be 3-64 characters, letters, numbers, and hyphens only."
|
|
17425
17844
|
)
|
|
17426
17845
|
);
|
|
@@ -17428,7 +17847,7 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17428
17847
|
}
|
|
17429
17848
|
if (name.startsWith("vm0-")) {
|
|
17430
17849
|
console.error(
|
|
17431
|
-
|
|
17850
|
+
chalk22.red(
|
|
17432
17851
|
'\u2717 Invalid name. Cannot start with "vm0-" (reserved prefix).'
|
|
17433
17852
|
)
|
|
17434
17853
|
);
|
|
@@ -17439,24 +17858,24 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17439
17858
|
const dockerfile = await readFile8(file2, "utf8");
|
|
17440
17859
|
const validation = validateDockerfile(dockerfile);
|
|
17441
17860
|
if (!validation.valid) {
|
|
17442
|
-
console.error(
|
|
17861
|
+
console.error(chalk22.red("\u2717 Dockerfile validation failed\n"));
|
|
17443
17862
|
for (const error43 of validation.errors) {
|
|
17444
|
-
console.error(
|
|
17863
|
+
console.error(chalk22.red(` ${error43}`));
|
|
17445
17864
|
}
|
|
17446
17865
|
console.error();
|
|
17447
17866
|
console.error(
|
|
17448
|
-
|
|
17867
|
+
chalk22.yellow(
|
|
17449
17868
|
" vm0 image build only supports FROM and RUN instructions."
|
|
17450
17869
|
)
|
|
17451
17870
|
);
|
|
17452
17871
|
console.error(
|
|
17453
|
-
|
|
17872
|
+
chalk22.yellow(
|
|
17454
17873
|
" The purpose is to pre-install environment dependencies."
|
|
17455
17874
|
)
|
|
17456
17875
|
);
|
|
17457
17876
|
process.exit(1);
|
|
17458
17877
|
}
|
|
17459
|
-
console.log(
|
|
17878
|
+
console.log(chalk22.bold(`Building image: ${scope.slug}/${name}`));
|
|
17460
17879
|
console.log();
|
|
17461
17880
|
const buildInfo = await apiClient.createImage({
|
|
17462
17881
|
dockerfile,
|
|
@@ -17464,7 +17883,7 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17464
17883
|
deleteExisting
|
|
17465
17884
|
});
|
|
17466
17885
|
const { imageId, buildId, versionId } = buildInfo;
|
|
17467
|
-
console.log(
|
|
17886
|
+
console.log(chalk22.dim(` Build ID: ${buildId}`));
|
|
17468
17887
|
console.log();
|
|
17469
17888
|
let logsOffset = 0;
|
|
17470
17889
|
let status = "building";
|
|
@@ -17480,7 +17899,7 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17480
17899
|
}
|
|
17481
17900
|
const statusData = await statusResponse.json();
|
|
17482
17901
|
for (const log of statusData.logs) {
|
|
17483
|
-
console.log(
|
|
17902
|
+
console.log(chalk22.dim(` ${log}`));
|
|
17484
17903
|
}
|
|
17485
17904
|
logsOffset = statusData.logsOffset;
|
|
17486
17905
|
status = statusData.status;
|
|
@@ -17492,23 +17911,23 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17492
17911
|
if (status === "ready") {
|
|
17493
17912
|
const shortVersion = formatVersionIdForDisplay(versionId);
|
|
17494
17913
|
console.log(
|
|
17495
|
-
|
|
17914
|
+
chalk22.green(`\u2713 Image built: ${scope.slug}/${name}:${shortVersion}`)
|
|
17496
17915
|
);
|
|
17497
17916
|
} else {
|
|
17498
|
-
console.error(
|
|
17917
|
+
console.error(chalk22.red(`\u2717 Build failed`));
|
|
17499
17918
|
process.exit(1);
|
|
17500
17919
|
}
|
|
17501
17920
|
} catch (error43) {
|
|
17502
17921
|
if (error43 instanceof Error) {
|
|
17503
17922
|
if (error43.message.includes("Not authenticated")) {
|
|
17504
17923
|
console.error(
|
|
17505
|
-
|
|
17924
|
+
chalk22.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
17506
17925
|
);
|
|
17507
17926
|
} else {
|
|
17508
|
-
console.error(
|
|
17927
|
+
console.error(chalk22.red(`\u2717 ${error43.message}`));
|
|
17509
17928
|
}
|
|
17510
17929
|
} else {
|
|
17511
|
-
console.error(
|
|
17930
|
+
console.error(chalk22.red("\u2717 An unexpected error occurred"));
|
|
17512
17931
|
}
|
|
17513
17932
|
process.exit(1);
|
|
17514
17933
|
}
|
|
@@ -17516,9 +17935,9 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17516
17935
|
);
|
|
17517
17936
|
|
|
17518
17937
|
// src/commands/image/list.ts
|
|
17519
|
-
import { Command as
|
|
17520
|
-
import
|
|
17521
|
-
var
|
|
17938
|
+
import { Command as Command19 } from "commander";
|
|
17939
|
+
import chalk23 from "chalk";
|
|
17940
|
+
var listCommand3 = new Command19().name("list").alias("ls").description("List your custom images").action(async () => {
|
|
17522
17941
|
try {
|
|
17523
17942
|
const response = await apiClient.get("/api/images");
|
|
17524
17943
|
if (!response.ok) {
|
|
@@ -17530,15 +17949,15 @@ var listCommand = new Command15().name("list").alias("ls").description("List you
|
|
|
17530
17949
|
const data = await response.json();
|
|
17531
17950
|
const { images } = data;
|
|
17532
17951
|
if (images.length === 0) {
|
|
17533
|
-
console.log(
|
|
17952
|
+
console.log(chalk23.dim("No images found."));
|
|
17534
17953
|
console.log();
|
|
17535
17954
|
console.log("Build your first image:");
|
|
17536
17955
|
console.log(
|
|
17537
|
-
|
|
17956
|
+
chalk23.cyan(" vm0 image build --file Dockerfile --name my-image")
|
|
17538
17957
|
);
|
|
17539
17958
|
return;
|
|
17540
17959
|
}
|
|
17541
|
-
console.log(
|
|
17960
|
+
console.log(chalk23.bold("Your images:"));
|
|
17542
17961
|
console.log();
|
|
17543
17962
|
const imagesByAlias = /* @__PURE__ */ new Map();
|
|
17544
17963
|
for (const image of images) {
|
|
@@ -17552,50 +17971,49 @@ var listCommand = new Command15().name("list").alias("ls").description("List you
|
|
|
17552
17971
|
latestVersions.set(alias, latestReady?.versionId || null);
|
|
17553
17972
|
}
|
|
17554
17973
|
console.log(
|
|
17555
|
-
|
|
17974
|
+
chalk23.dim(
|
|
17556
17975
|
`${"NAME".padEnd(40)} ${"STATUS".padEnd(12)} ${"CREATED".padEnd(20)}`
|
|
17557
17976
|
)
|
|
17558
17977
|
);
|
|
17559
|
-
console.log(
|
|
17978
|
+
console.log(chalk23.dim("-".repeat(72)));
|
|
17560
17979
|
for (const image of images) {
|
|
17561
|
-
const statusColor = image.status === "ready" ?
|
|
17980
|
+
const statusColor = image.status === "ready" ? chalk23.green : image.status === "building" ? chalk23.yellow : chalk23.red;
|
|
17562
17981
|
const createdAt = new Date(image.createdAt).toLocaleString();
|
|
17563
17982
|
let displayName = image.alias;
|
|
17564
17983
|
if (image.versionId) {
|
|
17565
17984
|
const shortVersion = formatVersionIdForDisplay(image.versionId);
|
|
17566
17985
|
displayName = `${image.alias}:${shortVersion}`;
|
|
17567
17986
|
if (image.status === "ready" && latestVersions.get(image.alias) === image.versionId) {
|
|
17568
|
-
displayName = `${displayName} ${
|
|
17987
|
+
displayName = `${displayName} ${chalk23.cyan("latest")}`;
|
|
17569
17988
|
}
|
|
17570
17989
|
}
|
|
17571
17990
|
console.log(
|
|
17572
17991
|
`${displayName.padEnd(40)} ${statusColor(image.status.padEnd(12))} ${createdAt.padEnd(20)}`
|
|
17573
17992
|
);
|
|
17574
17993
|
if (image.status === "error" && image.errorMessage) {
|
|
17575
|
-
console.log(
|
|
17994
|
+
console.log(chalk23.red(` Error: ${image.errorMessage}`));
|
|
17576
17995
|
}
|
|
17577
17996
|
}
|
|
17578
17997
|
console.log();
|
|
17579
|
-
console.log(
|
|
17998
|
+
console.log(chalk23.dim(`Total: ${images.length} version(s)`));
|
|
17580
17999
|
} catch (error43) {
|
|
17581
18000
|
if (error43 instanceof Error) {
|
|
17582
18001
|
if (error43.message.includes("Not authenticated")) {
|
|
17583
|
-
console.error(
|
|
18002
|
+
console.error(chalk23.red("Not authenticated. Run: vm0 auth login"));
|
|
17584
18003
|
} else {
|
|
17585
|
-
console.error(
|
|
18004
|
+
console.error(chalk23.red(`Error: ${error43.message}`));
|
|
17586
18005
|
}
|
|
17587
18006
|
} else {
|
|
17588
|
-
console.error(
|
|
18007
|
+
console.error(chalk23.red("An unexpected error occurred"));
|
|
17589
18008
|
}
|
|
17590
18009
|
process.exit(1);
|
|
17591
18010
|
}
|
|
17592
18011
|
});
|
|
17593
18012
|
|
|
17594
18013
|
// src/commands/image/delete.ts
|
|
17595
|
-
import { Command as
|
|
17596
|
-
import
|
|
17597
|
-
|
|
17598
|
-
var deleteCommand = new Command16().name("delete").alias("rm").description("Delete a custom image or specific version").argument("<name>", "Image name or name:version to delete").option("-f, --force", "Skip confirmation prompt").option("--all", "Delete all versions of the image").action(
|
|
18014
|
+
import { Command as Command20 } from "commander";
|
|
18015
|
+
import chalk24 from "chalk";
|
|
18016
|
+
var deleteCommand = new Command20().name("delete").alias("rm").description("Delete a custom image or specific version").argument("<name>", "Image name or name:version to delete").option("-f, --force", "Skip confirmation prompt").option("--all", "Delete all versions of the image").action(
|
|
17599
18017
|
async (nameArg, options) => {
|
|
17600
18018
|
try {
|
|
17601
18019
|
const colonIndex = nameArg.lastIndexOf(":");
|
|
@@ -17616,12 +18034,12 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17616
18034
|
(img) => img.alias === name && img.versionId && img.versionId.startsWith(versionId.toLowerCase())
|
|
17617
18035
|
);
|
|
17618
18036
|
if (matchingVersions.length === 0) {
|
|
17619
|
-
console.error(
|
|
18037
|
+
console.error(chalk24.red(`Image version not found: ${nameArg}`));
|
|
17620
18038
|
process.exit(1);
|
|
17621
18039
|
}
|
|
17622
18040
|
if (matchingVersions.length > 1) {
|
|
17623
18041
|
console.error(
|
|
17624
|
-
|
|
18042
|
+
chalk24.red(
|
|
17625
18043
|
`Ambiguous version prefix "${versionId}". Please use more characters.`
|
|
17626
18044
|
)
|
|
17627
18045
|
);
|
|
@@ -17631,7 +18049,7 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17631
18049
|
} else if (options.all) {
|
|
17632
18050
|
imagesToDelete = data.images.filter((img) => img.alias === name);
|
|
17633
18051
|
if (imagesToDelete.length === 0) {
|
|
17634
|
-
console.error(
|
|
18052
|
+
console.error(chalk24.red(`Image not found: ${name}`));
|
|
17635
18053
|
process.exit(1);
|
|
17636
18054
|
}
|
|
17637
18055
|
} else {
|
|
@@ -17639,7 +18057,7 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17639
18057
|
(img) => img.alias === name
|
|
17640
18058
|
);
|
|
17641
18059
|
if (matchingImages.length === 0) {
|
|
17642
|
-
console.error(
|
|
18060
|
+
console.error(chalk24.red(`Image not found: ${name}`));
|
|
17643
18061
|
process.exit(1);
|
|
17644
18062
|
}
|
|
17645
18063
|
const latestReady = matchingImages.find(
|
|
@@ -17655,18 +18073,9 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17655
18073
|
const firstVersionDisplay = firstImage.versionId ? `:${formatVersionIdForDisplay(firstImage.versionId)}` : "";
|
|
17656
18074
|
const confirmMsg = imagesToDelete.length === 1 ? `Delete image "${firstImage.alias}${firstVersionDisplay}"?` : `Delete ${imagesToDelete.length} versions of "${name}"?`;
|
|
17657
18075
|
if (!options.force) {
|
|
17658
|
-
const
|
|
17659
|
-
|
|
17660
|
-
|
|
17661
|
-
});
|
|
17662
|
-
const answer = await new Promise((resolve2) => {
|
|
17663
|
-
rl.question(chalk19.yellow(`${confirmMsg} [y/N] `), (answer2) => {
|
|
17664
|
-
rl.close();
|
|
17665
|
-
resolve2(answer2);
|
|
17666
|
-
});
|
|
17667
|
-
});
|
|
17668
|
-
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
17669
|
-
console.log(chalk19.dim("Cancelled."));
|
|
18076
|
+
const confirmed = await promptConfirm(confirmMsg, false);
|
|
18077
|
+
if (!confirmed) {
|
|
18078
|
+
console.log(chalk24.dim("Cancelled."));
|
|
17670
18079
|
return;
|
|
17671
18080
|
}
|
|
17672
18081
|
}
|
|
@@ -17681,17 +18090,17 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17681
18090
|
);
|
|
17682
18091
|
}
|
|
17683
18092
|
const displayName = image.versionId ? `${image.alias}:${formatVersionIdForDisplay(image.versionId)}` : image.alias;
|
|
17684
|
-
console.log(
|
|
18093
|
+
console.log(chalk24.green(`Deleted image: ${displayName}`));
|
|
17685
18094
|
}
|
|
17686
18095
|
} catch (error43) {
|
|
17687
18096
|
if (error43 instanceof Error) {
|
|
17688
18097
|
if (error43.message.includes("Not authenticated")) {
|
|
17689
|
-
console.error(
|
|
18098
|
+
console.error(chalk24.red("Not authenticated. Run: vm0 auth login"));
|
|
17690
18099
|
} else {
|
|
17691
|
-
console.error(
|
|
18100
|
+
console.error(chalk24.red(`Error: ${error43.message}`));
|
|
17692
18101
|
}
|
|
17693
18102
|
} else {
|
|
17694
|
-
console.error(
|
|
18103
|
+
console.error(chalk24.red("An unexpected error occurred"));
|
|
17695
18104
|
}
|
|
17696
18105
|
process.exit(1);
|
|
17697
18106
|
}
|
|
@@ -17699,9 +18108,9 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17699
18108
|
);
|
|
17700
18109
|
|
|
17701
18110
|
// src/commands/image/versions.ts
|
|
17702
|
-
import { Command as
|
|
17703
|
-
import
|
|
17704
|
-
var versionsCommand = new
|
|
18111
|
+
import { Command as Command21 } from "commander";
|
|
18112
|
+
import chalk25 from "chalk";
|
|
18113
|
+
var versionsCommand = new Command21().name("versions").description("List all versions of an image").argument("<name>", "Name of the image").action(async (name) => {
|
|
17705
18114
|
try {
|
|
17706
18115
|
const response = await apiClient.get("/api/images");
|
|
17707
18116
|
if (!response.ok) {
|
|
@@ -17713,42 +18122,42 @@ var versionsCommand = new Command17().name("versions").description("List all ver
|
|
|
17713
18122
|
const data = await response.json();
|
|
17714
18123
|
const versions = data.images.filter((img) => img.alias === name);
|
|
17715
18124
|
if (versions.length === 0) {
|
|
17716
|
-
console.error(
|
|
18125
|
+
console.error(chalk25.red(`Image not found: ${name}`));
|
|
17717
18126
|
process.exit(1);
|
|
17718
18127
|
}
|
|
17719
18128
|
const latestReady = versions.find((v) => v.status === "ready");
|
|
17720
18129
|
const latestVersionId = latestReady?.versionId || null;
|
|
17721
|
-
console.log(
|
|
18130
|
+
console.log(chalk25.bold(`Versions of ${name}:`));
|
|
17722
18131
|
console.log();
|
|
17723
18132
|
console.log(
|
|
17724
|
-
|
|
18133
|
+
chalk25.dim(
|
|
17725
18134
|
`${"VERSION".padEnd(20)} ${"STATUS".padEnd(12)} ${"CREATED".padEnd(24)}`
|
|
17726
18135
|
)
|
|
17727
18136
|
);
|
|
17728
|
-
console.log(
|
|
18137
|
+
console.log(chalk25.dim("-".repeat(56)));
|
|
17729
18138
|
for (const version2 of versions) {
|
|
17730
|
-
const statusColor = version2.status === "ready" ?
|
|
18139
|
+
const statusColor = version2.status === "ready" ? chalk25.green : version2.status === "building" ? chalk25.yellow : chalk25.red;
|
|
17731
18140
|
const createdAt = new Date(version2.createdAt).toLocaleString();
|
|
17732
18141
|
let versionDisplay = version2.versionId ? formatVersionIdForDisplay(version2.versionId) : "(legacy)";
|
|
17733
18142
|
if (version2.status === "ready" && version2.versionId === latestVersionId) {
|
|
17734
|
-
versionDisplay = `${versionDisplay} ${
|
|
18143
|
+
versionDisplay = `${versionDisplay} ${chalk25.cyan("latest")}`;
|
|
17735
18144
|
}
|
|
17736
18145
|
console.log(
|
|
17737
18146
|
`${versionDisplay.padEnd(20)} ${statusColor(version2.status.padEnd(12))} ${createdAt.padEnd(24)}`
|
|
17738
18147
|
);
|
|
17739
18148
|
if (version2.status === "error" && version2.errorMessage) {
|
|
17740
|
-
console.log(
|
|
18149
|
+
console.log(chalk25.red(` Error: ${version2.errorMessage}`));
|
|
17741
18150
|
}
|
|
17742
18151
|
}
|
|
17743
18152
|
console.log();
|
|
17744
|
-
console.log(
|
|
18153
|
+
console.log(chalk25.dim(`Total: ${versions.length} version(s)`));
|
|
17745
18154
|
console.log();
|
|
17746
|
-
console.log(
|
|
17747
|
-
console.log(
|
|
18155
|
+
console.log(chalk25.dim("Usage:"));
|
|
18156
|
+
console.log(chalk25.dim(` image: "${name}" # uses latest`));
|
|
17748
18157
|
if (latestVersionId) {
|
|
17749
18158
|
const shortVersion = formatVersionIdForDisplay(latestVersionId);
|
|
17750
18159
|
console.log(
|
|
17751
|
-
|
|
18160
|
+
chalk25.dim(
|
|
17752
18161
|
` image: "${name}:${shortVersion}" # pin to specific version`
|
|
17753
18162
|
)
|
|
17754
18163
|
);
|
|
@@ -17756,23 +18165,23 @@ var versionsCommand = new Command17().name("versions").description("List all ver
|
|
|
17756
18165
|
} catch (error43) {
|
|
17757
18166
|
if (error43 instanceof Error) {
|
|
17758
18167
|
if (error43.message.includes("Not authenticated")) {
|
|
17759
|
-
console.error(
|
|
18168
|
+
console.error(chalk25.red("Not authenticated. Run: vm0 auth login"));
|
|
17760
18169
|
} else {
|
|
17761
|
-
console.error(
|
|
18170
|
+
console.error(chalk25.red(`Error: ${error43.message}`));
|
|
17762
18171
|
}
|
|
17763
18172
|
} else {
|
|
17764
|
-
console.error(
|
|
18173
|
+
console.error(chalk25.red("An unexpected error occurred"));
|
|
17765
18174
|
}
|
|
17766
18175
|
process.exit(1);
|
|
17767
18176
|
}
|
|
17768
18177
|
});
|
|
17769
18178
|
|
|
17770
18179
|
// src/commands/image/index.ts
|
|
17771
|
-
var imageCommand = new
|
|
18180
|
+
var imageCommand = new Command22().name("image").description("Manage custom images").addCommand(buildCommand).addCommand(listCommand3).addCommand(deleteCommand).addCommand(versionsCommand);
|
|
17772
18181
|
|
|
17773
18182
|
// src/commands/logs/index.ts
|
|
17774
|
-
import { Command as
|
|
17775
|
-
import
|
|
18183
|
+
import { Command as Command23 } from "commander";
|
|
18184
|
+
import chalk26 from "chalk";
|
|
17776
18185
|
|
|
17777
18186
|
// src/lib/time-parser.ts
|
|
17778
18187
|
function parseTime(timeStr) {
|
|
@@ -17819,7 +18228,7 @@ function parseRelativeTime(value, unit) {
|
|
|
17819
18228
|
}
|
|
17820
18229
|
|
|
17821
18230
|
// src/commands/logs/index.ts
|
|
17822
|
-
function
|
|
18231
|
+
function formatBytes8(bytes) {
|
|
17823
18232
|
if (bytes === 0) return "0 B";
|
|
17824
18233
|
const k = 1024;
|
|
17825
18234
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -17829,28 +18238,28 @@ function formatBytes7(bytes) {
|
|
|
17829
18238
|
function formatMetric(metric) {
|
|
17830
18239
|
const memPercent = (metric.mem_used / metric.mem_total * 100).toFixed(1);
|
|
17831
18240
|
const diskPercent = (metric.disk_used / metric.disk_total * 100).toFixed(1);
|
|
17832
|
-
return `[${metric.ts}] CPU: ${metric.cpu.toFixed(1)}% | Mem: ${
|
|
18241
|
+
return `[${metric.ts}] CPU: ${metric.cpu.toFixed(1)}% | Mem: ${formatBytes8(metric.mem_used)}/${formatBytes8(metric.mem_total)} (${memPercent}%) | Disk: ${formatBytes8(metric.disk_used)}/${formatBytes8(metric.disk_total)} (${diskPercent}%)`;
|
|
17833
18242
|
}
|
|
17834
18243
|
function formatNetworkLog(entry) {
|
|
17835
18244
|
let statusColor;
|
|
17836
18245
|
if (entry.status >= 200 && entry.status < 300) {
|
|
17837
|
-
statusColor =
|
|
18246
|
+
statusColor = chalk26.green;
|
|
17838
18247
|
} else if (entry.status >= 300 && entry.status < 400) {
|
|
17839
|
-
statusColor =
|
|
18248
|
+
statusColor = chalk26.yellow;
|
|
17840
18249
|
} else if (entry.status >= 400) {
|
|
17841
|
-
statusColor =
|
|
18250
|
+
statusColor = chalk26.red;
|
|
17842
18251
|
} else {
|
|
17843
|
-
statusColor =
|
|
18252
|
+
statusColor = chalk26.gray;
|
|
17844
18253
|
}
|
|
17845
18254
|
let latencyColor;
|
|
17846
18255
|
if (entry.latency_ms < 500) {
|
|
17847
|
-
latencyColor =
|
|
18256
|
+
latencyColor = chalk26.green;
|
|
17848
18257
|
} else if (entry.latency_ms < 2e3) {
|
|
17849
|
-
latencyColor =
|
|
18258
|
+
latencyColor = chalk26.yellow;
|
|
17850
18259
|
} else {
|
|
17851
|
-
latencyColor =
|
|
18260
|
+
latencyColor = chalk26.red;
|
|
17852
18261
|
}
|
|
17853
|
-
return `[${entry.timestamp}] ${entry.method.padEnd(6)} ${statusColor(entry.status)} ${latencyColor(entry.latency_ms + "ms")} ${
|
|
18262
|
+
return `[${entry.timestamp}] ${entry.method.padEnd(6)} ${statusColor(entry.status)} ${latencyColor(entry.latency_ms + "ms")} ${formatBytes8(entry.request_size)}/${formatBytes8(entry.response_size)} ${chalk26.dim(entry.url)}`;
|
|
17854
18263
|
}
|
|
17855
18264
|
function renderAgentEvent(event, provider) {
|
|
17856
18265
|
const eventData = event.eventData;
|
|
@@ -17873,7 +18282,7 @@ function getLogType(options) {
|
|
|
17873
18282
|
].filter(Boolean).length;
|
|
17874
18283
|
if (selected > 1) {
|
|
17875
18284
|
console.error(
|
|
17876
|
-
|
|
18285
|
+
chalk26.red(
|
|
17877
18286
|
"Options --agent, --system, --metrics, and --network are mutually exclusive"
|
|
17878
18287
|
)
|
|
17879
18288
|
);
|
|
@@ -17884,7 +18293,7 @@ function getLogType(options) {
|
|
|
17884
18293
|
if (options.network) return "network";
|
|
17885
18294
|
return "agent";
|
|
17886
18295
|
}
|
|
17887
|
-
var logsCommand = new
|
|
18296
|
+
var logsCommand = new Command23().name("logs").description("View logs for an agent run").argument("<runId>", "Run ID to fetch logs for").option("-a, --agent", "Show agent events (default)").option("-s, --system", "Show system log").option("-m, --metrics", "Show metrics").option("-n, --network", "Show network logs (proxy traffic)").option(
|
|
17888
18297
|
"--since <time>",
|
|
17889
18298
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z, 1705312200)"
|
|
17890
18299
|
).option("--tail <n>", "Show last N entries (default: 5, max: 100)").option("--head <n>", "Show first N entries (max: 100)").action(
|
|
@@ -17893,7 +18302,7 @@ var logsCommand = new Command19().name("logs").description("View logs for an age
|
|
|
17893
18302
|
const logType = getLogType(options);
|
|
17894
18303
|
if (options.tail !== void 0 && options.head !== void 0) {
|
|
17895
18304
|
console.error(
|
|
17896
|
-
|
|
18305
|
+
chalk26.red("Options --tail and --head are mutually exclusive")
|
|
17897
18306
|
);
|
|
17898
18307
|
process.exit(1);
|
|
17899
18308
|
}
|
|
@@ -17930,7 +18339,7 @@ var logsCommand = new Command19().name("logs").description("View logs for an age
|
|
|
17930
18339
|
async function showAgentEvents(runId, options) {
|
|
17931
18340
|
const response = await apiClient.getAgentEvents(runId, options);
|
|
17932
18341
|
if (response.events.length === 0) {
|
|
17933
|
-
console.log(
|
|
18342
|
+
console.log(chalk26.yellow("No agent events found for this run."));
|
|
17934
18343
|
return;
|
|
17935
18344
|
}
|
|
17936
18345
|
const events = options.order === "desc" ? [...response.events].reverse() : response.events;
|
|
@@ -17940,7 +18349,7 @@ async function showAgentEvents(runId, options) {
|
|
|
17940
18349
|
if (response.hasMore) {
|
|
17941
18350
|
console.log();
|
|
17942
18351
|
console.log(
|
|
17943
|
-
|
|
18352
|
+
chalk26.dim(
|
|
17944
18353
|
`Showing ${response.events.length} events. Use --tail to see more.`
|
|
17945
18354
|
)
|
|
17946
18355
|
);
|
|
@@ -17949,21 +18358,21 @@ async function showAgentEvents(runId, options) {
|
|
|
17949
18358
|
async function showSystemLog(runId, options) {
|
|
17950
18359
|
const response = await apiClient.getSystemLog(runId, options);
|
|
17951
18360
|
if (!response.systemLog) {
|
|
17952
|
-
console.log(
|
|
18361
|
+
console.log(chalk26.yellow("No system log found for this run."));
|
|
17953
18362
|
return;
|
|
17954
18363
|
}
|
|
17955
18364
|
console.log(response.systemLog);
|
|
17956
18365
|
if (response.hasMore) {
|
|
17957
18366
|
console.log();
|
|
17958
18367
|
console.log(
|
|
17959
|
-
|
|
18368
|
+
chalk26.dim("More log entries available. Use --tail to see more.")
|
|
17960
18369
|
);
|
|
17961
18370
|
}
|
|
17962
18371
|
}
|
|
17963
18372
|
async function showMetrics(runId, options) {
|
|
17964
18373
|
const response = await apiClient.getMetrics(runId, options);
|
|
17965
18374
|
if (response.metrics.length === 0) {
|
|
17966
|
-
console.log(
|
|
18375
|
+
console.log(chalk26.yellow("No metrics found for this run."));
|
|
17967
18376
|
return;
|
|
17968
18377
|
}
|
|
17969
18378
|
const metrics = options.order === "desc" ? [...response.metrics].reverse() : response.metrics;
|
|
@@ -17973,7 +18382,7 @@ async function showMetrics(runId, options) {
|
|
|
17973
18382
|
if (response.hasMore) {
|
|
17974
18383
|
console.log();
|
|
17975
18384
|
console.log(
|
|
17976
|
-
|
|
18385
|
+
chalk26.dim(
|
|
17977
18386
|
`Showing ${response.metrics.length} metrics. Use --tail to see more.`
|
|
17978
18387
|
)
|
|
17979
18388
|
);
|
|
@@ -17983,7 +18392,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
17983
18392
|
const response = await apiClient.getNetworkLogs(runId, options);
|
|
17984
18393
|
if (response.networkLogs.length === 0) {
|
|
17985
18394
|
console.log(
|
|
17986
|
-
|
|
18395
|
+
chalk26.yellow(
|
|
17987
18396
|
"No network logs found for this run. Network logs are only captured when beta_network_security is enabled."
|
|
17988
18397
|
)
|
|
17989
18398
|
);
|
|
@@ -17996,7 +18405,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
17996
18405
|
if (response.hasMore) {
|
|
17997
18406
|
console.log();
|
|
17998
18407
|
console.log(
|
|
17999
|
-
|
|
18408
|
+
chalk26.dim(
|
|
18000
18409
|
`Showing ${response.networkLogs.length} network logs. Use --tail to see more.`
|
|
18001
18410
|
)
|
|
18002
18411
|
);
|
|
@@ -18005,31 +18414,31 @@ async function showNetworkLogs(runId, options) {
|
|
|
18005
18414
|
function handleError(error43, runId) {
|
|
18006
18415
|
if (error43 instanceof Error) {
|
|
18007
18416
|
if (error43.message.includes("Not authenticated")) {
|
|
18008
|
-
console.error(
|
|
18417
|
+
console.error(chalk26.red("Not authenticated. Run: vm0 auth login"));
|
|
18009
18418
|
} else if (error43.message.includes("not found")) {
|
|
18010
|
-
console.error(
|
|
18419
|
+
console.error(chalk26.red(`Run not found: ${runId}`));
|
|
18011
18420
|
} else if (error43.message.includes("Invalid time format")) {
|
|
18012
|
-
console.error(
|
|
18421
|
+
console.error(chalk26.red(error43.message));
|
|
18013
18422
|
} else {
|
|
18014
|
-
console.error(
|
|
18015
|
-
console.error(
|
|
18423
|
+
console.error(chalk26.red("Failed to fetch logs"));
|
|
18424
|
+
console.error(chalk26.dim(` ${error43.message}`));
|
|
18016
18425
|
}
|
|
18017
18426
|
} else {
|
|
18018
|
-
console.error(
|
|
18427
|
+
console.error(chalk26.red("An unexpected error occurred"));
|
|
18019
18428
|
}
|
|
18020
18429
|
}
|
|
18021
18430
|
|
|
18022
18431
|
// src/commands/scope/index.ts
|
|
18023
|
-
import { Command as
|
|
18432
|
+
import { Command as Command26 } from "commander";
|
|
18024
18433
|
|
|
18025
18434
|
// src/commands/scope/status.ts
|
|
18026
|
-
import { Command as
|
|
18027
|
-
import
|
|
18028
|
-
var statusCommand3 = new
|
|
18435
|
+
import { Command as Command24 } from "commander";
|
|
18436
|
+
import chalk27 from "chalk";
|
|
18437
|
+
var statusCommand3 = new Command24().name("status").description("View current scope status").action(async () => {
|
|
18029
18438
|
try {
|
|
18030
18439
|
const scope = await apiClient.getScope();
|
|
18031
|
-
console.log(
|
|
18032
|
-
console.log(` Slug: ${
|
|
18440
|
+
console.log(chalk27.bold("Scope Information:"));
|
|
18441
|
+
console.log(` Slug: ${chalk27.green(scope.slug)}`);
|
|
18033
18442
|
console.log(` Type: ${scope.type}`);
|
|
18034
18443
|
if (scope.displayName) {
|
|
18035
18444
|
console.log(` Display Name: ${scope.displayName}`);
|
|
@@ -18040,29 +18449,29 @@ var statusCommand3 = new Command20().name("status").description("View current sc
|
|
|
18040
18449
|
} catch (error43) {
|
|
18041
18450
|
if (error43 instanceof Error) {
|
|
18042
18451
|
if (error43.message.includes("Not authenticated")) {
|
|
18043
|
-
console.error(
|
|
18452
|
+
console.error(chalk27.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
18044
18453
|
} else if (error43.message.includes("No scope configured")) {
|
|
18045
|
-
console.log(
|
|
18454
|
+
console.log(chalk27.yellow("No scope configured."));
|
|
18046
18455
|
console.log();
|
|
18047
18456
|
console.log("Set your scope with:");
|
|
18048
|
-
console.log(
|
|
18457
|
+
console.log(chalk27.cyan(" vm0 scope set <slug>"));
|
|
18049
18458
|
console.log();
|
|
18050
18459
|
console.log("Example:");
|
|
18051
|
-
console.log(
|
|
18460
|
+
console.log(chalk27.dim(" vm0 scope set myusername"));
|
|
18052
18461
|
} else {
|
|
18053
|
-
console.error(
|
|
18462
|
+
console.error(chalk27.red(`\u2717 ${error43.message}`));
|
|
18054
18463
|
}
|
|
18055
18464
|
} else {
|
|
18056
|
-
console.error(
|
|
18465
|
+
console.error(chalk27.red("\u2717 An unexpected error occurred"));
|
|
18057
18466
|
}
|
|
18058
18467
|
process.exit(1);
|
|
18059
18468
|
}
|
|
18060
18469
|
});
|
|
18061
18470
|
|
|
18062
18471
|
// src/commands/scope/set.ts
|
|
18063
|
-
import { Command as
|
|
18064
|
-
import
|
|
18065
|
-
var setCommand = new
|
|
18472
|
+
import { Command as Command25 } from "commander";
|
|
18473
|
+
import chalk28 from "chalk";
|
|
18474
|
+
var setCommand = new Command25().name("set").description("Set your scope slug").argument("<slug>", "The scope slug (e.g., your username)").option("--force", "Force change existing scope (may break references)").option("--display-name <name>", "Display name for the scope").action(
|
|
18066
18475
|
async (slug, options) => {
|
|
18067
18476
|
try {
|
|
18068
18477
|
let existingScope;
|
|
@@ -18074,56 +18483,56 @@ var setCommand = new Command21().name("set").description("Set your scope slug").
|
|
|
18074
18483
|
if (existingScope) {
|
|
18075
18484
|
if (!options.force) {
|
|
18076
18485
|
console.error(
|
|
18077
|
-
|
|
18486
|
+
chalk28.yellow(`You already have a scope: ${existingScope.slug}`)
|
|
18078
18487
|
);
|
|
18079
18488
|
console.error();
|
|
18080
18489
|
console.error("To change your scope, use --force:");
|
|
18081
|
-
console.error(
|
|
18490
|
+
console.error(chalk28.cyan(` vm0 scope set ${slug} --force`));
|
|
18082
18491
|
console.error();
|
|
18083
18492
|
console.error(
|
|
18084
|
-
|
|
18493
|
+
chalk28.yellow(
|
|
18085
18494
|
"Warning: Changing your scope may break existing image references."
|
|
18086
18495
|
)
|
|
18087
18496
|
);
|
|
18088
18497
|
process.exit(1);
|
|
18089
18498
|
}
|
|
18090
18499
|
scope = await apiClient.updateScope({ slug, force: true });
|
|
18091
|
-
console.log(
|
|
18500
|
+
console.log(chalk28.green(`\u2713 Scope updated to ${scope.slug}`));
|
|
18092
18501
|
} else {
|
|
18093
18502
|
scope = await apiClient.createScope({
|
|
18094
18503
|
slug,
|
|
18095
18504
|
displayName: options.displayName
|
|
18096
18505
|
});
|
|
18097
|
-
console.log(
|
|
18506
|
+
console.log(chalk28.green(`\u2713 Scope created: ${scope.slug}`));
|
|
18098
18507
|
}
|
|
18099
18508
|
console.log();
|
|
18100
18509
|
console.log("Your images will now be namespaced as:");
|
|
18101
|
-
console.log(
|
|
18510
|
+
console.log(chalk28.cyan(` ${scope.slug}/<image-name>`));
|
|
18102
18511
|
} catch (error43) {
|
|
18103
18512
|
if (error43 instanceof Error) {
|
|
18104
18513
|
if (error43.message.includes("Not authenticated")) {
|
|
18105
18514
|
console.error(
|
|
18106
|
-
|
|
18515
|
+
chalk28.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
18107
18516
|
);
|
|
18108
18517
|
} else if (error43.message.includes("already exists")) {
|
|
18109
18518
|
console.error(
|
|
18110
|
-
|
|
18519
|
+
chalk28.red(
|
|
18111
18520
|
`\u2717 Scope "${slug}" is already taken. Please choose a different slug.`
|
|
18112
18521
|
)
|
|
18113
18522
|
);
|
|
18114
18523
|
} else if (error43.message.includes("reserved")) {
|
|
18115
|
-
console.error(
|
|
18524
|
+
console.error(chalk28.red(`\u2717 ${error43.message}`));
|
|
18116
18525
|
} else if (error43.message.includes("vm0")) {
|
|
18117
18526
|
console.error(
|
|
18118
|
-
|
|
18527
|
+
chalk28.red(
|
|
18119
18528
|
"\u2717 Scope slugs cannot start with 'vm0' (reserved for system use)"
|
|
18120
18529
|
)
|
|
18121
18530
|
);
|
|
18122
18531
|
} else {
|
|
18123
|
-
console.error(
|
|
18532
|
+
console.error(chalk28.red(`\u2717 ${error43.message}`));
|
|
18124
18533
|
}
|
|
18125
18534
|
} else {
|
|
18126
|
-
console.error(
|
|
18535
|
+
console.error(chalk28.red("\u2717 An unexpected error occurred"));
|
|
18127
18536
|
}
|
|
18128
18537
|
process.exit(1);
|
|
18129
18538
|
}
|
|
@@ -18131,13 +18540,13 @@ var setCommand = new Command21().name("set").description("Set your scope slug").
|
|
|
18131
18540
|
);
|
|
18132
18541
|
|
|
18133
18542
|
// src/commands/scope/index.ts
|
|
18134
|
-
var scopeCommand = new
|
|
18543
|
+
var scopeCommand = new Command26().name("scope").description("Manage your scope (namespace for images)").addCommand(statusCommand3).addCommand(setCommand);
|
|
18135
18544
|
|
|
18136
18545
|
// src/commands/init.ts
|
|
18137
|
-
import { Command as
|
|
18138
|
-
import
|
|
18139
|
-
import
|
|
18140
|
-
import { existsSync as
|
|
18546
|
+
import { Command as Command27 } from "commander";
|
|
18547
|
+
import chalk29 from "chalk";
|
|
18548
|
+
import path13 from "path";
|
|
18549
|
+
import { existsSync as existsSync10 } from "fs";
|
|
18141
18550
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
18142
18551
|
var VM0_YAML_FILE = "vm0.yaml";
|
|
18143
18552
|
var AGENTS_MD_FILE = "AGENTS.md";
|
|
@@ -18172,76 +18581,76 @@ You are a HackerNews AI content curator.
|
|
|
18172
18581
|
}
|
|
18173
18582
|
function checkExistingFiles() {
|
|
18174
18583
|
const existingFiles = [];
|
|
18175
|
-
if (
|
|
18176
|
-
if (
|
|
18584
|
+
if (existsSync10(VM0_YAML_FILE)) existingFiles.push(VM0_YAML_FILE);
|
|
18585
|
+
if (existsSync10(AGENTS_MD_FILE)) existingFiles.push(AGENTS_MD_FILE);
|
|
18177
18586
|
return existingFiles;
|
|
18178
18587
|
}
|
|
18179
|
-
|
|
18180
|
-
const rl = readline2.createInterface({
|
|
18181
|
-
input: process.stdin,
|
|
18182
|
-
output: process.stdout
|
|
18183
|
-
});
|
|
18184
|
-
return new Promise((resolve2, reject) => {
|
|
18185
|
-
rl.question(chalk24.cyan("? Enter agent name: "), (answer) => {
|
|
18186
|
-
rl.close();
|
|
18187
|
-
resolve2(answer.trim());
|
|
18188
|
-
});
|
|
18189
|
-
rl.on("SIGINT", () => {
|
|
18190
|
-
rl.close();
|
|
18191
|
-
console.log();
|
|
18192
|
-
reject(new Error("User cancelled"));
|
|
18193
|
-
});
|
|
18194
|
-
});
|
|
18195
|
-
}
|
|
18196
|
-
var initCommand3 = new Command23().name("init").description("Initialize a new VM0 project in the current directory").option("-f, --force", "Overwrite existing files").option("-n, --name <name>", "Agent name (skips interactive prompt)").action(async (options) => {
|
|
18588
|
+
var initCommand3 = new Command27().name("init").description("Initialize a new VM0 project in the current directory").option("-f, --force", "Overwrite existing files").option("-n, --name <name>", "Agent name (required in non-interactive mode)").action(async (options) => {
|
|
18197
18589
|
const existingFiles = checkExistingFiles();
|
|
18198
18590
|
if (existingFiles.length > 0 && !options.force) {
|
|
18199
18591
|
for (const file2 of existingFiles) {
|
|
18200
|
-
console.log(
|
|
18592
|
+
console.log(chalk29.red(`\u2717 ${file2} already exists`));
|
|
18201
18593
|
}
|
|
18202
18594
|
console.log();
|
|
18203
|
-
console.log(`To overwrite: ${
|
|
18595
|
+
console.log(`To overwrite: ${chalk29.cyan("vm0 init --force")}`);
|
|
18204
18596
|
process.exit(1);
|
|
18205
18597
|
}
|
|
18206
18598
|
let agentName;
|
|
18207
18599
|
if (options.name) {
|
|
18208
18600
|
agentName = options.name.trim();
|
|
18601
|
+
} else if (!isInteractive()) {
|
|
18602
|
+
console.error(
|
|
18603
|
+
chalk29.red("\u2717 --name flag is required in non-interactive mode")
|
|
18604
|
+
);
|
|
18605
|
+
console.error(chalk29.dim(" Usage: vm0 init --name <agent-name>"));
|
|
18606
|
+
process.exit(1);
|
|
18209
18607
|
} else {
|
|
18210
|
-
|
|
18211
|
-
|
|
18212
|
-
|
|
18213
|
-
|
|
18608
|
+
const dirName = path13.basename(process.cwd());
|
|
18609
|
+
const defaultName = validateAgentName(dirName) ? dirName : void 0;
|
|
18610
|
+
const name = await promptText(
|
|
18611
|
+
"Enter agent name",
|
|
18612
|
+
defaultName,
|
|
18613
|
+
(value) => {
|
|
18614
|
+
if (!validateAgentName(value)) {
|
|
18615
|
+
return "Must be 3-64 characters, alphanumeric and hyphens, start/end with letter or number";
|
|
18616
|
+
}
|
|
18617
|
+
return true;
|
|
18618
|
+
}
|
|
18619
|
+
);
|
|
18620
|
+
if (name === void 0) {
|
|
18621
|
+
console.log(chalk29.dim("Cancelled"));
|
|
18622
|
+
return;
|
|
18214
18623
|
}
|
|
18624
|
+
agentName = name;
|
|
18215
18625
|
}
|
|
18216
18626
|
if (!agentName || !validateAgentName(agentName)) {
|
|
18217
|
-
console.log(
|
|
18627
|
+
console.log(chalk29.red("\u2717 Invalid agent name"));
|
|
18218
18628
|
console.log(
|
|
18219
|
-
|
|
18629
|
+
chalk29.dim(" Must be 3-64 characters, alphanumeric and hyphens only")
|
|
18220
18630
|
);
|
|
18221
|
-
console.log(
|
|
18631
|
+
console.log(chalk29.dim(" Must start and end with letter or number"));
|
|
18222
18632
|
process.exit(1);
|
|
18223
18633
|
}
|
|
18224
18634
|
await writeFile7(VM0_YAML_FILE, generateVm0Yaml(agentName));
|
|
18225
18635
|
const vm0Status = existingFiles.includes(VM0_YAML_FILE) ? " (overwritten)" : "";
|
|
18226
|
-
console.log(
|
|
18636
|
+
console.log(chalk29.green(`\u2713 Created ${VM0_YAML_FILE}${vm0Status}`));
|
|
18227
18637
|
await writeFile7(AGENTS_MD_FILE, generateAgentsMd());
|
|
18228
18638
|
const agentsStatus = existingFiles.includes(AGENTS_MD_FILE) ? " (overwritten)" : "";
|
|
18229
|
-
console.log(
|
|
18639
|
+
console.log(chalk29.green(`\u2713 Created ${AGENTS_MD_FILE}${agentsStatus}`));
|
|
18230
18640
|
console.log();
|
|
18231
18641
|
console.log("Next steps:");
|
|
18232
18642
|
console.log(
|
|
18233
|
-
` 1. Get your Claude Code token: ${
|
|
18643
|
+
` 1. Get your Claude Code token: ${chalk29.cyan("claude setup-token")}`
|
|
18234
18644
|
);
|
|
18235
18645
|
console.log(` 2. Set the environment variable (or add to .env file):`);
|
|
18236
|
-
console.log(
|
|
18237
|
-
console.log(` 3. Run your agent: ${
|
|
18646
|
+
console.log(chalk29.dim(` export CLAUDE_CODE_OAUTH_TOKEN=<your-token>`));
|
|
18647
|
+
console.log(` 3. Run your agent: ${chalk29.cyan('vm0 cook "your prompt"')}`);
|
|
18238
18648
|
});
|
|
18239
18649
|
|
|
18240
18650
|
// src/commands/setup-github.ts
|
|
18241
|
-
import { Command as
|
|
18242
|
-
import
|
|
18243
|
-
import
|
|
18244
|
-
import { existsSync as existsSync10 } from "fs";
|
|
18651
|
+
import { Command as Command28 } from "commander";
|
|
18652
|
+
import chalk30 from "chalk";
|
|
18653
|
+
import { existsSync as existsSync11 } from "fs";
|
|
18245
18654
|
import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
|
|
18246
18655
|
import { execSync, spawnSync } from "child_process";
|
|
18247
18656
|
import { parse as parseYaml5 } from "yaml";
|
|
@@ -18264,57 +18673,57 @@ function isGhAuthenticated() {
|
|
|
18264
18673
|
async function checkPrerequisites() {
|
|
18265
18674
|
console.log("Checking prerequisites...");
|
|
18266
18675
|
if (!isGhInstalled()) {
|
|
18267
|
-
console.log(
|
|
18676
|
+
console.log(chalk30.red("\u2717 GitHub CLI (gh) is not installed"));
|
|
18268
18677
|
console.log();
|
|
18269
18678
|
console.log("GitHub CLI is required for this command.");
|
|
18270
18679
|
console.log();
|
|
18271
|
-
console.log(` macOS: ${
|
|
18272
|
-
console.log(` Other: ${
|
|
18680
|
+
console.log(` macOS: ${chalk30.cyan("brew install gh")}`);
|
|
18681
|
+
console.log(` Other: ${chalk30.cyan("https://cli.github.com/")}`);
|
|
18273
18682
|
console.log();
|
|
18274
18683
|
console.log("After installation, run:");
|
|
18275
|
-
console.log(` ${
|
|
18684
|
+
console.log(` ${chalk30.cyan("gh auth login")}`);
|
|
18276
18685
|
console.log();
|
|
18277
18686
|
console.log("Then try again:");
|
|
18278
|
-
console.log(` ${
|
|
18687
|
+
console.log(` ${chalk30.cyan("vm0 setup-github")}`);
|
|
18279
18688
|
process.exit(1);
|
|
18280
18689
|
}
|
|
18281
|
-
console.log(
|
|
18690
|
+
console.log(chalk30.green("\u2713 GitHub CLI (gh) is installed"));
|
|
18282
18691
|
if (!isGhAuthenticated()) {
|
|
18283
|
-
console.log(
|
|
18692
|
+
console.log(chalk30.red("\u2717 GitHub CLI is not authenticated"));
|
|
18284
18693
|
console.log();
|
|
18285
18694
|
console.log("Please authenticate GitHub CLI first:");
|
|
18286
|
-
console.log(` ${
|
|
18695
|
+
console.log(` ${chalk30.cyan("gh auth login")}`);
|
|
18287
18696
|
console.log();
|
|
18288
18697
|
console.log("Then try again:");
|
|
18289
|
-
console.log(` ${
|
|
18698
|
+
console.log(` ${chalk30.cyan("vm0 setup-github")}`);
|
|
18290
18699
|
process.exit(1);
|
|
18291
18700
|
}
|
|
18292
|
-
console.log(
|
|
18701
|
+
console.log(chalk30.green("\u2713 GitHub CLI is authenticated"));
|
|
18293
18702
|
const token = await getToken();
|
|
18294
18703
|
if (!token) {
|
|
18295
|
-
console.log(
|
|
18704
|
+
console.log(chalk30.red("\u2717 VM0 not authenticated"));
|
|
18296
18705
|
console.log();
|
|
18297
18706
|
console.log("Please authenticate with VM0 first:");
|
|
18298
|
-
console.log(` ${
|
|
18707
|
+
console.log(` ${chalk30.cyan("vm0 auth login")}`);
|
|
18299
18708
|
console.log();
|
|
18300
18709
|
console.log("Then try again:");
|
|
18301
|
-
console.log(` ${
|
|
18710
|
+
console.log(` ${chalk30.cyan("vm0 setup-github")}`);
|
|
18302
18711
|
process.exit(1);
|
|
18303
18712
|
}
|
|
18304
|
-
console.log(
|
|
18305
|
-
if (!
|
|
18306
|
-
console.log(
|
|
18713
|
+
console.log(chalk30.green("\u2713 VM0 authenticated"));
|
|
18714
|
+
if (!existsSync11("vm0.yaml")) {
|
|
18715
|
+
console.log(chalk30.red("\u2717 vm0.yaml not found"));
|
|
18307
18716
|
console.log();
|
|
18308
18717
|
console.log("This command requires a vm0.yaml configuration file.");
|
|
18309
18718
|
console.log();
|
|
18310
18719
|
console.log("To create one, run:");
|
|
18311
|
-
console.log(` ${
|
|
18720
|
+
console.log(` ${chalk30.cyan("vm0 init")}`);
|
|
18312
18721
|
console.log();
|
|
18313
18722
|
console.log("Then try again:");
|
|
18314
|
-
console.log(` ${
|
|
18723
|
+
console.log(` ${chalk30.cyan("vm0 setup-github")}`);
|
|
18315
18724
|
process.exit(1);
|
|
18316
18725
|
}
|
|
18317
|
-
console.log(
|
|
18726
|
+
console.log(chalk30.green("\u2713 vm0.yaml found"));
|
|
18318
18727
|
return token;
|
|
18319
18728
|
}
|
|
18320
18729
|
function generatePublishYaml() {
|
|
@@ -18425,22 +18834,8 @@ function extractSecretsAndVars(config2) {
|
|
|
18425
18834
|
};
|
|
18426
18835
|
}
|
|
18427
18836
|
async function promptYesNo(question, defaultYes) {
|
|
18428
|
-
const
|
|
18429
|
-
|
|
18430
|
-
input: process.stdin,
|
|
18431
|
-
output: process.stdout
|
|
18432
|
-
});
|
|
18433
|
-
return new Promise((resolve2) => {
|
|
18434
|
-
rl.question(chalk25.cyan(`? ${question} ${hint} `), (answer) => {
|
|
18435
|
-
rl.close();
|
|
18436
|
-
const normalized = answer.trim().toLowerCase();
|
|
18437
|
-
if (normalized === "") {
|
|
18438
|
-
resolve2(defaultYes);
|
|
18439
|
-
} else {
|
|
18440
|
-
resolve2(normalized === "y" || normalized === "yes");
|
|
18441
|
-
}
|
|
18442
|
-
});
|
|
18443
|
-
});
|
|
18837
|
+
const result = await promptConfirm(question, defaultYes);
|
|
18838
|
+
return result ?? false;
|
|
18444
18839
|
}
|
|
18445
18840
|
function setGitHubSecret(name, value) {
|
|
18446
18841
|
const result = spawnSync("gh", ["secret", "set", name], {
|
|
@@ -18482,7 +18877,7 @@ function displaySecretsTable(secretStatuses, varStatuses) {
|
|
|
18482
18877
|
if (secretStatuses.length > 0) {
|
|
18483
18878
|
console.log("\u2502 Secrets: \u2502");
|
|
18484
18879
|
for (const s of secretStatuses) {
|
|
18485
|
-
const status = s.found ?
|
|
18880
|
+
const status = s.found ? chalk30.green("\u2713") : chalk30.red("\u2717");
|
|
18486
18881
|
const source = s.found ? `(from ${s.source})` : "not found";
|
|
18487
18882
|
const paddedName = (s.name + " ").padEnd(23, ".");
|
|
18488
18883
|
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
@@ -18491,7 +18886,7 @@ function displaySecretsTable(secretStatuses, varStatuses) {
|
|
|
18491
18886
|
if (varStatuses.length > 0) {
|
|
18492
18887
|
console.log("\u2502 Variables: \u2502");
|
|
18493
18888
|
for (const v of varStatuses) {
|
|
18494
|
-
const status = v.found ?
|
|
18889
|
+
const status = v.found ? chalk30.green("\u2713") : chalk30.red("\u2717");
|
|
18495
18890
|
const source = v.found ? `(from ${v.source})` : "not found";
|
|
18496
18891
|
const paddedName = (v.name + " ").padEnd(23, ".");
|
|
18497
18892
|
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
@@ -18503,17 +18898,17 @@ function showManualSetupInstructions(secrets, vars) {
|
|
|
18503
18898
|
console.log("Skipped automatic setup. Configure secrets manually:");
|
|
18504
18899
|
console.log();
|
|
18505
18900
|
console.log(" Step 1: Get your VM0 token");
|
|
18506
|
-
console.log(` ${
|
|
18901
|
+
console.log(` ${chalk30.cyan("vm0 auth setup-token")}`);
|
|
18507
18902
|
console.log();
|
|
18508
18903
|
console.log(" Step 2: Set GitHub secrets");
|
|
18509
18904
|
for (const s of secrets) {
|
|
18510
|
-
console.log(` ${
|
|
18905
|
+
console.log(` ${chalk30.cyan(`gh secret set ${s}`)}`);
|
|
18511
18906
|
}
|
|
18512
18907
|
if (vars.length > 0) {
|
|
18513
18908
|
console.log();
|
|
18514
18909
|
console.log(" Step 3: Set GitHub variables");
|
|
18515
18910
|
for (const v of vars) {
|
|
18516
|
-
console.log(` ${
|
|
18911
|
+
console.log(` ${chalk30.cyan(`gh variable set ${v}`)}`);
|
|
18517
18912
|
}
|
|
18518
18913
|
}
|
|
18519
18914
|
}
|
|
@@ -18556,7 +18951,7 @@ function showWorkflowsCreatedMessage() {
|
|
|
18556
18951
|
console.log("\u2502 3. Push to main branch to trigger publish \u2502");
|
|
18557
18952
|
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
18558
18953
|
}
|
|
18559
|
-
var setupGithubCommand = new
|
|
18954
|
+
var setupGithubCommand = new Command28().name("setup-github").description("Initialize GitHub Actions workflows for agent deployment").option("-f, --force", "Overwrite existing workflow files").option("-y, --yes", "Auto-confirm all prompts").option("--skip-secrets", "Skip automatic secrets/variables setup").action(
|
|
18560
18955
|
async (options) => {
|
|
18561
18956
|
const vm0Token = await checkPrerequisites();
|
|
18562
18957
|
if (!vm0Token) {
|
|
@@ -18568,10 +18963,10 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18568
18963
|
const config2 = parseYaml5(content);
|
|
18569
18964
|
const agents = config2.agents;
|
|
18570
18965
|
const agentName = Object.keys(agents)[0];
|
|
18571
|
-
console.log(
|
|
18966
|
+
console.log(chalk30.green(`\u2713 Agent: ${agentName}`));
|
|
18572
18967
|
const { secrets, vars } = extractSecretsAndVars(config2);
|
|
18573
18968
|
console.log(
|
|
18574
|
-
|
|
18969
|
+
chalk30.green(
|
|
18575
18970
|
`\u2713 Found ${secrets.length} secrets, ${vars.length} variables`
|
|
18576
18971
|
)
|
|
18577
18972
|
);
|
|
@@ -18579,10 +18974,10 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18579
18974
|
const publishPath = ".github/workflows/publish.yml";
|
|
18580
18975
|
const runPath = ".github/workflows/run.yml";
|
|
18581
18976
|
const existingFiles = [];
|
|
18582
|
-
if (
|
|
18583
|
-
if (
|
|
18977
|
+
if (existsSync11(publishPath)) existingFiles.push(publishPath);
|
|
18978
|
+
if (existsSync11(runPath)) existingFiles.push(runPath);
|
|
18584
18979
|
if (existingFiles.length > 0 && !options.force) {
|
|
18585
|
-
console.log(
|
|
18980
|
+
console.log(chalk30.yellow("\u26A0 Existing workflow files detected:"));
|
|
18586
18981
|
for (const file2 of existingFiles) {
|
|
18587
18982
|
console.log(` \u2022 ${file2}`);
|
|
18588
18983
|
}
|
|
@@ -18595,7 +18990,7 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18595
18990
|
if (!overwrite) {
|
|
18596
18991
|
console.log();
|
|
18597
18992
|
console.log("Aborted. To force overwrite, run:");
|
|
18598
|
-
console.log(` ${
|
|
18993
|
+
console.log(` ${chalk30.cyan("vm0 setup-github --force")}`);
|
|
18599
18994
|
process.exit(0);
|
|
18600
18995
|
}
|
|
18601
18996
|
}
|
|
@@ -18605,13 +19000,13 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18605
19000
|
await mkdir7(".github/workflows", { recursive: true });
|
|
18606
19001
|
await writeFile8(publishPath, generatePublishYaml());
|
|
18607
19002
|
const publishStatus = existingFiles.includes(publishPath) ? "Overwrote" : "Created";
|
|
18608
|
-
console.log(
|
|
19003
|
+
console.log(chalk30.green(`\u2713 ${publishStatus} ${publishPath}`));
|
|
18609
19004
|
await writeFile8(runPath, generateRunYaml(agentName, secrets, vars));
|
|
18610
19005
|
const runStatus = existingFiles.includes(runPath) ? "Overwrote" : "Created";
|
|
18611
|
-
console.log(
|
|
19006
|
+
console.log(chalk30.green(`\u2713 ${runStatus} ${runPath}`));
|
|
18612
19007
|
console.log();
|
|
18613
19008
|
if (options.skipSecrets) {
|
|
18614
|
-
console.log(
|
|
19009
|
+
console.log(chalk30.green("\u2713 Done (secrets setup skipped)"));
|
|
18615
19010
|
return;
|
|
18616
19011
|
}
|
|
18617
19012
|
const { secretStatuses, varStatuses } = await detectSecretValues(
|
|
@@ -18651,14 +19046,14 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18651
19046
|
if (s.found && s.value) {
|
|
18652
19047
|
const success2 = setGitHubSecret(s.name, s.value);
|
|
18653
19048
|
if (success2) {
|
|
18654
|
-
console.log(` ${
|
|
19049
|
+
console.log(` ${chalk30.green("\u2713")} ${s.name}`);
|
|
18655
19050
|
} else {
|
|
18656
|
-
console.log(` ${
|
|
19051
|
+
console.log(` ${chalk30.red("\u2717")} ${s.name} (failed)`);
|
|
18657
19052
|
failedSecrets.push(s.name);
|
|
18658
19053
|
}
|
|
18659
19054
|
} else {
|
|
18660
19055
|
console.log(
|
|
18661
|
-
` ${
|
|
19056
|
+
` ${chalk30.yellow("\u26A0")} ${s.name} (skipped - not found)`
|
|
18662
19057
|
);
|
|
18663
19058
|
}
|
|
18664
19059
|
}
|
|
@@ -18670,14 +19065,14 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18670
19065
|
if (v.found && v.value) {
|
|
18671
19066
|
const success2 = setGitHubVariable(v.name, v.value);
|
|
18672
19067
|
if (success2) {
|
|
18673
|
-
console.log(` ${
|
|
19068
|
+
console.log(` ${chalk30.green("\u2713")} ${v.name}`);
|
|
18674
19069
|
} else {
|
|
18675
|
-
console.log(` ${
|
|
19070
|
+
console.log(` ${chalk30.red("\u2717")} ${v.name} (failed)`);
|
|
18676
19071
|
failedVars.push(v.name);
|
|
18677
19072
|
}
|
|
18678
19073
|
} else {
|
|
18679
19074
|
console.log(
|
|
18680
|
-
` ${
|
|
19075
|
+
` ${chalk30.yellow("\u26A0")} ${v.name} (skipped - not found)`
|
|
18681
19076
|
);
|
|
18682
19077
|
}
|
|
18683
19078
|
}
|
|
@@ -18700,10 +19095,10 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18700
19095
|
);
|
|
18701
19096
|
|
|
18702
19097
|
// src/index.ts
|
|
18703
|
-
var program = new
|
|
18704
|
-
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.
|
|
19098
|
+
var program = new Command29();
|
|
19099
|
+
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.32.0");
|
|
18705
19100
|
program.command("info").description("Display environment information").action(async () => {
|
|
18706
|
-
console.log(
|
|
19101
|
+
console.log(chalk31.bold("System Information:"));
|
|
18707
19102
|
console.log(`Node Version: ${process.version}`);
|
|
18708
19103
|
console.log(`Platform: ${process.platform}`);
|
|
18709
19104
|
console.log(`Architecture: ${process.arch}`);
|