@vm0/cli 4.31.1 → 4.33.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 +965 -451
- 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")
|
|
@@ -2760,7 +2760,7 @@ var $ZodBase64 = /* @__PURE__ */ $constructor("$ZodBase64", (inst, def) => {
|
|
|
2760
2760
|
function isValidBase64URL(data) {
|
|
2761
2761
|
if (!base64url.test(data))
|
|
2762
2762
|
return false;
|
|
2763
|
-
const base643 = data.replace(/[-_]/g, (
|
|
2763
|
+
const base643 = data.replace(/[-_]/g, (c11) => c11 === "-" ? "+" : "/");
|
|
2764
2764
|
const padded = base643.padEnd(Math.ceil(base643.length / 4) * 4, "=");
|
|
2765
2765
|
return isValidBase64(padded);
|
|
2766
2766
|
}
|
|
@@ -11672,9 +11672,9 @@ var ZodDate = /* @__PURE__ */ $constructor("ZodDate", (inst, def) => {
|
|
|
11672
11672
|
ZodType.init(inst, def);
|
|
11673
11673
|
inst.min = (value, params) => inst.check(_gte(value, params));
|
|
11674
11674
|
inst.max = (value, params) => inst.check(_lte(value, params));
|
|
11675
|
-
const
|
|
11676
|
-
inst.minDate =
|
|
11677
|
-
inst.maxDate =
|
|
11675
|
+
const c11 = inst._zod.bag;
|
|
11676
|
+
inst.minDate = c11.minimum ? new Date(c11.minimum) : null;
|
|
11677
|
+
inst.maxDate = c11.maximum ? new Date(c11.maximum) : null;
|
|
11678
11678
|
});
|
|
11679
11679
|
function date3(params) {
|
|
11680
11680
|
return _date(ZodDate, params);
|
|
@@ -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();
|
|
@@ -13504,6 +13526,82 @@ var scopeContract = c9.router({
|
|
|
13504
13526
|
}
|
|
13505
13527
|
});
|
|
13506
13528
|
|
|
13529
|
+
// ../../packages/core/src/contracts/sessions.ts
|
|
13530
|
+
var c10 = initContract();
|
|
13531
|
+
var sessionResponseSchema = external_exports.object({
|
|
13532
|
+
id: external_exports.string(),
|
|
13533
|
+
agentComposeId: external_exports.string(),
|
|
13534
|
+
agentComposeVersionId: external_exports.string().nullable(),
|
|
13535
|
+
conversationId: external_exports.string().nullable(),
|
|
13536
|
+
artifactName: external_exports.string().nullable(),
|
|
13537
|
+
vars: external_exports.record(external_exports.string(), external_exports.string()).nullable(),
|
|
13538
|
+
secretNames: external_exports.array(external_exports.string()).nullable(),
|
|
13539
|
+
volumeVersions: external_exports.record(external_exports.string(), external_exports.string()).nullable(),
|
|
13540
|
+
createdAt: external_exports.string(),
|
|
13541
|
+
updatedAt: external_exports.string()
|
|
13542
|
+
});
|
|
13543
|
+
var agentComposeSnapshotSchema = external_exports.object({
|
|
13544
|
+
agentComposeVersionId: external_exports.string(),
|
|
13545
|
+
vars: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
13546
|
+
secretNames: external_exports.array(external_exports.string()).optional()
|
|
13547
|
+
});
|
|
13548
|
+
var artifactSnapshotSchema2 = external_exports.object({
|
|
13549
|
+
artifactName: external_exports.string(),
|
|
13550
|
+
artifactVersion: external_exports.string()
|
|
13551
|
+
});
|
|
13552
|
+
var volumeVersionsSnapshotSchema2 = external_exports.object({
|
|
13553
|
+
versions: external_exports.record(external_exports.string(), external_exports.string())
|
|
13554
|
+
});
|
|
13555
|
+
var checkpointResponseSchema = external_exports.object({
|
|
13556
|
+
id: external_exports.string(),
|
|
13557
|
+
runId: external_exports.string(),
|
|
13558
|
+
conversationId: external_exports.string(),
|
|
13559
|
+
agentComposeSnapshot: agentComposeSnapshotSchema,
|
|
13560
|
+
artifactSnapshot: artifactSnapshotSchema2.nullable(),
|
|
13561
|
+
volumeVersionsSnapshot: volumeVersionsSnapshotSchema2.nullable(),
|
|
13562
|
+
createdAt: external_exports.string()
|
|
13563
|
+
});
|
|
13564
|
+
var sessionsByIdContract = c10.router({
|
|
13565
|
+
/**
|
|
13566
|
+
* GET /api/agent/sessions/:id
|
|
13567
|
+
* Get session by ID
|
|
13568
|
+
*/
|
|
13569
|
+
getById: {
|
|
13570
|
+
method: "GET",
|
|
13571
|
+
path: "/api/agent/sessions/:id",
|
|
13572
|
+
pathParams: external_exports.object({
|
|
13573
|
+
id: external_exports.string().min(1, "Session ID is required")
|
|
13574
|
+
}),
|
|
13575
|
+
responses: {
|
|
13576
|
+
200: sessionResponseSchema,
|
|
13577
|
+
401: apiErrorSchema,
|
|
13578
|
+
403: apiErrorSchema,
|
|
13579
|
+
404: apiErrorSchema
|
|
13580
|
+
},
|
|
13581
|
+
summary: "Get session by ID"
|
|
13582
|
+
}
|
|
13583
|
+
});
|
|
13584
|
+
var checkpointsByIdContract = c10.router({
|
|
13585
|
+
/**
|
|
13586
|
+
* GET /api/agent/checkpoints/:id
|
|
13587
|
+
* Get checkpoint by ID
|
|
13588
|
+
*/
|
|
13589
|
+
getById: {
|
|
13590
|
+
method: "GET",
|
|
13591
|
+
path: "/api/agent/checkpoints/:id",
|
|
13592
|
+
pathParams: external_exports.object({
|
|
13593
|
+
id: external_exports.string().min(1, "Checkpoint ID is required")
|
|
13594
|
+
}),
|
|
13595
|
+
responses: {
|
|
13596
|
+
200: checkpointResponseSchema,
|
|
13597
|
+
401: apiErrorSchema,
|
|
13598
|
+
403: apiErrorSchema,
|
|
13599
|
+
404: apiErrorSchema
|
|
13600
|
+
},
|
|
13601
|
+
summary: "Get checkpoint by ID"
|
|
13602
|
+
}
|
|
13603
|
+
});
|
|
13604
|
+
|
|
13507
13605
|
// ../../packages/core/src/scope-reference.ts
|
|
13508
13606
|
function getLegacySystemTemplateWarning(legacyFormat) {
|
|
13509
13607
|
if (!isLegacySystemTemplate(legacyFormat)) {
|
|
@@ -13908,10 +14006,51 @@ var ApiClient = class {
|
|
|
13908
14006
|
}
|
|
13909
14007
|
return await response.json();
|
|
13910
14008
|
}
|
|
14009
|
+
/**
|
|
14010
|
+
* Get session by ID
|
|
14011
|
+
* Used by run continue to fetch session info including secretNames
|
|
14012
|
+
*/
|
|
14013
|
+
async getSession(sessionId) {
|
|
14014
|
+
const baseUrl = await this.getBaseUrl();
|
|
14015
|
+
const headers = await this.getHeaders();
|
|
14016
|
+
const response = await fetch(`${baseUrl}/api/agent/sessions/${sessionId}`, {
|
|
14017
|
+
method: "GET",
|
|
14018
|
+
headers
|
|
14019
|
+
});
|
|
14020
|
+
if (!response.ok) {
|
|
14021
|
+
const error43 = await response.json();
|
|
14022
|
+
throw new Error(
|
|
14023
|
+
error43.error?.message || `Session not found: ${sessionId}`
|
|
14024
|
+
);
|
|
14025
|
+
}
|
|
14026
|
+
return await response.json();
|
|
14027
|
+
}
|
|
14028
|
+
/**
|
|
14029
|
+
* Get checkpoint by ID
|
|
14030
|
+
* Used by run resume to fetch checkpoint info including secretNames
|
|
14031
|
+
*/
|
|
14032
|
+
async getCheckpoint(checkpointId) {
|
|
14033
|
+
const baseUrl = await this.getBaseUrl();
|
|
14034
|
+
const headers = await this.getHeaders();
|
|
14035
|
+
const response = await fetch(
|
|
14036
|
+
`${baseUrl}/api/agent/checkpoints/${checkpointId}`,
|
|
14037
|
+
{
|
|
14038
|
+
method: "GET",
|
|
14039
|
+
headers
|
|
14040
|
+
}
|
|
14041
|
+
);
|
|
14042
|
+
if (!response.ok) {
|
|
14043
|
+
const error43 = await response.json();
|
|
14044
|
+
throw new Error(
|
|
14045
|
+
error43.error?.message || `Checkpoint not found: ${checkpointId}`
|
|
14046
|
+
);
|
|
14047
|
+
}
|
|
14048
|
+
return await response.json();
|
|
14049
|
+
}
|
|
13911
14050
|
/**
|
|
13912
14051
|
* Generic GET request
|
|
13913
14052
|
*/
|
|
13914
|
-
async get(
|
|
14053
|
+
async get(path14) {
|
|
13915
14054
|
const baseUrl = await this.getBaseUrl();
|
|
13916
14055
|
const token = await getToken();
|
|
13917
14056
|
if (!token) {
|
|
@@ -13924,7 +14063,7 @@ var ApiClient = class {
|
|
|
13924
14063
|
if (bypassSecret) {
|
|
13925
14064
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
13926
14065
|
}
|
|
13927
|
-
return fetch(`${baseUrl}${
|
|
14066
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
13928
14067
|
method: "GET",
|
|
13929
14068
|
headers
|
|
13930
14069
|
});
|
|
@@ -13932,7 +14071,7 @@ var ApiClient = class {
|
|
|
13932
14071
|
/**
|
|
13933
14072
|
* Generic POST request
|
|
13934
14073
|
*/
|
|
13935
|
-
async post(
|
|
14074
|
+
async post(path14, options) {
|
|
13936
14075
|
const baseUrl = await this.getBaseUrl();
|
|
13937
14076
|
const token = await getToken();
|
|
13938
14077
|
if (!token) {
|
|
@@ -13948,7 +14087,7 @@ var ApiClient = class {
|
|
|
13948
14087
|
if (bypassSecret) {
|
|
13949
14088
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
13950
14089
|
}
|
|
13951
|
-
return fetch(`${baseUrl}${
|
|
14090
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
13952
14091
|
method: "POST",
|
|
13953
14092
|
headers,
|
|
13954
14093
|
body: options?.body
|
|
@@ -13957,7 +14096,7 @@ var ApiClient = class {
|
|
|
13957
14096
|
/**
|
|
13958
14097
|
* Generic DELETE request
|
|
13959
14098
|
*/
|
|
13960
|
-
async delete(
|
|
14099
|
+
async delete(path14) {
|
|
13961
14100
|
const baseUrl = await this.getBaseUrl();
|
|
13962
14101
|
const token = await getToken();
|
|
13963
14102
|
if (!token) {
|
|
@@ -13970,7 +14109,7 @@ var ApiClient = class {
|
|
|
13970
14109
|
if (bypassSecret) {
|
|
13971
14110
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
13972
14111
|
}
|
|
13973
|
-
return fetch(`${baseUrl}${
|
|
14112
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
13974
14113
|
method: "DELETE",
|
|
13975
14114
|
headers
|
|
13976
14115
|
});
|
|
@@ -14340,6 +14479,28 @@ import * as tar2 from "tar";
|
|
|
14340
14479
|
import * as fs2 from "fs";
|
|
14341
14480
|
import * as path2 from "path";
|
|
14342
14481
|
import * as tar from "tar";
|
|
14482
|
+
function formatBytes(bytes) {
|
|
14483
|
+
if (bytes === 0) return "0 B";
|
|
14484
|
+
const k = 1024;
|
|
14485
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
14486
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
14487
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
14488
|
+
}
|
|
14489
|
+
function formatRelativeTime(isoDate) {
|
|
14490
|
+
const date5 = new Date(isoDate);
|
|
14491
|
+
const now = /* @__PURE__ */ new Date();
|
|
14492
|
+
const diffMs = now.getTime() - date5.getTime();
|
|
14493
|
+
const diffSec = Math.floor(diffMs / 1e3);
|
|
14494
|
+
const diffMin = Math.floor(diffSec / 60);
|
|
14495
|
+
const diffHour = Math.floor(diffMin / 60);
|
|
14496
|
+
const diffDay = Math.floor(diffHour / 24);
|
|
14497
|
+
const diffWeek = Math.floor(diffDay / 7);
|
|
14498
|
+
if (diffSec < 60) return "just now";
|
|
14499
|
+
if (diffMin < 60) return `${diffMin} minute${diffMin === 1 ? "" : "s"} ago`;
|
|
14500
|
+
if (diffHour < 24) return `${diffHour} hour${diffHour === 1 ? "" : "s"} ago`;
|
|
14501
|
+
if (diffDay < 7) return `${diffDay} day${diffDay === 1 ? "" : "s"} ago`;
|
|
14502
|
+
return `${diffWeek} week${diffWeek === 1 ? "" : "s"} ago`;
|
|
14503
|
+
}
|
|
14343
14504
|
function excludeVm0Filter(filePath) {
|
|
14344
14505
|
const shouldExclude = filePath === ".vm0" || filePath.startsWith(".vm0/") || filePath.startsWith("./.vm0");
|
|
14345
14506
|
return !shouldExclude;
|
|
@@ -14679,6 +14840,11 @@ async function uploadSkill(skillUrl) {
|
|
|
14679
14840
|
}
|
|
14680
14841
|
|
|
14681
14842
|
// src/commands/compose.ts
|
|
14843
|
+
function getSecretsFromComposeContent(content) {
|
|
14844
|
+
const refs = extractVariableReferences(content);
|
|
14845
|
+
const grouped = groupVariablesBySource(refs);
|
|
14846
|
+
return new Set(grouped.secrets.map((r) => r.name));
|
|
14847
|
+
}
|
|
14682
14848
|
function transformExperimentalShorthand(agent) {
|
|
14683
14849
|
const experimentalSecrets = agent.experimental_secrets;
|
|
14684
14850
|
const experimentalVars = agent.experimental_vars;
|
|
@@ -14843,6 +15009,15 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
14843
15009
|
const newVars = [...skillVars.entries()].filter(
|
|
14844
15010
|
([name]) => !(name in environment)
|
|
14845
15011
|
);
|
|
15012
|
+
let headSecrets = /* @__PURE__ */ new Set();
|
|
15013
|
+
try {
|
|
15014
|
+
const existingCompose = await apiClient.getComposeByName(agentName);
|
|
15015
|
+
if (existingCompose.content) {
|
|
15016
|
+
headSecrets = getSecretsFromComposeContent(existingCompose.content);
|
|
15017
|
+
}
|
|
15018
|
+
} catch {
|
|
15019
|
+
}
|
|
15020
|
+
const trulyNewSecrets = newSecrets.map(([name]) => name).filter((name) => !headSecrets.has(name));
|
|
14846
15021
|
if (newSecrets.length > 0 || newVars.length > 0) {
|
|
14847
15022
|
console.log();
|
|
14848
15023
|
console.log(
|
|
@@ -14852,7 +15027,11 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
14852
15027
|
if (newSecrets.length > 0) {
|
|
14853
15028
|
console.log(chalk2.cyan(" Secrets:"));
|
|
14854
15029
|
for (const [name, skills] of newSecrets) {
|
|
14855
|
-
|
|
15030
|
+
const isNew = trulyNewSecrets.includes(name);
|
|
15031
|
+
const newMarker = isNew ? chalk2.yellow(" (new)") : "";
|
|
15032
|
+
console.log(
|
|
15033
|
+
` ${name.padEnd(24)}${newMarker} <- ${skills.join(", ")}`
|
|
15034
|
+
);
|
|
14856
15035
|
}
|
|
14857
15036
|
}
|
|
14858
15037
|
if (newVars.length > 0) {
|
|
@@ -14862,24 +15041,31 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
14862
15041
|
}
|
|
14863
15042
|
}
|
|
14864
15043
|
console.log();
|
|
14865
|
-
if (
|
|
14866
|
-
if (!
|
|
14867
|
-
|
|
14868
|
-
|
|
14869
|
-
|
|
14870
|
-
|
|
14871
|
-
|
|
14872
|
-
|
|
14873
|
-
|
|
14874
|
-
|
|
14875
|
-
|
|
14876
|
-
|
|
14877
|
-
|
|
14878
|
-
|
|
14879
|
-
|
|
14880
|
-
|
|
14881
|
-
|
|
14882
|
-
|
|
15044
|
+
if (trulyNewSecrets.length > 0) {
|
|
15045
|
+
if (!options.yes) {
|
|
15046
|
+
if (!process.stdin.isTTY) {
|
|
15047
|
+
console.error(
|
|
15048
|
+
chalk2.red(
|
|
15049
|
+
`\u2717 New secrets detected: ${trulyNewSecrets.join(", ")}`
|
|
15050
|
+
)
|
|
15051
|
+
);
|
|
15052
|
+
console.error(
|
|
15053
|
+
chalk2.dim(
|
|
15054
|
+
" Use --yes flag to approve new secrets in non-interactive mode."
|
|
15055
|
+
)
|
|
15056
|
+
);
|
|
15057
|
+
process.exit(1);
|
|
15058
|
+
}
|
|
15059
|
+
const response2 = await prompts({
|
|
15060
|
+
type: "confirm",
|
|
15061
|
+
name: "value",
|
|
15062
|
+
message: `Approve ${trulyNewSecrets.length} new secret(s)?`,
|
|
15063
|
+
initial: true
|
|
15064
|
+
});
|
|
15065
|
+
if (!response2.value) {
|
|
15066
|
+
console.log(chalk2.yellow("Compose cancelled."));
|
|
15067
|
+
process.exit(0);
|
|
15068
|
+
}
|
|
14883
15069
|
}
|
|
14884
15070
|
}
|
|
14885
15071
|
for (const [name] of newSecrets) {
|
|
@@ -15195,9 +15381,9 @@ var CodexEventParser = class {
|
|
|
15195
15381
|
}
|
|
15196
15382
|
}
|
|
15197
15383
|
if (itemType === "file_change" && item.changes && item.changes.length > 0) {
|
|
15198
|
-
const changes = item.changes.map((
|
|
15199
|
-
const action =
|
|
15200
|
-
return `${action}: ${
|
|
15384
|
+
const changes = item.changes.map((c11) => {
|
|
15385
|
+
const action = c11.kind === "add" ? "Created" : c11.kind === "modify" ? "Modified" : "Deleted";
|
|
15386
|
+
return `${action}: ${c11.path}`;
|
|
15201
15387
|
}).join("\n");
|
|
15202
15388
|
return {
|
|
15203
15389
|
type: "text",
|
|
@@ -15538,9 +15724,9 @@ var CodexEventRenderer = class {
|
|
|
15538
15724
|
return;
|
|
15539
15725
|
}
|
|
15540
15726
|
if (itemType === "file_change" && item.changes && item.changes.length > 0) {
|
|
15541
|
-
const summary = item.changes.map((
|
|
15542
|
-
const icon =
|
|
15543
|
-
return `${icon}${
|
|
15727
|
+
const summary = item.changes.map((c11) => {
|
|
15728
|
+
const icon = c11.kind === "add" ? "+" : c11.kind === "delete" ? "-" : "~";
|
|
15729
|
+
return `${icon}${c11.path}`;
|
|
15544
15730
|
}).join(", ");
|
|
15545
15731
|
console.log(chalk4.green("[files]") + ` ${summary}`);
|
|
15546
15732
|
return;
|
|
@@ -15959,8 +16145,9 @@ runCmd.command("resume").description("Resume an agent run from a checkpoint (use
|
|
|
15959
16145
|
console.error(chalk5.dim(" Checkpoint ID must be a valid UUID"));
|
|
15960
16146
|
process.exit(1);
|
|
15961
16147
|
}
|
|
15962
|
-
const
|
|
15963
|
-
const
|
|
16148
|
+
const checkpointInfo = await apiClient.getCheckpoint(checkpointId);
|
|
16149
|
+
const requiredSecretNames = checkpointInfo.agentComposeSnapshot.secretNames || [];
|
|
16150
|
+
const loadedSecrets = loadValues(secrets, requiredSecretNames);
|
|
15964
16151
|
if (verbose) {
|
|
15965
16152
|
logVerbosePreFlight("Resuming agent run from checkpoint", [
|
|
15966
16153
|
{ label: "Checkpoint ID", value: checkpointId },
|
|
@@ -16056,8 +16243,9 @@ runCmd.command("continue").description(
|
|
|
16056
16243
|
console.error(chalk5.dim(" Agent session ID must be a valid UUID"));
|
|
16057
16244
|
process.exit(1);
|
|
16058
16245
|
}
|
|
16059
|
-
const
|
|
16060
|
-
const
|
|
16246
|
+
const sessionInfo = await apiClient.getSession(agentSessionId);
|
|
16247
|
+
const requiredSecretNames = sessionInfo.secretNames || [];
|
|
16248
|
+
const loadedSecrets = loadValues(secrets, requiredSecretNames);
|
|
16061
16249
|
if (verbose) {
|
|
16062
16250
|
logVerbosePreFlight("Continuing agent run from session", [
|
|
16063
16251
|
{ label: "Session ID", value: agentSessionId },
|
|
@@ -16127,7 +16315,7 @@ runCmd.command("continue").description(
|
|
|
16127
16315
|
var runCommand = runCmd;
|
|
16128
16316
|
|
|
16129
16317
|
// src/commands/volume/index.ts
|
|
16130
|
-
import { Command as
|
|
16318
|
+
import { Command as Command9 } from "commander";
|
|
16131
16319
|
|
|
16132
16320
|
// src/commands/volume/init.ts
|
|
16133
16321
|
import { Command as Command3 } from "commander";
|
|
@@ -16181,8 +16369,53 @@ async function writeStorageConfig(storageName, basePath = process.cwd(), type =
|
|
|
16181
16369
|
await writeFile4(configPath, yamlContent, "utf8");
|
|
16182
16370
|
}
|
|
16183
16371
|
|
|
16372
|
+
// src/lib/prompt-utils.ts
|
|
16373
|
+
import prompts2 from "prompts";
|
|
16374
|
+
function isInteractive() {
|
|
16375
|
+
return process.stdout.isTTY === true;
|
|
16376
|
+
}
|
|
16377
|
+
async function promptText(message, initial, validate) {
|
|
16378
|
+
if (!isInteractive()) {
|
|
16379
|
+
return void 0;
|
|
16380
|
+
}
|
|
16381
|
+
const response = await prompts2(
|
|
16382
|
+
{
|
|
16383
|
+
type: "text",
|
|
16384
|
+
name: "value",
|
|
16385
|
+
message,
|
|
16386
|
+
initial,
|
|
16387
|
+
validate
|
|
16388
|
+
},
|
|
16389
|
+
{
|
|
16390
|
+
onCancel: () => {
|
|
16391
|
+
return false;
|
|
16392
|
+
}
|
|
16393
|
+
}
|
|
16394
|
+
);
|
|
16395
|
+
return response.value;
|
|
16396
|
+
}
|
|
16397
|
+
async function promptConfirm(message, initial = true) {
|
|
16398
|
+
if (!isInteractive()) {
|
|
16399
|
+
return void 0;
|
|
16400
|
+
}
|
|
16401
|
+
const response = await prompts2(
|
|
16402
|
+
{
|
|
16403
|
+
type: "confirm",
|
|
16404
|
+
name: "value",
|
|
16405
|
+
message,
|
|
16406
|
+
initial
|
|
16407
|
+
},
|
|
16408
|
+
{
|
|
16409
|
+
onCancel: () => {
|
|
16410
|
+
return false;
|
|
16411
|
+
}
|
|
16412
|
+
}
|
|
16413
|
+
);
|
|
16414
|
+
return response.value;
|
|
16415
|
+
}
|
|
16416
|
+
|
|
16184
16417
|
// src/commands/volume/init.ts
|
|
16185
|
-
var initCommand = new Command3().name("init").description("Initialize a volume in the current directory").action(async () => {
|
|
16418
|
+
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
16419
|
try {
|
|
16187
16420
|
const cwd = process.cwd();
|
|
16188
16421
|
const dirName = path7.basename(cwd);
|
|
@@ -16196,9 +16429,37 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
16196
16429
|
);
|
|
16197
16430
|
return;
|
|
16198
16431
|
}
|
|
16199
|
-
|
|
16432
|
+
let volumeName;
|
|
16433
|
+
if (options.name) {
|
|
16434
|
+
volumeName = options.name;
|
|
16435
|
+
} else if (!isInteractive()) {
|
|
16436
|
+
console.error(
|
|
16437
|
+
chalk6.red("\u2717 --name flag is required in non-interactive mode")
|
|
16438
|
+
);
|
|
16439
|
+
console.error(
|
|
16440
|
+
chalk6.dim(" Usage: vm0 volume init --name <volume-name>")
|
|
16441
|
+
);
|
|
16442
|
+
process.exit(1);
|
|
16443
|
+
} else {
|
|
16444
|
+
const defaultName = isValidStorageName(dirName) ? dirName : void 0;
|
|
16445
|
+
const name = await promptText(
|
|
16446
|
+
"Enter volume name",
|
|
16447
|
+
defaultName,
|
|
16448
|
+
(value) => {
|
|
16449
|
+
if (!isValidStorageName(value)) {
|
|
16450
|
+
return "Must be 3-64 characters, lowercase alphanumeric with hyphens";
|
|
16451
|
+
}
|
|
16452
|
+
return true;
|
|
16453
|
+
}
|
|
16454
|
+
);
|
|
16455
|
+
if (name === void 0) {
|
|
16456
|
+
console.log(chalk6.dim("Cancelled"));
|
|
16457
|
+
return;
|
|
16458
|
+
}
|
|
16459
|
+
volumeName = name;
|
|
16460
|
+
}
|
|
16200
16461
|
if (!isValidStorageName(volumeName)) {
|
|
16201
|
-
console.error(chalk6.red(`\u2717 Invalid volume name: "${
|
|
16462
|
+
console.error(chalk6.red(`\u2717 Invalid volume name: "${volumeName}"`));
|
|
16202
16463
|
console.error(
|
|
16203
16464
|
chalk6.dim(
|
|
16204
16465
|
" Volume names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
@@ -16228,7 +16489,7 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
16228
16489
|
// src/commands/volume/push.ts
|
|
16229
16490
|
import { Command as Command4 } from "commander";
|
|
16230
16491
|
import chalk7 from "chalk";
|
|
16231
|
-
function
|
|
16492
|
+
function formatBytes2(bytes) {
|
|
16232
16493
|
if (bytes === 0) return "0 B";
|
|
16233
16494
|
const k = 1024;
|
|
16234
16495
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -16264,7 +16525,7 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
16264
16525
|
}
|
|
16265
16526
|
console.log(chalk7.dim(` Version: ${shortVersion}`));
|
|
16266
16527
|
console.log(chalk7.dim(` Files: ${result.fileCount.toLocaleString()}`));
|
|
16267
|
-
console.log(chalk7.dim(` Size: ${
|
|
16528
|
+
console.log(chalk7.dim(` Size: ${formatBytes2(result.size)}`));
|
|
16268
16529
|
} catch (error43) {
|
|
16269
16530
|
console.error(chalk7.red("\u2717 Push failed"));
|
|
16270
16531
|
if (error43 instanceof Error) {
|
|
@@ -16295,7 +16556,7 @@ async function handleEmptyStorageResponse(cwd) {
|
|
|
16295
16556
|
}
|
|
16296
16557
|
|
|
16297
16558
|
// src/commands/volume/pull.ts
|
|
16298
|
-
function
|
|
16559
|
+
function formatBytes3(bytes) {
|
|
16299
16560
|
if (bytes === 0) return "0 B";
|
|
16300
16561
|
const k = 1024;
|
|
16301
16562
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -16354,7 +16615,7 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
16354
16615
|
}
|
|
16355
16616
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
16356
16617
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
16357
|
-
console.log(chalk9.green(`\u2713 Downloaded ${
|
|
16618
|
+
console.log(chalk9.green(`\u2713 Downloaded ${formatBytes3(tarBuffer.length)}`));
|
|
16358
16619
|
const tmpDir = fs6.mkdtempSync(path8.join(os4.tmpdir(), "vm0-"));
|
|
16359
16620
|
const tarPath = path8.join(tmpDir, "volume.tar.gz");
|
|
16360
16621
|
await fs6.promises.writeFile(tarPath, tarBuffer);
|
|
@@ -16390,7 +16651,7 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
16390
16651
|
// src/commands/volume/status.ts
|
|
16391
16652
|
import { Command as Command6 } from "commander";
|
|
16392
16653
|
import chalk10 from "chalk";
|
|
16393
|
-
function
|
|
16654
|
+
function formatBytes4(bytes) {
|
|
16394
16655
|
if (bytes === 0) return "0 B";
|
|
16395
16656
|
const k = 1024;
|
|
16396
16657
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -16437,7 +16698,7 @@ var statusCommand = new Command6().name("status").description("Show status of cl
|
|
|
16437
16698
|
console.log(chalk10.green("\u2713 Found"));
|
|
16438
16699
|
console.log(chalk10.dim(` Version: ${shortVersion}`));
|
|
16439
16700
|
console.log(chalk10.dim(` Files: ${info.fileCount.toLocaleString()}`));
|
|
16440
|
-
console.log(chalk10.dim(` Size: ${
|
|
16701
|
+
console.log(chalk10.dim(` Size: ${formatBytes4(info.size)}`));
|
|
16441
16702
|
}
|
|
16442
16703
|
} catch (error43) {
|
|
16443
16704
|
console.error(chalk10.red("\u2717 Status check failed"));
|
|
@@ -16448,85 +16709,275 @@ var statusCommand = new Command6().name("status").description("Show status of cl
|
|
|
16448
16709
|
}
|
|
16449
16710
|
});
|
|
16450
16711
|
|
|
16712
|
+
// src/commands/volume/list.ts
|
|
16713
|
+
import { Command as Command7 } from "commander";
|
|
16714
|
+
import chalk11 from "chalk";
|
|
16715
|
+
var listCommand = new Command7().name("list").alias("ls").description("List all remote volumes").action(async () => {
|
|
16716
|
+
try {
|
|
16717
|
+
const url2 = "/api/storages/list?type=volume";
|
|
16718
|
+
const response = await apiClient.get(url2);
|
|
16719
|
+
if (!response.ok) {
|
|
16720
|
+
const error43 = await response.json();
|
|
16721
|
+
throw new Error(error43.error?.message || "List failed");
|
|
16722
|
+
}
|
|
16723
|
+
const items = await response.json();
|
|
16724
|
+
if (items.length === 0) {
|
|
16725
|
+
console.log(chalk11.dim("No volumes found"));
|
|
16726
|
+
console.log(
|
|
16727
|
+
chalk11.dim(" Create one with: vm0 volume init && vm0 volume push")
|
|
16728
|
+
);
|
|
16729
|
+
return;
|
|
16730
|
+
}
|
|
16731
|
+
const nameWidth = Math.max(4, ...items.map((i) => i.name.length));
|
|
16732
|
+
const sizeWidth = Math.max(
|
|
16733
|
+
4,
|
|
16734
|
+
...items.map((i) => formatBytes(i.size).length)
|
|
16735
|
+
);
|
|
16736
|
+
const filesWidth = Math.max(
|
|
16737
|
+
5,
|
|
16738
|
+
...items.map((i) => i.fileCount.toString().length)
|
|
16739
|
+
);
|
|
16740
|
+
const header = [
|
|
16741
|
+
"NAME".padEnd(nameWidth),
|
|
16742
|
+
"SIZE".padStart(sizeWidth),
|
|
16743
|
+
"FILES".padStart(filesWidth),
|
|
16744
|
+
"UPDATED"
|
|
16745
|
+
].join(" ");
|
|
16746
|
+
console.log(chalk11.dim(header));
|
|
16747
|
+
for (const item of items) {
|
|
16748
|
+
const row = [
|
|
16749
|
+
item.name.padEnd(nameWidth),
|
|
16750
|
+
formatBytes(item.size).padStart(sizeWidth),
|
|
16751
|
+
item.fileCount.toString().padStart(filesWidth),
|
|
16752
|
+
formatRelativeTime(item.updatedAt)
|
|
16753
|
+
].join(" ");
|
|
16754
|
+
console.log(row);
|
|
16755
|
+
}
|
|
16756
|
+
} catch (error43) {
|
|
16757
|
+
console.error(chalk11.red("\u2717 Failed to list volumes"));
|
|
16758
|
+
if (error43 instanceof Error) {
|
|
16759
|
+
if (error43.message.includes("Not authenticated")) {
|
|
16760
|
+
console.error(chalk11.dim(" Run: vm0 auth login"));
|
|
16761
|
+
} else {
|
|
16762
|
+
console.error(chalk11.dim(` ${error43.message}`));
|
|
16763
|
+
}
|
|
16764
|
+
}
|
|
16765
|
+
process.exit(1);
|
|
16766
|
+
}
|
|
16767
|
+
});
|
|
16768
|
+
|
|
16769
|
+
// src/commands/volume/clone.ts
|
|
16770
|
+
import { Command as Command8 } from "commander";
|
|
16771
|
+
import chalk13 from "chalk";
|
|
16772
|
+
|
|
16773
|
+
// src/lib/clone-utils.ts
|
|
16774
|
+
import chalk12 from "chalk";
|
|
16775
|
+
import path9 from "path";
|
|
16776
|
+
import * as fs7 from "fs";
|
|
16777
|
+
import * as os5 from "os";
|
|
16778
|
+
import * as tar4 from "tar";
|
|
16779
|
+
async function cloneStorage(name, type, destination, options = {}) {
|
|
16780
|
+
const typeLabel = type === "artifact" ? "artifact" : "volume";
|
|
16781
|
+
if (fs7.existsSync(destination)) {
|
|
16782
|
+
throw new Error(`Directory "${destination}" already exists`);
|
|
16783
|
+
}
|
|
16784
|
+
console.log(chalk12.dim(`Checking remote ${typeLabel}...`));
|
|
16785
|
+
let url2 = `/api/storages/download?name=${encodeURIComponent(name)}&type=${type}`;
|
|
16786
|
+
if (options.version) {
|
|
16787
|
+
url2 += `&version=${encodeURIComponent(options.version)}`;
|
|
16788
|
+
}
|
|
16789
|
+
const response = await apiClient.get(url2);
|
|
16790
|
+
if (!response.ok) {
|
|
16791
|
+
if (response.status === 404) {
|
|
16792
|
+
throw new Error(
|
|
16793
|
+
`${typeLabel.charAt(0).toUpperCase() + typeLabel.slice(1)} "${name}" not found`
|
|
16794
|
+
);
|
|
16795
|
+
}
|
|
16796
|
+
const error43 = await response.json();
|
|
16797
|
+
throw new Error(error43.error?.message || "Clone failed");
|
|
16798
|
+
}
|
|
16799
|
+
const downloadInfo = await response.json();
|
|
16800
|
+
console.log(chalk12.dim(`Creating directory: ${destination}/`));
|
|
16801
|
+
await fs7.promises.mkdir(destination, { recursive: true });
|
|
16802
|
+
if (downloadInfo.empty) {
|
|
16803
|
+
await writeStorageConfig(name, destination, type);
|
|
16804
|
+
console.log(chalk12.green(`\u2713 Cloned empty ${typeLabel}: ${name}`));
|
|
16805
|
+
console.log(chalk12.dim(`\u2713 Initialized .vm0/storage.yaml`));
|
|
16806
|
+
return {
|
|
16807
|
+
success: true,
|
|
16808
|
+
fileCount: 0,
|
|
16809
|
+
size: 0,
|
|
16810
|
+
versionId: downloadInfo.versionId
|
|
16811
|
+
};
|
|
16812
|
+
}
|
|
16813
|
+
if (!downloadInfo.url) {
|
|
16814
|
+
throw new Error("No download URL returned");
|
|
16815
|
+
}
|
|
16816
|
+
console.log(chalk12.dim("Downloading from S3..."));
|
|
16817
|
+
const s3Response = await fetch(downloadInfo.url);
|
|
16818
|
+
if (!s3Response.ok) {
|
|
16819
|
+
await fs7.promises.rm(destination, { recursive: true, force: true });
|
|
16820
|
+
throw new Error(`S3 download failed: ${s3Response.status}`);
|
|
16821
|
+
}
|
|
16822
|
+
const arrayBuffer = await s3Response.arrayBuffer();
|
|
16823
|
+
const tarBuffer = Buffer.from(arrayBuffer);
|
|
16824
|
+
console.log(chalk12.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
|
|
16825
|
+
const tmpDir = fs7.mkdtempSync(path9.join(os5.tmpdir(), "vm0-clone-"));
|
|
16826
|
+
const tarPath = path9.join(tmpDir, "archive.tar.gz");
|
|
16827
|
+
await fs7.promises.writeFile(tarPath, tarBuffer);
|
|
16828
|
+
const files = await listTarFiles(tarPath);
|
|
16829
|
+
console.log(chalk12.dim("Extracting files..."));
|
|
16830
|
+
await tar4.extract({
|
|
16831
|
+
file: tarPath,
|
|
16832
|
+
cwd: destination,
|
|
16833
|
+
gzip: true
|
|
16834
|
+
});
|
|
16835
|
+
await fs7.promises.unlink(tarPath);
|
|
16836
|
+
await fs7.promises.rmdir(tmpDir);
|
|
16837
|
+
console.log(chalk12.green(`\u2713 Extracted ${files.length} files`));
|
|
16838
|
+
await writeStorageConfig(name, destination, type);
|
|
16839
|
+
console.log(chalk12.green(`\u2713 Initialized .vm0/storage.yaml`));
|
|
16840
|
+
return {
|
|
16841
|
+
success: true,
|
|
16842
|
+
fileCount: downloadInfo.fileCount,
|
|
16843
|
+
size: downloadInfo.size,
|
|
16844
|
+
versionId: downloadInfo.versionId
|
|
16845
|
+
};
|
|
16846
|
+
}
|
|
16847
|
+
|
|
16848
|
+
// src/commands/volume/clone.ts
|
|
16849
|
+
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) => {
|
|
16850
|
+
try {
|
|
16851
|
+
const targetDir = destination || name;
|
|
16852
|
+
console.log(`Cloning volume: ${name}`);
|
|
16853
|
+
const result = await cloneStorage(name, "volume", targetDir);
|
|
16854
|
+
console.log(chalk13.green(`
|
|
16855
|
+
\u2713 Successfully cloned volume: ${name}`));
|
|
16856
|
+
console.log(chalk13.dim(` Location: ${targetDir}/`));
|
|
16857
|
+
console.log(chalk13.dim(` Version: ${result.versionId.slice(0, 8)}`));
|
|
16858
|
+
} catch (error43) {
|
|
16859
|
+
console.error(chalk13.red("\u2717 Clone failed"));
|
|
16860
|
+
if (error43 instanceof Error) {
|
|
16861
|
+
if (error43.message.includes("Not authenticated")) {
|
|
16862
|
+
console.error(chalk13.dim(" Run: vm0 auth login"));
|
|
16863
|
+
} else {
|
|
16864
|
+
console.error(chalk13.dim(` ${error43.message}`));
|
|
16865
|
+
}
|
|
16866
|
+
}
|
|
16867
|
+
process.exit(1);
|
|
16868
|
+
}
|
|
16869
|
+
});
|
|
16870
|
+
|
|
16451
16871
|
// src/commands/volume/index.ts
|
|
16452
|
-
var volumeCommand = new
|
|
16872
|
+
var volumeCommand = new Command9().name("volume").description("Manage cloud volumes").addCommand(initCommand).addCommand(pushCommand).addCommand(pullCommand).addCommand(statusCommand).addCommand(listCommand).addCommand(cloneCommand);
|
|
16453
16873
|
|
|
16454
16874
|
// src/commands/artifact/index.ts
|
|
16455
|
-
import { Command as
|
|
16875
|
+
import { Command as Command16 } from "commander";
|
|
16456
16876
|
|
|
16457
16877
|
// src/commands/artifact/init.ts
|
|
16458
|
-
import { Command as
|
|
16459
|
-
import
|
|
16460
|
-
import
|
|
16461
|
-
var initCommand2 = new
|
|
16878
|
+
import { Command as Command10 } from "commander";
|
|
16879
|
+
import chalk14 from "chalk";
|
|
16880
|
+
import path10 from "path";
|
|
16881
|
+
var initCommand2 = new Command10().name("init").description("Initialize an artifact in the current directory").option(
|
|
16882
|
+
"-n, --name <name>",
|
|
16883
|
+
"Artifact name (required in non-interactive mode)"
|
|
16884
|
+
).action(async (options) => {
|
|
16462
16885
|
try {
|
|
16463
16886
|
const cwd = process.cwd();
|
|
16464
|
-
const dirName =
|
|
16887
|
+
const dirName = path10.basename(cwd);
|
|
16465
16888
|
const existingConfig = await readStorageConfig(cwd);
|
|
16466
16889
|
if (existingConfig) {
|
|
16467
16890
|
if (existingConfig.type === "artifact") {
|
|
16468
16891
|
console.log(
|
|
16469
|
-
|
|
16892
|
+
chalk14.yellow(
|
|
16470
16893
|
`Artifact already initialized: ${existingConfig.name}`
|
|
16471
16894
|
)
|
|
16472
16895
|
);
|
|
16473
16896
|
} else {
|
|
16474
16897
|
console.log(
|
|
16475
|
-
|
|
16898
|
+
chalk14.yellow(
|
|
16476
16899
|
`Directory already initialized as volume: ${existingConfig.name}`
|
|
16477
16900
|
)
|
|
16478
16901
|
);
|
|
16479
16902
|
console.log(
|
|
16480
|
-
|
|
16903
|
+
chalk14.dim(
|
|
16481
16904
|
" To change type, delete .vm0/storage.yaml and reinitialize"
|
|
16482
16905
|
)
|
|
16483
16906
|
);
|
|
16484
16907
|
}
|
|
16485
16908
|
console.log(
|
|
16486
|
-
|
|
16909
|
+
chalk14.dim(`Config file: ${path10.join(cwd, ".vm0", "storage.yaml")}`)
|
|
16487
16910
|
);
|
|
16488
16911
|
return;
|
|
16489
16912
|
}
|
|
16490
|
-
|
|
16913
|
+
let artifactName;
|
|
16914
|
+
if (options.name) {
|
|
16915
|
+
artifactName = options.name;
|
|
16916
|
+
} else if (!isInteractive()) {
|
|
16917
|
+
console.error(
|
|
16918
|
+
chalk14.red("\u2717 --name flag is required in non-interactive mode")
|
|
16919
|
+
);
|
|
16920
|
+
console.error(
|
|
16921
|
+
chalk14.dim(" Usage: vm0 artifact init --name <artifact-name>")
|
|
16922
|
+
);
|
|
16923
|
+
process.exit(1);
|
|
16924
|
+
} else {
|
|
16925
|
+
const defaultName = isValidStorageName(dirName) ? dirName : void 0;
|
|
16926
|
+
const name = await promptText(
|
|
16927
|
+
"Enter artifact name",
|
|
16928
|
+
defaultName,
|
|
16929
|
+
(value) => {
|
|
16930
|
+
if (!isValidStorageName(value)) {
|
|
16931
|
+
return "Must be 3-64 characters, lowercase alphanumeric with hyphens";
|
|
16932
|
+
}
|
|
16933
|
+
return true;
|
|
16934
|
+
}
|
|
16935
|
+
);
|
|
16936
|
+
if (name === void 0) {
|
|
16937
|
+
console.log(chalk14.dim("Cancelled"));
|
|
16938
|
+
return;
|
|
16939
|
+
}
|
|
16940
|
+
artifactName = name;
|
|
16941
|
+
}
|
|
16491
16942
|
if (!isValidStorageName(artifactName)) {
|
|
16492
|
-
console.error(
|
|
16943
|
+
console.error(chalk14.red(`\u2717 Invalid artifact name: "${artifactName}"`));
|
|
16493
16944
|
console.error(
|
|
16494
|
-
|
|
16945
|
+
chalk14.dim(
|
|
16495
16946
|
" Artifact names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
16496
16947
|
)
|
|
16497
16948
|
);
|
|
16498
16949
|
console.error(
|
|
16499
|
-
|
|
16950
|
+
chalk14.dim(" Example: my-project, user-workspace, code-artifact")
|
|
16500
16951
|
);
|
|
16501
16952
|
process.exit(1);
|
|
16502
16953
|
}
|
|
16503
16954
|
await writeStorageConfig(artifactName, cwd, "artifact");
|
|
16504
|
-
console.log(
|
|
16955
|
+
console.log(chalk14.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
16505
16956
|
console.log(
|
|
16506
|
-
|
|
16507
|
-
`\u2713 Config saved to ${
|
|
16957
|
+
chalk14.dim(
|
|
16958
|
+
`\u2713 Config saved to ${path10.join(cwd, ".vm0", "storage.yaml")}`
|
|
16508
16959
|
)
|
|
16509
16960
|
);
|
|
16510
16961
|
} catch (error43) {
|
|
16511
|
-
console.error(
|
|
16962
|
+
console.error(chalk14.red("\u2717 Failed to initialize artifact"));
|
|
16512
16963
|
if (error43 instanceof Error) {
|
|
16513
|
-
console.error(
|
|
16964
|
+
console.error(chalk14.dim(` ${error43.message}`));
|
|
16514
16965
|
}
|
|
16515
16966
|
process.exit(1);
|
|
16516
16967
|
}
|
|
16517
16968
|
});
|
|
16518
16969
|
|
|
16519
16970
|
// src/commands/artifact/push.ts
|
|
16520
|
-
import { Command as
|
|
16521
|
-
import
|
|
16522
|
-
function
|
|
16971
|
+
import { Command as Command11 } from "commander";
|
|
16972
|
+
import chalk15 from "chalk";
|
|
16973
|
+
function formatBytes5(bytes) {
|
|
16523
16974
|
if (bytes === 0) return "0 B";
|
|
16524
16975
|
const k = 1024;
|
|
16525
16976
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
16526
16977
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
16527
16978
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
16528
16979
|
}
|
|
16529
|
-
var pushCommand2 = new
|
|
16980
|
+
var pushCommand2 = new Command11().name("push").description("Push local files to cloud artifact").option(
|
|
16530
16981
|
"-f, --force",
|
|
16531
16982
|
"Force upload even if content unchanged (recreate archive)"
|
|
16532
16983
|
).action(async (options) => {
|
|
@@ -16534,76 +16985,76 @@ var pushCommand2 = new Command9().name("push").description("Push local files to
|
|
|
16534
16985
|
const cwd = process.cwd();
|
|
16535
16986
|
const config2 = await readStorageConfig(cwd);
|
|
16536
16987
|
if (!config2) {
|
|
16537
|
-
console.error(
|
|
16538
|
-
console.error(
|
|
16988
|
+
console.error(chalk15.red("\u2717 No artifact initialized in this directory"));
|
|
16989
|
+
console.error(chalk15.dim(" Run: vm0 artifact init"));
|
|
16539
16990
|
process.exit(1);
|
|
16540
16991
|
}
|
|
16541
16992
|
if (config2.type !== "artifact") {
|
|
16542
16993
|
console.error(
|
|
16543
|
-
|
|
16994
|
+
chalk15.red(
|
|
16544
16995
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
16545
16996
|
)
|
|
16546
16997
|
);
|
|
16547
|
-
console.error(
|
|
16998
|
+
console.error(chalk15.dim(" Use: vm0 volume push"));
|
|
16548
16999
|
process.exit(1);
|
|
16549
17000
|
}
|
|
16550
17001
|
console.log(`Pushing artifact: ${config2.name}`);
|
|
16551
17002
|
const result = await directUpload(config2.name, "artifact", cwd, {
|
|
16552
17003
|
onProgress: (message) => {
|
|
16553
|
-
console.log(
|
|
17004
|
+
console.log(chalk15.dim(message));
|
|
16554
17005
|
},
|
|
16555
17006
|
force: options.force
|
|
16556
17007
|
});
|
|
16557
17008
|
const shortVersion = result.versionId.slice(0, 8);
|
|
16558
17009
|
if (result.empty) {
|
|
16559
|
-
console.log(
|
|
17010
|
+
console.log(chalk15.yellow("No files found (empty artifact)"));
|
|
16560
17011
|
} else if (result.deduplicated) {
|
|
16561
|
-
console.log(
|
|
17012
|
+
console.log(chalk15.green("\u2713 Content unchanged (deduplicated)"));
|
|
16562
17013
|
} else {
|
|
16563
|
-
console.log(
|
|
17014
|
+
console.log(chalk15.green("\u2713 Upload complete"));
|
|
16564
17015
|
}
|
|
16565
|
-
console.log(
|
|
16566
|
-
console.log(
|
|
16567
|
-
console.log(
|
|
17016
|
+
console.log(chalk15.dim(` Version: ${shortVersion}`));
|
|
17017
|
+
console.log(chalk15.dim(` Files: ${result.fileCount.toLocaleString()}`));
|
|
17018
|
+
console.log(chalk15.dim(` Size: ${formatBytes5(result.size)}`));
|
|
16568
17019
|
} catch (error43) {
|
|
16569
|
-
console.error(
|
|
17020
|
+
console.error(chalk15.red("\u2717 Push failed"));
|
|
16570
17021
|
if (error43 instanceof Error) {
|
|
16571
|
-
console.error(
|
|
17022
|
+
console.error(chalk15.dim(` ${error43.message}`));
|
|
16572
17023
|
}
|
|
16573
17024
|
process.exit(1);
|
|
16574
17025
|
}
|
|
16575
17026
|
});
|
|
16576
17027
|
|
|
16577
17028
|
// src/commands/artifact/pull.ts
|
|
16578
|
-
import { Command as
|
|
16579
|
-
import
|
|
16580
|
-
import
|
|
16581
|
-
import * as
|
|
16582
|
-
import * as
|
|
16583
|
-
import * as
|
|
16584
|
-
function
|
|
17029
|
+
import { Command as Command12 } from "commander";
|
|
17030
|
+
import chalk16 from "chalk";
|
|
17031
|
+
import path11 from "path";
|
|
17032
|
+
import * as fs8 from "fs";
|
|
17033
|
+
import * as os6 from "os";
|
|
17034
|
+
import * as tar5 from "tar";
|
|
17035
|
+
function formatBytes6(bytes) {
|
|
16585
17036
|
if (bytes === 0) return "0 B";
|
|
16586
17037
|
const k = 1024;
|
|
16587
17038
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
16588
17039
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
16589
17040
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
16590
17041
|
}
|
|
16591
|
-
var pullCommand2 = new
|
|
17042
|
+
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
17043
|
try {
|
|
16593
17044
|
const cwd = process.cwd();
|
|
16594
17045
|
const config2 = await readStorageConfig(cwd);
|
|
16595
17046
|
if (!config2) {
|
|
16596
|
-
console.error(
|
|
16597
|
-
console.error(
|
|
17047
|
+
console.error(chalk16.red("\u2717 No artifact initialized in this directory"));
|
|
17048
|
+
console.error(chalk16.dim(" Run: vm0 artifact init"));
|
|
16598
17049
|
process.exit(1);
|
|
16599
17050
|
}
|
|
16600
17051
|
if (config2.type !== "artifact") {
|
|
16601
17052
|
console.error(
|
|
16602
|
-
|
|
17053
|
+
chalk16.red(
|
|
16603
17054
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
16604
17055
|
)
|
|
16605
17056
|
);
|
|
16606
|
-
console.error(
|
|
17057
|
+
console.error(chalk16.dim(" Use: vm0 volume pull"));
|
|
16607
17058
|
process.exit(1);
|
|
16608
17059
|
}
|
|
16609
17060
|
if (versionId) {
|
|
@@ -16611,7 +17062,7 @@ var pullCommand2 = new Command10().name("pull").description("Pull cloud artifact
|
|
|
16611
17062
|
} else {
|
|
16612
17063
|
console.log(`Pulling artifact: ${config2.name}`);
|
|
16613
17064
|
}
|
|
16614
|
-
console.log(
|
|
17065
|
+
console.log(chalk16.dim("Getting download URL..."));
|
|
16615
17066
|
let url2 = `/api/storages/download?name=${encodeURIComponent(config2.name)}&type=artifact`;
|
|
16616
17067
|
if (versionId) {
|
|
16617
17068
|
url2 += `&version=${encodeURIComponent(versionId)}`;
|
|
@@ -16619,14 +17070,14 @@ var pullCommand2 = new Command10().name("pull").description("Pull cloud artifact
|
|
|
16619
17070
|
const response = await apiClient.get(url2);
|
|
16620
17071
|
if (!response.ok) {
|
|
16621
17072
|
if (response.status === 404) {
|
|
16622
|
-
console.error(
|
|
17073
|
+
console.error(chalk16.red(`\u2717 Artifact "${config2.name}" not found`));
|
|
16623
17074
|
console.error(
|
|
16624
|
-
|
|
17075
|
+
chalk16.dim(
|
|
16625
17076
|
" Make sure the artifact name is correct in .vm0/storage.yaml"
|
|
16626
17077
|
)
|
|
16627
17078
|
);
|
|
16628
17079
|
console.error(
|
|
16629
|
-
|
|
17080
|
+
chalk16.dim(" Or push the artifact first with: vm0 artifact push")
|
|
16630
17081
|
);
|
|
16631
17082
|
} else {
|
|
16632
17083
|
const error43 = await response.json();
|
|
@@ -16642,18 +17093,18 @@ var pullCommand2 = new Command10().name("pull").description("Pull cloud artifact
|
|
|
16642
17093
|
if (!downloadInfo.url) {
|
|
16643
17094
|
throw new Error("No download URL returned");
|
|
16644
17095
|
}
|
|
16645
|
-
console.log(
|
|
17096
|
+
console.log(chalk16.dim("Downloading from S3..."));
|
|
16646
17097
|
const s3Response = await fetch(downloadInfo.url);
|
|
16647
17098
|
if (!s3Response.ok) {
|
|
16648
17099
|
throw new Error(`S3 download failed: ${s3Response.status}`);
|
|
16649
17100
|
}
|
|
16650
17101
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
16651
17102
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
16652
|
-
console.log(
|
|
16653
|
-
const tmpDir =
|
|
16654
|
-
const tarPath =
|
|
16655
|
-
await
|
|
16656
|
-
console.log(
|
|
17103
|
+
console.log(chalk16.green(`\u2713 Downloaded ${formatBytes6(tarBuffer.length)}`));
|
|
17104
|
+
const tmpDir = fs8.mkdtempSync(path11.join(os6.tmpdir(), "vm0-"));
|
|
17105
|
+
const tarPath = path11.join(tmpDir, "artifact.tar.gz");
|
|
17106
|
+
await fs8.promises.writeFile(tarPath, tarBuffer);
|
|
17107
|
+
console.log(chalk16.dim("Syncing local files..."));
|
|
16657
17108
|
const remoteFiles = await listTarFiles(tarPath);
|
|
16658
17109
|
const remoteFilesSet = new Set(
|
|
16659
17110
|
remoteFiles.map((f) => f.replace(/\\/g, "/"))
|
|
@@ -16661,53 +17112,53 @@ var pullCommand2 = new Command10().name("pull").description("Pull cloud artifact
|
|
|
16661
17112
|
const removedCount = await removeExtraFiles(cwd, remoteFilesSet);
|
|
16662
17113
|
if (removedCount > 0) {
|
|
16663
17114
|
console.log(
|
|
16664
|
-
|
|
17115
|
+
chalk16.green(`\u2713 Removed ${removedCount} files not in remote`)
|
|
16665
17116
|
);
|
|
16666
17117
|
}
|
|
16667
|
-
console.log(
|
|
16668
|
-
await
|
|
17118
|
+
console.log(chalk16.dim("Extracting files..."));
|
|
17119
|
+
await tar5.extract({
|
|
16669
17120
|
file: tarPath,
|
|
16670
17121
|
cwd,
|
|
16671
17122
|
gzip: true
|
|
16672
17123
|
});
|
|
16673
|
-
await
|
|
16674
|
-
await
|
|
16675
|
-
console.log(
|
|
17124
|
+
await fs8.promises.unlink(tarPath);
|
|
17125
|
+
await fs8.promises.rmdir(tmpDir);
|
|
17126
|
+
console.log(chalk16.green(`\u2713 Extracted ${remoteFiles.length} files`));
|
|
16676
17127
|
} catch (error43) {
|
|
16677
|
-
console.error(
|
|
17128
|
+
console.error(chalk16.red("\u2717 Pull failed"));
|
|
16678
17129
|
if (error43 instanceof Error) {
|
|
16679
|
-
console.error(
|
|
17130
|
+
console.error(chalk16.dim(` ${error43.message}`));
|
|
16680
17131
|
}
|
|
16681
17132
|
process.exit(1);
|
|
16682
17133
|
}
|
|
16683
17134
|
});
|
|
16684
17135
|
|
|
16685
17136
|
// src/commands/artifact/status.ts
|
|
16686
|
-
import { Command as
|
|
16687
|
-
import
|
|
16688
|
-
function
|
|
17137
|
+
import { Command as Command13 } from "commander";
|
|
17138
|
+
import chalk17 from "chalk";
|
|
17139
|
+
function formatBytes7(bytes) {
|
|
16689
17140
|
if (bytes === 0) return "0 B";
|
|
16690
17141
|
const k = 1024;
|
|
16691
17142
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
16692
17143
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
16693
17144
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
16694
17145
|
}
|
|
16695
|
-
var statusCommand2 = new
|
|
17146
|
+
var statusCommand2 = new Command13().name("status").description("Show status of cloud artifact").action(async () => {
|
|
16696
17147
|
try {
|
|
16697
17148
|
const cwd = process.cwd();
|
|
16698
17149
|
const config2 = await readStorageConfig(cwd);
|
|
16699
17150
|
if (!config2) {
|
|
16700
|
-
console.error(
|
|
16701
|
-
console.error(
|
|
17151
|
+
console.error(chalk17.red("\u2717 No artifact initialized in this directory"));
|
|
17152
|
+
console.error(chalk17.dim(" Run: vm0 artifact init"));
|
|
16702
17153
|
process.exit(1);
|
|
16703
17154
|
}
|
|
16704
17155
|
if (config2.type !== "artifact") {
|
|
16705
17156
|
console.error(
|
|
16706
|
-
|
|
17157
|
+
chalk17.red(
|
|
16707
17158
|
"\u2717 This directory is initialized as a volume, not an artifact"
|
|
16708
17159
|
)
|
|
16709
17160
|
);
|
|
16710
|
-
console.error(
|
|
17161
|
+
console.error(chalk17.dim(" Use: vm0 volume status"));
|
|
16711
17162
|
process.exit(1);
|
|
16712
17163
|
}
|
|
16713
17164
|
console.log(`Checking artifact: ${config2.name}`);
|
|
@@ -16715,8 +17166,8 @@ var statusCommand2 = new Command11().name("status").description("Show status of
|
|
|
16715
17166
|
const response = await apiClient.get(url2);
|
|
16716
17167
|
if (!response.ok) {
|
|
16717
17168
|
if (response.status === 404) {
|
|
16718
|
-
console.error(
|
|
16719
|
-
console.error(
|
|
17169
|
+
console.error(chalk17.red("\u2717 Not found on remote"));
|
|
17170
|
+
console.error(chalk17.dim(" Run: vm0 artifact push"));
|
|
16720
17171
|
} else {
|
|
16721
17172
|
const error43 = await response.json();
|
|
16722
17173
|
throw new Error(error43.error?.message || "Status check failed");
|
|
@@ -16726,32 +17177,116 @@ var statusCommand2 = new Command11().name("status").description("Show status of
|
|
|
16726
17177
|
const info = await response.json();
|
|
16727
17178
|
const shortVersion = info.versionId.slice(0, 8);
|
|
16728
17179
|
if (info.empty) {
|
|
16729
|
-
console.log(
|
|
16730
|
-
console.log(
|
|
17180
|
+
console.log(chalk17.green("\u2713 Found (empty)"));
|
|
17181
|
+
console.log(chalk17.dim(` Version: ${shortVersion}`));
|
|
16731
17182
|
} else {
|
|
16732
|
-
console.log(
|
|
16733
|
-
console.log(
|
|
16734
|
-
console.log(
|
|
16735
|
-
console.log(
|
|
17183
|
+
console.log(chalk17.green("\u2713 Found"));
|
|
17184
|
+
console.log(chalk17.dim(` Version: ${shortVersion}`));
|
|
17185
|
+
console.log(chalk17.dim(` Files: ${info.fileCount.toLocaleString()}`));
|
|
17186
|
+
console.log(chalk17.dim(` Size: ${formatBytes7(info.size)}`));
|
|
16736
17187
|
}
|
|
16737
17188
|
} catch (error43) {
|
|
16738
|
-
console.error(
|
|
17189
|
+
console.error(chalk17.red("\u2717 Status check failed"));
|
|
16739
17190
|
if (error43 instanceof Error) {
|
|
16740
|
-
console.error(
|
|
17191
|
+
console.error(chalk17.dim(` ${error43.message}`));
|
|
17192
|
+
}
|
|
17193
|
+
process.exit(1);
|
|
17194
|
+
}
|
|
17195
|
+
});
|
|
17196
|
+
|
|
17197
|
+
// src/commands/artifact/list.ts
|
|
17198
|
+
import { Command as Command14 } from "commander";
|
|
17199
|
+
import chalk18 from "chalk";
|
|
17200
|
+
var listCommand2 = new Command14().name("list").alias("ls").description("List all remote artifacts").action(async () => {
|
|
17201
|
+
try {
|
|
17202
|
+
const url2 = "/api/storages/list?type=artifact";
|
|
17203
|
+
const response = await apiClient.get(url2);
|
|
17204
|
+
if (!response.ok) {
|
|
17205
|
+
const error43 = await response.json();
|
|
17206
|
+
throw new Error(error43.error?.message || "List failed");
|
|
17207
|
+
}
|
|
17208
|
+
const items = await response.json();
|
|
17209
|
+
if (items.length === 0) {
|
|
17210
|
+
console.log(chalk18.dim("No artifacts found"));
|
|
17211
|
+
console.log(
|
|
17212
|
+
chalk18.dim(
|
|
17213
|
+
" Create one with: vm0 artifact init && vm0 artifact push"
|
|
17214
|
+
)
|
|
17215
|
+
);
|
|
17216
|
+
return;
|
|
17217
|
+
}
|
|
17218
|
+
const nameWidth = Math.max(4, ...items.map((i) => i.name.length));
|
|
17219
|
+
const sizeWidth = Math.max(
|
|
17220
|
+
4,
|
|
17221
|
+
...items.map((i) => formatBytes(i.size).length)
|
|
17222
|
+
);
|
|
17223
|
+
const filesWidth = Math.max(
|
|
17224
|
+
5,
|
|
17225
|
+
...items.map((i) => i.fileCount.toString().length)
|
|
17226
|
+
);
|
|
17227
|
+
const header = [
|
|
17228
|
+
"NAME".padEnd(nameWidth),
|
|
17229
|
+
"SIZE".padStart(sizeWidth),
|
|
17230
|
+
"FILES".padStart(filesWidth),
|
|
17231
|
+
"UPDATED"
|
|
17232
|
+
].join(" ");
|
|
17233
|
+
console.log(chalk18.dim(header));
|
|
17234
|
+
for (const item of items) {
|
|
17235
|
+
const row = [
|
|
17236
|
+
item.name.padEnd(nameWidth),
|
|
17237
|
+
formatBytes(item.size).padStart(sizeWidth),
|
|
17238
|
+
item.fileCount.toString().padStart(filesWidth),
|
|
17239
|
+
formatRelativeTime(item.updatedAt)
|
|
17240
|
+
].join(" ");
|
|
17241
|
+
console.log(row);
|
|
17242
|
+
}
|
|
17243
|
+
} catch (error43) {
|
|
17244
|
+
console.error(chalk18.red("\u2717 Failed to list artifacts"));
|
|
17245
|
+
if (error43 instanceof Error) {
|
|
17246
|
+
if (error43.message.includes("Not authenticated")) {
|
|
17247
|
+
console.error(chalk18.dim(" Run: vm0 auth login"));
|
|
17248
|
+
} else {
|
|
17249
|
+
console.error(chalk18.dim(` ${error43.message}`));
|
|
17250
|
+
}
|
|
17251
|
+
}
|
|
17252
|
+
process.exit(1);
|
|
17253
|
+
}
|
|
17254
|
+
});
|
|
17255
|
+
|
|
17256
|
+
// src/commands/artifact/clone.ts
|
|
17257
|
+
import { Command as Command15 } from "commander";
|
|
17258
|
+
import chalk19 from "chalk";
|
|
17259
|
+
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) => {
|
|
17260
|
+
try {
|
|
17261
|
+
const targetDir = destination || name;
|
|
17262
|
+
console.log(`Cloning artifact: ${name}`);
|
|
17263
|
+
const result = await cloneStorage(name, "artifact", targetDir);
|
|
17264
|
+
console.log(chalk19.green(`
|
|
17265
|
+
\u2713 Successfully cloned artifact: ${name}`));
|
|
17266
|
+
console.log(chalk19.dim(` Location: ${targetDir}/`));
|
|
17267
|
+
console.log(chalk19.dim(` Version: ${result.versionId.slice(0, 8)}`));
|
|
17268
|
+
} catch (error43) {
|
|
17269
|
+
console.error(chalk19.red("\u2717 Clone failed"));
|
|
17270
|
+
if (error43 instanceof Error) {
|
|
17271
|
+
if (error43.message.includes("Not authenticated")) {
|
|
17272
|
+
console.error(chalk19.dim(" Run: vm0 auth login"));
|
|
17273
|
+
} else {
|
|
17274
|
+
console.error(chalk19.dim(` ${error43.message}`));
|
|
17275
|
+
}
|
|
16741
17276
|
}
|
|
16742
17277
|
process.exit(1);
|
|
16743
17278
|
}
|
|
16744
17279
|
});
|
|
16745
17280
|
|
|
16746
17281
|
// src/commands/artifact/index.ts
|
|
16747
|
-
var artifactCommand = new
|
|
17282
|
+
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
17283
|
|
|
16749
17284
|
// src/commands/cook.ts
|
|
16750
|
-
import { Command as
|
|
16751
|
-
import
|
|
17285
|
+
import { Command as Command17 } from "commander";
|
|
17286
|
+
import chalk21 from "chalk";
|
|
16752
17287
|
import { readFile as readFile7, mkdir as mkdir6, writeFile as writeFile6, appendFile } from "fs/promises";
|
|
16753
|
-
import { existsSync as
|
|
16754
|
-
import
|
|
17288
|
+
import { existsSync as existsSync8, readFileSync } from "fs";
|
|
17289
|
+
import path12 from "path";
|
|
16755
17290
|
import { spawn as spawn2 } from "child_process";
|
|
16756
17291
|
import { parse as parseYaml4 } from "yaml";
|
|
16757
17292
|
import { config as dotenvConfig2 } from "dotenv";
|
|
@@ -16759,7 +17294,7 @@ import { config as dotenvConfig2 } from "dotenv";
|
|
|
16759
17294
|
// src/lib/update-checker.ts
|
|
16760
17295
|
import https from "https";
|
|
16761
17296
|
import { spawn } from "child_process";
|
|
16762
|
-
import
|
|
17297
|
+
import chalk20 from "chalk";
|
|
16763
17298
|
var PACKAGE_NAME = "@vm0/cli";
|
|
16764
17299
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`;
|
|
16765
17300
|
var TIMEOUT_MS = 5e3;
|
|
@@ -16824,21 +17359,21 @@ function performUpgrade(packageManager) {
|
|
|
16824
17359
|
async function checkAndUpgrade(currentVersion, prompt) {
|
|
16825
17360
|
const latestVersion = await getLatestVersion();
|
|
16826
17361
|
if (latestVersion === null) {
|
|
16827
|
-
console.log(
|
|
17362
|
+
console.log(chalk20.yellow("Warning: Could not check for updates"));
|
|
16828
17363
|
console.log();
|
|
16829
17364
|
return false;
|
|
16830
17365
|
}
|
|
16831
17366
|
if (latestVersion === currentVersion) {
|
|
16832
17367
|
return false;
|
|
16833
17368
|
}
|
|
16834
|
-
console.log(
|
|
17369
|
+
console.log(chalk20.yellow("vm0 is currently in Early Access (EA)."));
|
|
16835
17370
|
console.log(
|
|
16836
|
-
|
|
17371
|
+
chalk20.yellow(
|
|
16837
17372
|
`Current version: ${currentVersion} -> Latest version: ${latestVersion}`
|
|
16838
17373
|
)
|
|
16839
17374
|
);
|
|
16840
17375
|
console.log(
|
|
16841
|
-
|
|
17376
|
+
chalk20.yellow(
|
|
16842
17377
|
"Please always use the latest version for best compatibility."
|
|
16843
17378
|
)
|
|
16844
17379
|
);
|
|
@@ -16847,20 +17382,20 @@ async function checkAndUpgrade(currentVersion, prompt) {
|
|
|
16847
17382
|
console.log(`Upgrading via ${packageManager}...`);
|
|
16848
17383
|
const success2 = await performUpgrade(packageManager);
|
|
16849
17384
|
if (success2) {
|
|
16850
|
-
console.log(
|
|
17385
|
+
console.log(chalk20.green(`Upgraded to ${latestVersion}`));
|
|
16851
17386
|
console.log();
|
|
16852
17387
|
console.log("To continue, run:");
|
|
16853
|
-
console.log(
|
|
17388
|
+
console.log(chalk20.cyan(` ${buildRerunCommand(prompt)}`));
|
|
16854
17389
|
return true;
|
|
16855
17390
|
}
|
|
16856
17391
|
console.log();
|
|
16857
|
-
console.log(
|
|
16858
|
-
console.log(
|
|
16859
|
-
console.log(
|
|
16860
|
-
console.log(
|
|
17392
|
+
console.log(chalk20.red("Upgrade failed. Please run manually:"));
|
|
17393
|
+
console.log(chalk20.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
17394
|
+
console.log(chalk20.dim(" # or"));
|
|
17395
|
+
console.log(chalk20.cyan(` pnpm add -g ${PACKAGE_NAME}@latest`));
|
|
16861
17396
|
console.log();
|
|
16862
17397
|
console.log("Then re-run:");
|
|
16863
|
-
console.log(
|
|
17398
|
+
console.log(chalk20.cyan(` ${buildRerunCommand(prompt)}`));
|
|
16864
17399
|
return true;
|
|
16865
17400
|
}
|
|
16866
17401
|
|
|
@@ -16868,12 +17403,12 @@ async function checkAndUpgrade(currentVersion, prompt) {
|
|
|
16868
17403
|
import { homedir as homedir2 } from "os";
|
|
16869
17404
|
import { join as join6 } from "path";
|
|
16870
17405
|
import { readFile as readFile6, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
|
|
16871
|
-
import { existsSync as
|
|
17406
|
+
import { existsSync as existsSync7 } from "fs";
|
|
16872
17407
|
var CONFIG_DIR3 = join6(homedir2(), ".vm0");
|
|
16873
17408
|
var COOK_STATE_FILE = join6(CONFIG_DIR3, "cook.json");
|
|
16874
17409
|
var STALE_THRESHOLD_MS = 48 * 60 * 60 * 1e3;
|
|
16875
17410
|
async function loadCookStateFile() {
|
|
16876
|
-
if (!
|
|
17411
|
+
if (!existsSync7(COOK_STATE_FILE)) {
|
|
16877
17412
|
return { ppid: {} };
|
|
16878
17413
|
}
|
|
16879
17414
|
try {
|
|
@@ -16933,7 +17468,7 @@ async function saveCookState(state) {
|
|
|
16933
17468
|
var CONFIG_FILE3 = "vm0.yaml";
|
|
16934
17469
|
var ARTIFACT_DIR = "artifact";
|
|
16935
17470
|
function printCommand(cmd) {
|
|
16936
|
-
console.log(
|
|
17471
|
+
console.log(chalk21.dim(`> ${cmd}`));
|
|
16937
17472
|
}
|
|
16938
17473
|
function execVm0Command(args, options = {}) {
|
|
16939
17474
|
return new Promise((resolve2, reject) => {
|
|
@@ -17034,7 +17569,7 @@ function extractRequiredVarNames(config2) {
|
|
|
17034
17569
|
}
|
|
17035
17570
|
function checkMissingVariables(varNames, envFilePath) {
|
|
17036
17571
|
let dotenvValues = {};
|
|
17037
|
-
if (
|
|
17572
|
+
if (existsSync8(envFilePath)) {
|
|
17038
17573
|
const result = dotenvConfig2({ path: envFilePath, quiet: true });
|
|
17039
17574
|
if (result.parsed) {
|
|
17040
17575
|
dotenvValues = result.parsed;
|
|
@@ -17052,7 +17587,7 @@ function checkMissingVariables(varNames, envFilePath) {
|
|
|
17052
17587
|
}
|
|
17053
17588
|
async function generateEnvPlaceholders(missingVars, envFilePath) {
|
|
17054
17589
|
const placeholders = missingVars.map((name) => `${name}=`).join("\n");
|
|
17055
|
-
if (
|
|
17590
|
+
if (existsSync8(envFilePath)) {
|
|
17056
17591
|
const existingContent = readFileSync(envFilePath, "utf8");
|
|
17057
17592
|
const needsNewline = existingContent.length > 0 && !existingContent.endsWith("\n");
|
|
17058
17593
|
const prefix = needsNewline ? "\n" : "";
|
|
@@ -17068,9 +17603,9 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
17068
17603
|
runOutput,
|
|
17069
17604
|
ARTIFACT_DIR
|
|
17070
17605
|
);
|
|
17071
|
-
if (serverVersion &&
|
|
17606
|
+
if (serverVersion && existsSync8(artifactDir)) {
|
|
17072
17607
|
console.log();
|
|
17073
|
-
console.log(
|
|
17608
|
+
console.log(chalk21.bold("Pulling updated artifact:"));
|
|
17074
17609
|
printCommand(`cd ${ARTIFACT_DIR}`);
|
|
17075
17610
|
printCommand(`vm0 artifact pull ${serverVersion}`);
|
|
17076
17611
|
try {
|
|
@@ -17080,23 +17615,23 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
17080
17615
|
});
|
|
17081
17616
|
printCommand("cd ..");
|
|
17082
17617
|
} catch (error43) {
|
|
17083
|
-
console.error(
|
|
17618
|
+
console.error(chalk21.red(`\u2717 Artifact pull failed`));
|
|
17084
17619
|
if (error43 instanceof Error) {
|
|
17085
|
-
console.error(
|
|
17620
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17086
17621
|
}
|
|
17087
17622
|
}
|
|
17088
17623
|
}
|
|
17089
17624
|
}
|
|
17090
|
-
var cookCmd = new
|
|
17625
|
+
var cookCmd = new Command17().name("cook").description("One-click agent preparation and execution from vm0.yaml");
|
|
17091
17626
|
cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
17092
|
-
const shouldExit = await checkAndUpgrade("4.
|
|
17627
|
+
const shouldExit = await checkAndUpgrade("4.33.0", prompt);
|
|
17093
17628
|
if (shouldExit) {
|
|
17094
17629
|
process.exit(0);
|
|
17095
17630
|
}
|
|
17096
17631
|
const cwd = process.cwd();
|
|
17097
|
-
console.log(
|
|
17098
|
-
if (!
|
|
17099
|
-
console.error(
|
|
17632
|
+
console.log(chalk21.bold(`Reading config: ${CONFIG_FILE3}`));
|
|
17633
|
+
if (!existsSync8(CONFIG_FILE3)) {
|
|
17634
|
+
console.error(chalk21.red(`\u2717 Config file not found: ${CONFIG_FILE3}`));
|
|
17100
17635
|
process.exit(1);
|
|
17101
17636
|
}
|
|
17102
17637
|
let config2;
|
|
@@ -17104,49 +17639,49 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
17104
17639
|
const content = await readFile7(CONFIG_FILE3, "utf8");
|
|
17105
17640
|
config2 = parseYaml4(content);
|
|
17106
17641
|
} catch (error43) {
|
|
17107
|
-
console.error(
|
|
17642
|
+
console.error(chalk21.red("\u2717 Invalid YAML format"));
|
|
17108
17643
|
if (error43 instanceof Error) {
|
|
17109
|
-
console.error(
|
|
17644
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17110
17645
|
}
|
|
17111
17646
|
process.exit(1);
|
|
17112
17647
|
}
|
|
17113
17648
|
const validation = validateAgentCompose(config2);
|
|
17114
17649
|
if (!validation.valid) {
|
|
17115
|
-
console.error(
|
|
17650
|
+
console.error(chalk21.red(`\u2717 ${validation.error}`));
|
|
17116
17651
|
process.exit(1);
|
|
17117
17652
|
}
|
|
17118
17653
|
const agentNames = Object.keys(config2.agents);
|
|
17119
17654
|
const agentName = agentNames[0];
|
|
17120
17655
|
const volumeCount = config2.volumes ? Object.keys(config2.volumes).length : 0;
|
|
17121
17656
|
console.log(
|
|
17122
|
-
|
|
17657
|
+
chalk21.green(`\u2713 Config validated: 1 agent, ${volumeCount} volume(s)`)
|
|
17123
17658
|
);
|
|
17124
17659
|
const requiredVarNames = extractRequiredVarNames(config2);
|
|
17125
17660
|
if (requiredVarNames.length > 0) {
|
|
17126
|
-
const envFilePath =
|
|
17661
|
+
const envFilePath = path12.join(cwd, ".env");
|
|
17127
17662
|
const missingVars = checkMissingVariables(requiredVarNames, envFilePath);
|
|
17128
17663
|
if (missingVars.length > 0) {
|
|
17129
17664
|
await generateEnvPlaceholders(missingVars, envFilePath);
|
|
17130
17665
|
console.log();
|
|
17131
17666
|
console.log(
|
|
17132
|
-
|
|
17667
|
+
chalk21.yellow(
|
|
17133
17668
|
`\u26A0 Missing environment variables. Please fill in values in .env file:`
|
|
17134
17669
|
)
|
|
17135
17670
|
);
|
|
17136
17671
|
for (const varName of missingVars) {
|
|
17137
|
-
console.log(
|
|
17672
|
+
console.log(chalk21.yellow(` ${varName}`));
|
|
17138
17673
|
}
|
|
17139
17674
|
process.exit(1);
|
|
17140
17675
|
}
|
|
17141
17676
|
}
|
|
17142
17677
|
if (config2.volumes && Object.keys(config2.volumes).length > 0) {
|
|
17143
17678
|
console.log();
|
|
17144
|
-
console.log(
|
|
17679
|
+
console.log(chalk21.bold("Processing volumes:"));
|
|
17145
17680
|
for (const volumeConfig of Object.values(config2.volumes)) {
|
|
17146
|
-
const volumeDir =
|
|
17147
|
-
if (!
|
|
17681
|
+
const volumeDir = path12.join(cwd, volumeConfig.name);
|
|
17682
|
+
if (!existsSync8(volumeDir)) {
|
|
17148
17683
|
console.error(
|
|
17149
|
-
|
|
17684
|
+
chalk21.red(
|
|
17150
17685
|
`\u2717 Directory not found: ${volumeConfig.name}. Create the directory and add files first.`
|
|
17151
17686
|
)
|
|
17152
17687
|
);
|
|
@@ -17156,11 +17691,14 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
17156
17691
|
printCommand(`cd ${volumeConfig.name}`);
|
|
17157
17692
|
const existingConfig = await readStorageConfig(volumeDir);
|
|
17158
17693
|
if (!existingConfig) {
|
|
17159
|
-
printCommand(
|
|
17160
|
-
await execVm0Command(
|
|
17161
|
-
|
|
17162
|
-
|
|
17163
|
-
|
|
17694
|
+
printCommand(`vm0 volume init --name ${volumeConfig.name}`);
|
|
17695
|
+
await execVm0Command(
|
|
17696
|
+
["volume", "init", "--name", volumeConfig.name],
|
|
17697
|
+
{
|
|
17698
|
+
cwd: volumeDir,
|
|
17699
|
+
silent: true
|
|
17700
|
+
}
|
|
17701
|
+
);
|
|
17164
17702
|
}
|
|
17165
17703
|
printCommand("vm0 volume push");
|
|
17166
17704
|
await execVm0Command(["volume", "push"], {
|
|
@@ -17169,27 +17707,27 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
17169
17707
|
});
|
|
17170
17708
|
printCommand("cd ..");
|
|
17171
17709
|
} catch (error43) {
|
|
17172
|
-
console.error(
|
|
17710
|
+
console.error(chalk21.red(`\u2717 Failed`));
|
|
17173
17711
|
if (error43 instanceof Error) {
|
|
17174
|
-
console.error(
|
|
17712
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17175
17713
|
}
|
|
17176
17714
|
process.exit(1);
|
|
17177
17715
|
}
|
|
17178
17716
|
}
|
|
17179
17717
|
}
|
|
17180
17718
|
console.log();
|
|
17181
|
-
console.log(
|
|
17182
|
-
const artifactDir =
|
|
17719
|
+
console.log(chalk21.bold("Processing artifact:"));
|
|
17720
|
+
const artifactDir = path12.join(cwd, ARTIFACT_DIR);
|
|
17183
17721
|
try {
|
|
17184
|
-
if (!
|
|
17722
|
+
if (!existsSync8(artifactDir)) {
|
|
17185
17723
|
printCommand(`mkdir ${ARTIFACT_DIR}`);
|
|
17186
17724
|
await mkdir6(artifactDir, { recursive: true });
|
|
17187
17725
|
}
|
|
17188
17726
|
printCommand(`cd ${ARTIFACT_DIR}`);
|
|
17189
17727
|
const existingConfig = await readStorageConfig(artifactDir);
|
|
17190
17728
|
if (!existingConfig) {
|
|
17191
|
-
printCommand(
|
|
17192
|
-
await execVm0Command(["artifact", "init"], {
|
|
17729
|
+
printCommand(`vm0 artifact init --name ${ARTIFACT_DIR}`);
|
|
17730
|
+
await execVm0Command(["artifact", "init", "--name", ARTIFACT_DIR], {
|
|
17193
17731
|
cwd: artifactDir,
|
|
17194
17732
|
silent: true
|
|
17195
17733
|
});
|
|
@@ -17201,29 +17739,29 @@ cookCmd.argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
|
17201
17739
|
});
|
|
17202
17740
|
printCommand("cd ..");
|
|
17203
17741
|
} catch (error43) {
|
|
17204
|
-
console.error(
|
|
17742
|
+
console.error(chalk21.red(`\u2717 Failed`));
|
|
17205
17743
|
if (error43 instanceof Error) {
|
|
17206
|
-
console.error(
|
|
17744
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17207
17745
|
}
|
|
17208
17746
|
process.exit(1);
|
|
17209
17747
|
}
|
|
17210
17748
|
console.log();
|
|
17211
|
-
console.log(
|
|
17749
|
+
console.log(chalk21.bold("Composing agent:"));
|
|
17212
17750
|
printCommand(`vm0 compose ${CONFIG_FILE3}`);
|
|
17213
17751
|
try {
|
|
17214
17752
|
await execVm0Command(["compose", CONFIG_FILE3], {
|
|
17215
17753
|
cwd
|
|
17216
17754
|
});
|
|
17217
17755
|
} catch (error43) {
|
|
17218
|
-
console.error(
|
|
17756
|
+
console.error(chalk21.red(`\u2717 Compose failed`));
|
|
17219
17757
|
if (error43 instanceof Error) {
|
|
17220
|
-
console.error(
|
|
17758
|
+
console.error(chalk21.dim(` ${error43.message}`));
|
|
17221
17759
|
}
|
|
17222
17760
|
process.exit(1);
|
|
17223
17761
|
}
|
|
17224
17762
|
if (prompt) {
|
|
17225
17763
|
console.log();
|
|
17226
|
-
console.log(
|
|
17764
|
+
console.log(chalk21.bold("Running agent:"));
|
|
17227
17765
|
printCommand(
|
|
17228
17766
|
`vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "${prompt}"`
|
|
17229
17767
|
);
|
|
@@ -17265,8 +17803,8 @@ cookCmd.command("logs").description("View logs from the last cook run").option("
|
|
|
17265
17803
|
async (options) => {
|
|
17266
17804
|
const state = await loadCookState();
|
|
17267
17805
|
if (!state.lastRunId) {
|
|
17268
|
-
console.error(
|
|
17269
|
-
console.error(
|
|
17806
|
+
console.error(chalk21.red("\u2717 No previous run found"));
|
|
17807
|
+
console.error(chalk21.dim(" Run 'vm0 cook <prompt>' first"));
|
|
17270
17808
|
process.exit(1);
|
|
17271
17809
|
}
|
|
17272
17810
|
const args = ["logs", state.lastRunId];
|
|
@@ -17308,12 +17846,12 @@ cookCmd.command("continue").description(
|
|
|
17308
17846
|
).argument("<prompt>", "Prompt for the continued agent").action(async (prompt) => {
|
|
17309
17847
|
const state = await loadCookState();
|
|
17310
17848
|
if (!state.lastSessionId) {
|
|
17311
|
-
console.error(
|
|
17312
|
-
console.error(
|
|
17849
|
+
console.error(chalk21.red("\u2717 No previous session found"));
|
|
17850
|
+
console.error(chalk21.dim(" Run 'vm0 cook <prompt>' first"));
|
|
17313
17851
|
process.exit(1);
|
|
17314
17852
|
}
|
|
17315
17853
|
const cwd = process.cwd();
|
|
17316
|
-
const artifactDir =
|
|
17854
|
+
const artifactDir = path12.join(cwd, ARTIFACT_DIR);
|
|
17317
17855
|
printCommand(`vm0 run continue ${state.lastSessionId} "${prompt}"`);
|
|
17318
17856
|
console.log();
|
|
17319
17857
|
let runOutput;
|
|
@@ -17340,12 +17878,12 @@ cookCmd.command("resume").description(
|
|
|
17340
17878
|
).argument("<prompt>", "Prompt for the resumed agent").action(async (prompt) => {
|
|
17341
17879
|
const state = await loadCookState();
|
|
17342
17880
|
if (!state.lastCheckpointId) {
|
|
17343
|
-
console.error(
|
|
17344
|
-
console.error(
|
|
17881
|
+
console.error(chalk21.red("\u2717 No previous checkpoint found"));
|
|
17882
|
+
console.error(chalk21.dim(" Run 'vm0 cook <prompt>' first"));
|
|
17345
17883
|
process.exit(1);
|
|
17346
17884
|
}
|
|
17347
17885
|
const cwd = process.cwd();
|
|
17348
|
-
const artifactDir =
|
|
17886
|
+
const artifactDir = path12.join(cwd, ARTIFACT_DIR);
|
|
17349
17887
|
printCommand(`vm0 run resume ${state.lastCheckpointId} "${prompt}"`);
|
|
17350
17888
|
console.log();
|
|
17351
17889
|
let runOutput;
|
|
@@ -17370,13 +17908,13 @@ cookCmd.command("resume").description(
|
|
|
17370
17908
|
var cookCommand = cookCmd;
|
|
17371
17909
|
|
|
17372
17910
|
// src/commands/image/index.ts
|
|
17373
|
-
import { Command as
|
|
17911
|
+
import { Command as Command22 } from "commander";
|
|
17374
17912
|
|
|
17375
17913
|
// src/commands/image/build.ts
|
|
17376
|
-
import { Command as
|
|
17377
|
-
import
|
|
17914
|
+
import { Command as Command18 } from "commander";
|
|
17915
|
+
import chalk22 from "chalk";
|
|
17378
17916
|
import { readFile as readFile8 } from "fs/promises";
|
|
17379
|
-
import { existsSync as
|
|
17917
|
+
import { existsSync as existsSync9 } from "fs";
|
|
17380
17918
|
|
|
17381
17919
|
// src/lib/dockerfile-validator.ts
|
|
17382
17920
|
var ALLOWED_INSTRUCTIONS = /* @__PURE__ */ new Set(["FROM", "RUN"]);
|
|
@@ -17410,17 +17948,17 @@ function validateDockerfile(content) {
|
|
|
17410
17948
|
|
|
17411
17949
|
// src/commands/image/build.ts
|
|
17412
17950
|
var sleep2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
17413
|
-
var buildCommand = new
|
|
17951
|
+
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
17952
|
async (options) => {
|
|
17415
17953
|
const { file: file2, name, deleteExisting } = options;
|
|
17416
|
-
if (!
|
|
17417
|
-
console.error(
|
|
17954
|
+
if (!existsSync9(file2)) {
|
|
17955
|
+
console.error(chalk22.red(`\u2717 Dockerfile not found: ${file2}`));
|
|
17418
17956
|
process.exit(1);
|
|
17419
17957
|
}
|
|
17420
17958
|
const nameRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,62}[a-zA-Z0-9]$/;
|
|
17421
17959
|
if (!nameRegex.test(name)) {
|
|
17422
17960
|
console.error(
|
|
17423
|
-
|
|
17961
|
+
chalk22.red(
|
|
17424
17962
|
"\u2717 Invalid name format. Must be 3-64 characters, letters, numbers, and hyphens only."
|
|
17425
17963
|
)
|
|
17426
17964
|
);
|
|
@@ -17428,7 +17966,7 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17428
17966
|
}
|
|
17429
17967
|
if (name.startsWith("vm0-")) {
|
|
17430
17968
|
console.error(
|
|
17431
|
-
|
|
17969
|
+
chalk22.red(
|
|
17432
17970
|
'\u2717 Invalid name. Cannot start with "vm0-" (reserved prefix).'
|
|
17433
17971
|
)
|
|
17434
17972
|
);
|
|
@@ -17439,24 +17977,24 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17439
17977
|
const dockerfile = await readFile8(file2, "utf8");
|
|
17440
17978
|
const validation = validateDockerfile(dockerfile);
|
|
17441
17979
|
if (!validation.valid) {
|
|
17442
|
-
console.error(
|
|
17980
|
+
console.error(chalk22.red("\u2717 Dockerfile validation failed\n"));
|
|
17443
17981
|
for (const error43 of validation.errors) {
|
|
17444
|
-
console.error(
|
|
17982
|
+
console.error(chalk22.red(` ${error43}`));
|
|
17445
17983
|
}
|
|
17446
17984
|
console.error();
|
|
17447
17985
|
console.error(
|
|
17448
|
-
|
|
17986
|
+
chalk22.yellow(
|
|
17449
17987
|
" vm0 image build only supports FROM and RUN instructions."
|
|
17450
17988
|
)
|
|
17451
17989
|
);
|
|
17452
17990
|
console.error(
|
|
17453
|
-
|
|
17991
|
+
chalk22.yellow(
|
|
17454
17992
|
" The purpose is to pre-install environment dependencies."
|
|
17455
17993
|
)
|
|
17456
17994
|
);
|
|
17457
17995
|
process.exit(1);
|
|
17458
17996
|
}
|
|
17459
|
-
console.log(
|
|
17997
|
+
console.log(chalk22.bold(`Building image: ${scope.slug}/${name}`));
|
|
17460
17998
|
console.log();
|
|
17461
17999
|
const buildInfo = await apiClient.createImage({
|
|
17462
18000
|
dockerfile,
|
|
@@ -17464,7 +18002,7 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17464
18002
|
deleteExisting
|
|
17465
18003
|
});
|
|
17466
18004
|
const { imageId, buildId, versionId } = buildInfo;
|
|
17467
|
-
console.log(
|
|
18005
|
+
console.log(chalk22.dim(` Build ID: ${buildId}`));
|
|
17468
18006
|
console.log();
|
|
17469
18007
|
let logsOffset = 0;
|
|
17470
18008
|
let status = "building";
|
|
@@ -17480,7 +18018,7 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17480
18018
|
}
|
|
17481
18019
|
const statusData = await statusResponse.json();
|
|
17482
18020
|
for (const log of statusData.logs) {
|
|
17483
|
-
console.log(
|
|
18021
|
+
console.log(chalk22.dim(` ${log}`));
|
|
17484
18022
|
}
|
|
17485
18023
|
logsOffset = statusData.logsOffset;
|
|
17486
18024
|
status = statusData.status;
|
|
@@ -17492,23 +18030,23 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17492
18030
|
if (status === "ready") {
|
|
17493
18031
|
const shortVersion = formatVersionIdForDisplay(versionId);
|
|
17494
18032
|
console.log(
|
|
17495
|
-
|
|
18033
|
+
chalk22.green(`\u2713 Image built: ${scope.slug}/${name}:${shortVersion}`)
|
|
17496
18034
|
);
|
|
17497
18035
|
} else {
|
|
17498
|
-
console.error(
|
|
18036
|
+
console.error(chalk22.red(`\u2717 Build failed`));
|
|
17499
18037
|
process.exit(1);
|
|
17500
18038
|
}
|
|
17501
18039
|
} catch (error43) {
|
|
17502
18040
|
if (error43 instanceof Error) {
|
|
17503
18041
|
if (error43.message.includes("Not authenticated")) {
|
|
17504
18042
|
console.error(
|
|
17505
|
-
|
|
18043
|
+
chalk22.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
17506
18044
|
);
|
|
17507
18045
|
} else {
|
|
17508
|
-
console.error(
|
|
18046
|
+
console.error(chalk22.red(`\u2717 ${error43.message}`));
|
|
17509
18047
|
}
|
|
17510
18048
|
} else {
|
|
17511
|
-
console.error(
|
|
18049
|
+
console.error(chalk22.red("\u2717 An unexpected error occurred"));
|
|
17512
18050
|
}
|
|
17513
18051
|
process.exit(1);
|
|
17514
18052
|
}
|
|
@@ -17516,9 +18054,9 @@ var buildCommand = new Command14().name("build").description("Build a custom ima
|
|
|
17516
18054
|
);
|
|
17517
18055
|
|
|
17518
18056
|
// src/commands/image/list.ts
|
|
17519
|
-
import { Command as
|
|
17520
|
-
import
|
|
17521
|
-
var
|
|
18057
|
+
import { Command as Command19 } from "commander";
|
|
18058
|
+
import chalk23 from "chalk";
|
|
18059
|
+
var listCommand3 = new Command19().name("list").alias("ls").description("List your custom images").action(async () => {
|
|
17522
18060
|
try {
|
|
17523
18061
|
const response = await apiClient.get("/api/images");
|
|
17524
18062
|
if (!response.ok) {
|
|
@@ -17530,15 +18068,15 @@ var listCommand = new Command15().name("list").alias("ls").description("List you
|
|
|
17530
18068
|
const data = await response.json();
|
|
17531
18069
|
const { images } = data;
|
|
17532
18070
|
if (images.length === 0) {
|
|
17533
|
-
console.log(
|
|
18071
|
+
console.log(chalk23.dim("No images found."));
|
|
17534
18072
|
console.log();
|
|
17535
18073
|
console.log("Build your first image:");
|
|
17536
18074
|
console.log(
|
|
17537
|
-
|
|
18075
|
+
chalk23.cyan(" vm0 image build --file Dockerfile --name my-image")
|
|
17538
18076
|
);
|
|
17539
18077
|
return;
|
|
17540
18078
|
}
|
|
17541
|
-
console.log(
|
|
18079
|
+
console.log(chalk23.bold("Your images:"));
|
|
17542
18080
|
console.log();
|
|
17543
18081
|
const imagesByAlias = /* @__PURE__ */ new Map();
|
|
17544
18082
|
for (const image of images) {
|
|
@@ -17552,50 +18090,49 @@ var listCommand = new Command15().name("list").alias("ls").description("List you
|
|
|
17552
18090
|
latestVersions.set(alias, latestReady?.versionId || null);
|
|
17553
18091
|
}
|
|
17554
18092
|
console.log(
|
|
17555
|
-
|
|
18093
|
+
chalk23.dim(
|
|
17556
18094
|
`${"NAME".padEnd(40)} ${"STATUS".padEnd(12)} ${"CREATED".padEnd(20)}`
|
|
17557
18095
|
)
|
|
17558
18096
|
);
|
|
17559
|
-
console.log(
|
|
18097
|
+
console.log(chalk23.dim("-".repeat(72)));
|
|
17560
18098
|
for (const image of images) {
|
|
17561
|
-
const statusColor = image.status === "ready" ?
|
|
18099
|
+
const statusColor = image.status === "ready" ? chalk23.green : image.status === "building" ? chalk23.yellow : chalk23.red;
|
|
17562
18100
|
const createdAt = new Date(image.createdAt).toLocaleString();
|
|
17563
18101
|
let displayName = image.alias;
|
|
17564
18102
|
if (image.versionId) {
|
|
17565
18103
|
const shortVersion = formatVersionIdForDisplay(image.versionId);
|
|
17566
18104
|
displayName = `${image.alias}:${shortVersion}`;
|
|
17567
18105
|
if (image.status === "ready" && latestVersions.get(image.alias) === image.versionId) {
|
|
17568
|
-
displayName = `${displayName} ${
|
|
18106
|
+
displayName = `${displayName} ${chalk23.cyan("latest")}`;
|
|
17569
18107
|
}
|
|
17570
18108
|
}
|
|
17571
18109
|
console.log(
|
|
17572
18110
|
`${displayName.padEnd(40)} ${statusColor(image.status.padEnd(12))} ${createdAt.padEnd(20)}`
|
|
17573
18111
|
);
|
|
17574
18112
|
if (image.status === "error" && image.errorMessage) {
|
|
17575
|
-
console.log(
|
|
18113
|
+
console.log(chalk23.red(` Error: ${image.errorMessage}`));
|
|
17576
18114
|
}
|
|
17577
18115
|
}
|
|
17578
18116
|
console.log();
|
|
17579
|
-
console.log(
|
|
18117
|
+
console.log(chalk23.dim(`Total: ${images.length} version(s)`));
|
|
17580
18118
|
} catch (error43) {
|
|
17581
18119
|
if (error43 instanceof Error) {
|
|
17582
18120
|
if (error43.message.includes("Not authenticated")) {
|
|
17583
|
-
console.error(
|
|
18121
|
+
console.error(chalk23.red("Not authenticated. Run: vm0 auth login"));
|
|
17584
18122
|
} else {
|
|
17585
|
-
console.error(
|
|
18123
|
+
console.error(chalk23.red(`Error: ${error43.message}`));
|
|
17586
18124
|
}
|
|
17587
18125
|
} else {
|
|
17588
|
-
console.error(
|
|
18126
|
+
console.error(chalk23.red("An unexpected error occurred"));
|
|
17589
18127
|
}
|
|
17590
18128
|
process.exit(1);
|
|
17591
18129
|
}
|
|
17592
18130
|
});
|
|
17593
18131
|
|
|
17594
18132
|
// 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(
|
|
18133
|
+
import { Command as Command20 } from "commander";
|
|
18134
|
+
import chalk24 from "chalk";
|
|
18135
|
+
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
18136
|
async (nameArg, options) => {
|
|
17600
18137
|
try {
|
|
17601
18138
|
const colonIndex = nameArg.lastIndexOf(":");
|
|
@@ -17616,12 +18153,12 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17616
18153
|
(img) => img.alias === name && img.versionId && img.versionId.startsWith(versionId.toLowerCase())
|
|
17617
18154
|
);
|
|
17618
18155
|
if (matchingVersions.length === 0) {
|
|
17619
|
-
console.error(
|
|
18156
|
+
console.error(chalk24.red(`Image version not found: ${nameArg}`));
|
|
17620
18157
|
process.exit(1);
|
|
17621
18158
|
}
|
|
17622
18159
|
if (matchingVersions.length > 1) {
|
|
17623
18160
|
console.error(
|
|
17624
|
-
|
|
18161
|
+
chalk24.red(
|
|
17625
18162
|
`Ambiguous version prefix "${versionId}". Please use more characters.`
|
|
17626
18163
|
)
|
|
17627
18164
|
);
|
|
@@ -17631,7 +18168,7 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17631
18168
|
} else if (options.all) {
|
|
17632
18169
|
imagesToDelete = data.images.filter((img) => img.alias === name);
|
|
17633
18170
|
if (imagesToDelete.length === 0) {
|
|
17634
|
-
console.error(
|
|
18171
|
+
console.error(chalk24.red(`Image not found: ${name}`));
|
|
17635
18172
|
process.exit(1);
|
|
17636
18173
|
}
|
|
17637
18174
|
} else {
|
|
@@ -17639,7 +18176,7 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17639
18176
|
(img) => img.alias === name
|
|
17640
18177
|
);
|
|
17641
18178
|
if (matchingImages.length === 0) {
|
|
17642
|
-
console.error(
|
|
18179
|
+
console.error(chalk24.red(`Image not found: ${name}`));
|
|
17643
18180
|
process.exit(1);
|
|
17644
18181
|
}
|
|
17645
18182
|
const latestReady = matchingImages.find(
|
|
@@ -17655,18 +18192,9 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17655
18192
|
const firstVersionDisplay = firstImage.versionId ? `:${formatVersionIdForDisplay(firstImage.versionId)}` : "";
|
|
17656
18193
|
const confirmMsg = imagesToDelete.length === 1 ? `Delete image "${firstImage.alias}${firstVersionDisplay}"?` : `Delete ${imagesToDelete.length} versions of "${name}"?`;
|
|
17657
18194
|
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."));
|
|
18195
|
+
const confirmed = await promptConfirm(confirmMsg, false);
|
|
18196
|
+
if (!confirmed) {
|
|
18197
|
+
console.log(chalk24.dim("Cancelled."));
|
|
17670
18198
|
return;
|
|
17671
18199
|
}
|
|
17672
18200
|
}
|
|
@@ -17681,17 +18209,17 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17681
18209
|
);
|
|
17682
18210
|
}
|
|
17683
18211
|
const displayName = image.versionId ? `${image.alias}:${formatVersionIdForDisplay(image.versionId)}` : image.alias;
|
|
17684
|
-
console.log(
|
|
18212
|
+
console.log(chalk24.green(`Deleted image: ${displayName}`));
|
|
17685
18213
|
}
|
|
17686
18214
|
} catch (error43) {
|
|
17687
18215
|
if (error43 instanceof Error) {
|
|
17688
18216
|
if (error43.message.includes("Not authenticated")) {
|
|
17689
|
-
console.error(
|
|
18217
|
+
console.error(chalk24.red("Not authenticated. Run: vm0 auth login"));
|
|
17690
18218
|
} else {
|
|
17691
|
-
console.error(
|
|
18219
|
+
console.error(chalk24.red(`Error: ${error43.message}`));
|
|
17692
18220
|
}
|
|
17693
18221
|
} else {
|
|
17694
|
-
console.error(
|
|
18222
|
+
console.error(chalk24.red("An unexpected error occurred"));
|
|
17695
18223
|
}
|
|
17696
18224
|
process.exit(1);
|
|
17697
18225
|
}
|
|
@@ -17699,9 +18227,9 @@ var deleteCommand = new Command16().name("delete").alias("rm").description("Dele
|
|
|
17699
18227
|
);
|
|
17700
18228
|
|
|
17701
18229
|
// src/commands/image/versions.ts
|
|
17702
|
-
import { Command as
|
|
17703
|
-
import
|
|
17704
|
-
var versionsCommand = new
|
|
18230
|
+
import { Command as Command21 } from "commander";
|
|
18231
|
+
import chalk25 from "chalk";
|
|
18232
|
+
var versionsCommand = new Command21().name("versions").description("List all versions of an image").argument("<name>", "Name of the image").action(async (name) => {
|
|
17705
18233
|
try {
|
|
17706
18234
|
const response = await apiClient.get("/api/images");
|
|
17707
18235
|
if (!response.ok) {
|
|
@@ -17713,42 +18241,42 @@ var versionsCommand = new Command17().name("versions").description("List all ver
|
|
|
17713
18241
|
const data = await response.json();
|
|
17714
18242
|
const versions = data.images.filter((img) => img.alias === name);
|
|
17715
18243
|
if (versions.length === 0) {
|
|
17716
|
-
console.error(
|
|
18244
|
+
console.error(chalk25.red(`Image not found: ${name}`));
|
|
17717
18245
|
process.exit(1);
|
|
17718
18246
|
}
|
|
17719
18247
|
const latestReady = versions.find((v) => v.status === "ready");
|
|
17720
18248
|
const latestVersionId = latestReady?.versionId || null;
|
|
17721
|
-
console.log(
|
|
18249
|
+
console.log(chalk25.bold(`Versions of ${name}:`));
|
|
17722
18250
|
console.log();
|
|
17723
18251
|
console.log(
|
|
17724
|
-
|
|
18252
|
+
chalk25.dim(
|
|
17725
18253
|
`${"VERSION".padEnd(20)} ${"STATUS".padEnd(12)} ${"CREATED".padEnd(24)}`
|
|
17726
18254
|
)
|
|
17727
18255
|
);
|
|
17728
|
-
console.log(
|
|
18256
|
+
console.log(chalk25.dim("-".repeat(56)));
|
|
17729
18257
|
for (const version2 of versions) {
|
|
17730
|
-
const statusColor = version2.status === "ready" ?
|
|
18258
|
+
const statusColor = version2.status === "ready" ? chalk25.green : version2.status === "building" ? chalk25.yellow : chalk25.red;
|
|
17731
18259
|
const createdAt = new Date(version2.createdAt).toLocaleString();
|
|
17732
18260
|
let versionDisplay = version2.versionId ? formatVersionIdForDisplay(version2.versionId) : "(legacy)";
|
|
17733
18261
|
if (version2.status === "ready" && version2.versionId === latestVersionId) {
|
|
17734
|
-
versionDisplay = `${versionDisplay} ${
|
|
18262
|
+
versionDisplay = `${versionDisplay} ${chalk25.cyan("latest")}`;
|
|
17735
18263
|
}
|
|
17736
18264
|
console.log(
|
|
17737
18265
|
`${versionDisplay.padEnd(20)} ${statusColor(version2.status.padEnd(12))} ${createdAt.padEnd(24)}`
|
|
17738
18266
|
);
|
|
17739
18267
|
if (version2.status === "error" && version2.errorMessage) {
|
|
17740
|
-
console.log(
|
|
18268
|
+
console.log(chalk25.red(` Error: ${version2.errorMessage}`));
|
|
17741
18269
|
}
|
|
17742
18270
|
}
|
|
17743
18271
|
console.log();
|
|
17744
|
-
console.log(
|
|
18272
|
+
console.log(chalk25.dim(`Total: ${versions.length} version(s)`));
|
|
17745
18273
|
console.log();
|
|
17746
|
-
console.log(
|
|
17747
|
-
console.log(
|
|
18274
|
+
console.log(chalk25.dim("Usage:"));
|
|
18275
|
+
console.log(chalk25.dim(` image: "${name}" # uses latest`));
|
|
17748
18276
|
if (latestVersionId) {
|
|
17749
18277
|
const shortVersion = formatVersionIdForDisplay(latestVersionId);
|
|
17750
18278
|
console.log(
|
|
17751
|
-
|
|
18279
|
+
chalk25.dim(
|
|
17752
18280
|
` image: "${name}:${shortVersion}" # pin to specific version`
|
|
17753
18281
|
)
|
|
17754
18282
|
);
|
|
@@ -17756,23 +18284,23 @@ var versionsCommand = new Command17().name("versions").description("List all ver
|
|
|
17756
18284
|
} catch (error43) {
|
|
17757
18285
|
if (error43 instanceof Error) {
|
|
17758
18286
|
if (error43.message.includes("Not authenticated")) {
|
|
17759
|
-
console.error(
|
|
18287
|
+
console.error(chalk25.red("Not authenticated. Run: vm0 auth login"));
|
|
17760
18288
|
} else {
|
|
17761
|
-
console.error(
|
|
18289
|
+
console.error(chalk25.red(`Error: ${error43.message}`));
|
|
17762
18290
|
}
|
|
17763
18291
|
} else {
|
|
17764
|
-
console.error(
|
|
18292
|
+
console.error(chalk25.red("An unexpected error occurred"));
|
|
17765
18293
|
}
|
|
17766
18294
|
process.exit(1);
|
|
17767
18295
|
}
|
|
17768
18296
|
});
|
|
17769
18297
|
|
|
17770
18298
|
// src/commands/image/index.ts
|
|
17771
|
-
var imageCommand = new
|
|
18299
|
+
var imageCommand = new Command22().name("image").description("Manage custom images").addCommand(buildCommand).addCommand(listCommand3).addCommand(deleteCommand).addCommand(versionsCommand);
|
|
17772
18300
|
|
|
17773
18301
|
// src/commands/logs/index.ts
|
|
17774
|
-
import { Command as
|
|
17775
|
-
import
|
|
18302
|
+
import { Command as Command23 } from "commander";
|
|
18303
|
+
import chalk26 from "chalk";
|
|
17776
18304
|
|
|
17777
18305
|
// src/lib/time-parser.ts
|
|
17778
18306
|
function parseTime(timeStr) {
|
|
@@ -17819,7 +18347,7 @@ function parseRelativeTime(value, unit) {
|
|
|
17819
18347
|
}
|
|
17820
18348
|
|
|
17821
18349
|
// src/commands/logs/index.ts
|
|
17822
|
-
function
|
|
18350
|
+
function formatBytes8(bytes) {
|
|
17823
18351
|
if (bytes === 0) return "0 B";
|
|
17824
18352
|
const k = 1024;
|
|
17825
18353
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -17829,28 +18357,28 @@ function formatBytes7(bytes) {
|
|
|
17829
18357
|
function formatMetric(metric) {
|
|
17830
18358
|
const memPercent = (metric.mem_used / metric.mem_total * 100).toFixed(1);
|
|
17831
18359
|
const diskPercent = (metric.disk_used / metric.disk_total * 100).toFixed(1);
|
|
17832
|
-
return `[${metric.ts}] CPU: ${metric.cpu.toFixed(1)}% | Mem: ${
|
|
18360
|
+
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
18361
|
}
|
|
17834
18362
|
function formatNetworkLog(entry) {
|
|
17835
18363
|
let statusColor;
|
|
17836
18364
|
if (entry.status >= 200 && entry.status < 300) {
|
|
17837
|
-
statusColor =
|
|
18365
|
+
statusColor = chalk26.green;
|
|
17838
18366
|
} else if (entry.status >= 300 && entry.status < 400) {
|
|
17839
|
-
statusColor =
|
|
18367
|
+
statusColor = chalk26.yellow;
|
|
17840
18368
|
} else if (entry.status >= 400) {
|
|
17841
|
-
statusColor =
|
|
18369
|
+
statusColor = chalk26.red;
|
|
17842
18370
|
} else {
|
|
17843
|
-
statusColor =
|
|
18371
|
+
statusColor = chalk26.gray;
|
|
17844
18372
|
}
|
|
17845
18373
|
let latencyColor;
|
|
17846
18374
|
if (entry.latency_ms < 500) {
|
|
17847
|
-
latencyColor =
|
|
18375
|
+
latencyColor = chalk26.green;
|
|
17848
18376
|
} else if (entry.latency_ms < 2e3) {
|
|
17849
|
-
latencyColor =
|
|
18377
|
+
latencyColor = chalk26.yellow;
|
|
17850
18378
|
} else {
|
|
17851
|
-
latencyColor =
|
|
18379
|
+
latencyColor = chalk26.red;
|
|
17852
18380
|
}
|
|
17853
|
-
return `[${entry.timestamp}] ${entry.method.padEnd(6)} ${statusColor(entry.status)} ${latencyColor(entry.latency_ms + "ms")} ${
|
|
18381
|
+
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
18382
|
}
|
|
17855
18383
|
function renderAgentEvent(event, provider) {
|
|
17856
18384
|
const eventData = event.eventData;
|
|
@@ -17873,7 +18401,7 @@ function getLogType(options) {
|
|
|
17873
18401
|
].filter(Boolean).length;
|
|
17874
18402
|
if (selected > 1) {
|
|
17875
18403
|
console.error(
|
|
17876
|
-
|
|
18404
|
+
chalk26.red(
|
|
17877
18405
|
"Options --agent, --system, --metrics, and --network are mutually exclusive"
|
|
17878
18406
|
)
|
|
17879
18407
|
);
|
|
@@ -17884,7 +18412,7 @@ function getLogType(options) {
|
|
|
17884
18412
|
if (options.network) return "network";
|
|
17885
18413
|
return "agent";
|
|
17886
18414
|
}
|
|
17887
|
-
var logsCommand = new
|
|
18415
|
+
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
18416
|
"--since <time>",
|
|
17889
18417
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z, 1705312200)"
|
|
17890
18418
|
).option("--tail <n>", "Show last N entries (default: 5, max: 100)").option("--head <n>", "Show first N entries (max: 100)").action(
|
|
@@ -17893,7 +18421,7 @@ var logsCommand = new Command19().name("logs").description("View logs for an age
|
|
|
17893
18421
|
const logType = getLogType(options);
|
|
17894
18422
|
if (options.tail !== void 0 && options.head !== void 0) {
|
|
17895
18423
|
console.error(
|
|
17896
|
-
|
|
18424
|
+
chalk26.red("Options --tail and --head are mutually exclusive")
|
|
17897
18425
|
);
|
|
17898
18426
|
process.exit(1);
|
|
17899
18427
|
}
|
|
@@ -17930,7 +18458,7 @@ var logsCommand = new Command19().name("logs").description("View logs for an age
|
|
|
17930
18458
|
async function showAgentEvents(runId, options) {
|
|
17931
18459
|
const response = await apiClient.getAgentEvents(runId, options);
|
|
17932
18460
|
if (response.events.length === 0) {
|
|
17933
|
-
console.log(
|
|
18461
|
+
console.log(chalk26.yellow("No agent events found for this run."));
|
|
17934
18462
|
return;
|
|
17935
18463
|
}
|
|
17936
18464
|
const events = options.order === "desc" ? [...response.events].reverse() : response.events;
|
|
@@ -17940,7 +18468,7 @@ async function showAgentEvents(runId, options) {
|
|
|
17940
18468
|
if (response.hasMore) {
|
|
17941
18469
|
console.log();
|
|
17942
18470
|
console.log(
|
|
17943
|
-
|
|
18471
|
+
chalk26.dim(
|
|
17944
18472
|
`Showing ${response.events.length} events. Use --tail to see more.`
|
|
17945
18473
|
)
|
|
17946
18474
|
);
|
|
@@ -17949,21 +18477,21 @@ async function showAgentEvents(runId, options) {
|
|
|
17949
18477
|
async function showSystemLog(runId, options) {
|
|
17950
18478
|
const response = await apiClient.getSystemLog(runId, options);
|
|
17951
18479
|
if (!response.systemLog) {
|
|
17952
|
-
console.log(
|
|
18480
|
+
console.log(chalk26.yellow("No system log found for this run."));
|
|
17953
18481
|
return;
|
|
17954
18482
|
}
|
|
17955
18483
|
console.log(response.systemLog);
|
|
17956
18484
|
if (response.hasMore) {
|
|
17957
18485
|
console.log();
|
|
17958
18486
|
console.log(
|
|
17959
|
-
|
|
18487
|
+
chalk26.dim("More log entries available. Use --tail to see more.")
|
|
17960
18488
|
);
|
|
17961
18489
|
}
|
|
17962
18490
|
}
|
|
17963
18491
|
async function showMetrics(runId, options) {
|
|
17964
18492
|
const response = await apiClient.getMetrics(runId, options);
|
|
17965
18493
|
if (response.metrics.length === 0) {
|
|
17966
|
-
console.log(
|
|
18494
|
+
console.log(chalk26.yellow("No metrics found for this run."));
|
|
17967
18495
|
return;
|
|
17968
18496
|
}
|
|
17969
18497
|
const metrics = options.order === "desc" ? [...response.metrics].reverse() : response.metrics;
|
|
@@ -17973,7 +18501,7 @@ async function showMetrics(runId, options) {
|
|
|
17973
18501
|
if (response.hasMore) {
|
|
17974
18502
|
console.log();
|
|
17975
18503
|
console.log(
|
|
17976
|
-
|
|
18504
|
+
chalk26.dim(
|
|
17977
18505
|
`Showing ${response.metrics.length} metrics. Use --tail to see more.`
|
|
17978
18506
|
)
|
|
17979
18507
|
);
|
|
@@ -17983,7 +18511,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
17983
18511
|
const response = await apiClient.getNetworkLogs(runId, options);
|
|
17984
18512
|
if (response.networkLogs.length === 0) {
|
|
17985
18513
|
console.log(
|
|
17986
|
-
|
|
18514
|
+
chalk26.yellow(
|
|
17987
18515
|
"No network logs found for this run. Network logs are only captured when beta_network_security is enabled."
|
|
17988
18516
|
)
|
|
17989
18517
|
);
|
|
@@ -17996,7 +18524,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
17996
18524
|
if (response.hasMore) {
|
|
17997
18525
|
console.log();
|
|
17998
18526
|
console.log(
|
|
17999
|
-
|
|
18527
|
+
chalk26.dim(
|
|
18000
18528
|
`Showing ${response.networkLogs.length} network logs. Use --tail to see more.`
|
|
18001
18529
|
)
|
|
18002
18530
|
);
|
|
@@ -18005,31 +18533,31 @@ async function showNetworkLogs(runId, options) {
|
|
|
18005
18533
|
function handleError(error43, runId) {
|
|
18006
18534
|
if (error43 instanceof Error) {
|
|
18007
18535
|
if (error43.message.includes("Not authenticated")) {
|
|
18008
|
-
console.error(
|
|
18536
|
+
console.error(chalk26.red("Not authenticated. Run: vm0 auth login"));
|
|
18009
18537
|
} else if (error43.message.includes("not found")) {
|
|
18010
|
-
console.error(
|
|
18538
|
+
console.error(chalk26.red(`Run not found: ${runId}`));
|
|
18011
18539
|
} else if (error43.message.includes("Invalid time format")) {
|
|
18012
|
-
console.error(
|
|
18540
|
+
console.error(chalk26.red(error43.message));
|
|
18013
18541
|
} else {
|
|
18014
|
-
console.error(
|
|
18015
|
-
console.error(
|
|
18542
|
+
console.error(chalk26.red("Failed to fetch logs"));
|
|
18543
|
+
console.error(chalk26.dim(` ${error43.message}`));
|
|
18016
18544
|
}
|
|
18017
18545
|
} else {
|
|
18018
|
-
console.error(
|
|
18546
|
+
console.error(chalk26.red("An unexpected error occurred"));
|
|
18019
18547
|
}
|
|
18020
18548
|
}
|
|
18021
18549
|
|
|
18022
18550
|
// src/commands/scope/index.ts
|
|
18023
|
-
import { Command as
|
|
18551
|
+
import { Command as Command26 } from "commander";
|
|
18024
18552
|
|
|
18025
18553
|
// src/commands/scope/status.ts
|
|
18026
|
-
import { Command as
|
|
18027
|
-
import
|
|
18028
|
-
var statusCommand3 = new
|
|
18554
|
+
import { Command as Command24 } from "commander";
|
|
18555
|
+
import chalk27 from "chalk";
|
|
18556
|
+
var statusCommand3 = new Command24().name("status").description("View current scope status").action(async () => {
|
|
18029
18557
|
try {
|
|
18030
18558
|
const scope = await apiClient.getScope();
|
|
18031
|
-
console.log(
|
|
18032
|
-
console.log(` Slug: ${
|
|
18559
|
+
console.log(chalk27.bold("Scope Information:"));
|
|
18560
|
+
console.log(` Slug: ${chalk27.green(scope.slug)}`);
|
|
18033
18561
|
console.log(` Type: ${scope.type}`);
|
|
18034
18562
|
if (scope.displayName) {
|
|
18035
18563
|
console.log(` Display Name: ${scope.displayName}`);
|
|
@@ -18040,29 +18568,29 @@ var statusCommand3 = new Command20().name("status").description("View current sc
|
|
|
18040
18568
|
} catch (error43) {
|
|
18041
18569
|
if (error43 instanceof Error) {
|
|
18042
18570
|
if (error43.message.includes("Not authenticated")) {
|
|
18043
|
-
console.error(
|
|
18571
|
+
console.error(chalk27.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
18044
18572
|
} else if (error43.message.includes("No scope configured")) {
|
|
18045
|
-
console.log(
|
|
18573
|
+
console.log(chalk27.yellow("No scope configured."));
|
|
18046
18574
|
console.log();
|
|
18047
18575
|
console.log("Set your scope with:");
|
|
18048
|
-
console.log(
|
|
18576
|
+
console.log(chalk27.cyan(" vm0 scope set <slug>"));
|
|
18049
18577
|
console.log();
|
|
18050
18578
|
console.log("Example:");
|
|
18051
|
-
console.log(
|
|
18579
|
+
console.log(chalk27.dim(" vm0 scope set myusername"));
|
|
18052
18580
|
} else {
|
|
18053
|
-
console.error(
|
|
18581
|
+
console.error(chalk27.red(`\u2717 ${error43.message}`));
|
|
18054
18582
|
}
|
|
18055
18583
|
} else {
|
|
18056
|
-
console.error(
|
|
18584
|
+
console.error(chalk27.red("\u2717 An unexpected error occurred"));
|
|
18057
18585
|
}
|
|
18058
18586
|
process.exit(1);
|
|
18059
18587
|
}
|
|
18060
18588
|
});
|
|
18061
18589
|
|
|
18062
18590
|
// src/commands/scope/set.ts
|
|
18063
|
-
import { Command as
|
|
18064
|
-
import
|
|
18065
|
-
var setCommand = new
|
|
18591
|
+
import { Command as Command25 } from "commander";
|
|
18592
|
+
import chalk28 from "chalk";
|
|
18593
|
+
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
18594
|
async (slug, options) => {
|
|
18067
18595
|
try {
|
|
18068
18596
|
let existingScope;
|
|
@@ -18074,56 +18602,56 @@ var setCommand = new Command21().name("set").description("Set your scope slug").
|
|
|
18074
18602
|
if (existingScope) {
|
|
18075
18603
|
if (!options.force) {
|
|
18076
18604
|
console.error(
|
|
18077
|
-
|
|
18605
|
+
chalk28.yellow(`You already have a scope: ${existingScope.slug}`)
|
|
18078
18606
|
);
|
|
18079
18607
|
console.error();
|
|
18080
18608
|
console.error("To change your scope, use --force:");
|
|
18081
|
-
console.error(
|
|
18609
|
+
console.error(chalk28.cyan(` vm0 scope set ${slug} --force`));
|
|
18082
18610
|
console.error();
|
|
18083
18611
|
console.error(
|
|
18084
|
-
|
|
18612
|
+
chalk28.yellow(
|
|
18085
18613
|
"Warning: Changing your scope may break existing image references."
|
|
18086
18614
|
)
|
|
18087
18615
|
);
|
|
18088
18616
|
process.exit(1);
|
|
18089
18617
|
}
|
|
18090
18618
|
scope = await apiClient.updateScope({ slug, force: true });
|
|
18091
|
-
console.log(
|
|
18619
|
+
console.log(chalk28.green(`\u2713 Scope updated to ${scope.slug}`));
|
|
18092
18620
|
} else {
|
|
18093
18621
|
scope = await apiClient.createScope({
|
|
18094
18622
|
slug,
|
|
18095
18623
|
displayName: options.displayName
|
|
18096
18624
|
});
|
|
18097
|
-
console.log(
|
|
18625
|
+
console.log(chalk28.green(`\u2713 Scope created: ${scope.slug}`));
|
|
18098
18626
|
}
|
|
18099
18627
|
console.log();
|
|
18100
18628
|
console.log("Your images will now be namespaced as:");
|
|
18101
|
-
console.log(
|
|
18629
|
+
console.log(chalk28.cyan(` ${scope.slug}/<image-name>`));
|
|
18102
18630
|
} catch (error43) {
|
|
18103
18631
|
if (error43 instanceof Error) {
|
|
18104
18632
|
if (error43.message.includes("Not authenticated")) {
|
|
18105
18633
|
console.error(
|
|
18106
|
-
|
|
18634
|
+
chalk28.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
18107
18635
|
);
|
|
18108
18636
|
} else if (error43.message.includes("already exists")) {
|
|
18109
18637
|
console.error(
|
|
18110
|
-
|
|
18638
|
+
chalk28.red(
|
|
18111
18639
|
`\u2717 Scope "${slug}" is already taken. Please choose a different slug.`
|
|
18112
18640
|
)
|
|
18113
18641
|
);
|
|
18114
18642
|
} else if (error43.message.includes("reserved")) {
|
|
18115
|
-
console.error(
|
|
18643
|
+
console.error(chalk28.red(`\u2717 ${error43.message}`));
|
|
18116
18644
|
} else if (error43.message.includes("vm0")) {
|
|
18117
18645
|
console.error(
|
|
18118
|
-
|
|
18646
|
+
chalk28.red(
|
|
18119
18647
|
"\u2717 Scope slugs cannot start with 'vm0' (reserved for system use)"
|
|
18120
18648
|
)
|
|
18121
18649
|
);
|
|
18122
18650
|
} else {
|
|
18123
|
-
console.error(
|
|
18651
|
+
console.error(chalk28.red(`\u2717 ${error43.message}`));
|
|
18124
18652
|
}
|
|
18125
18653
|
} else {
|
|
18126
|
-
console.error(
|
|
18654
|
+
console.error(chalk28.red("\u2717 An unexpected error occurred"));
|
|
18127
18655
|
}
|
|
18128
18656
|
process.exit(1);
|
|
18129
18657
|
}
|
|
@@ -18131,13 +18659,13 @@ var setCommand = new Command21().name("set").description("Set your scope slug").
|
|
|
18131
18659
|
);
|
|
18132
18660
|
|
|
18133
18661
|
// src/commands/scope/index.ts
|
|
18134
|
-
var scopeCommand = new
|
|
18662
|
+
var scopeCommand = new Command26().name("scope").description("Manage your scope (namespace for images)").addCommand(statusCommand3).addCommand(setCommand);
|
|
18135
18663
|
|
|
18136
18664
|
// src/commands/init.ts
|
|
18137
|
-
import { Command as
|
|
18138
|
-
import
|
|
18139
|
-
import
|
|
18140
|
-
import { existsSync as
|
|
18665
|
+
import { Command as Command27 } from "commander";
|
|
18666
|
+
import chalk29 from "chalk";
|
|
18667
|
+
import path13 from "path";
|
|
18668
|
+
import { existsSync as existsSync10 } from "fs";
|
|
18141
18669
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
18142
18670
|
var VM0_YAML_FILE = "vm0.yaml";
|
|
18143
18671
|
var AGENTS_MD_FILE = "AGENTS.md";
|
|
@@ -18172,76 +18700,76 @@ You are a HackerNews AI content curator.
|
|
|
18172
18700
|
}
|
|
18173
18701
|
function checkExistingFiles() {
|
|
18174
18702
|
const existingFiles = [];
|
|
18175
|
-
if (
|
|
18176
|
-
if (
|
|
18703
|
+
if (existsSync10(VM0_YAML_FILE)) existingFiles.push(VM0_YAML_FILE);
|
|
18704
|
+
if (existsSync10(AGENTS_MD_FILE)) existingFiles.push(AGENTS_MD_FILE);
|
|
18177
18705
|
return existingFiles;
|
|
18178
18706
|
}
|
|
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) => {
|
|
18707
|
+
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
18708
|
const existingFiles = checkExistingFiles();
|
|
18198
18709
|
if (existingFiles.length > 0 && !options.force) {
|
|
18199
18710
|
for (const file2 of existingFiles) {
|
|
18200
|
-
console.log(
|
|
18711
|
+
console.log(chalk29.red(`\u2717 ${file2} already exists`));
|
|
18201
18712
|
}
|
|
18202
18713
|
console.log();
|
|
18203
|
-
console.log(`To overwrite: ${
|
|
18714
|
+
console.log(`To overwrite: ${chalk29.cyan("vm0 init --force")}`);
|
|
18204
18715
|
process.exit(1);
|
|
18205
18716
|
}
|
|
18206
18717
|
let agentName;
|
|
18207
18718
|
if (options.name) {
|
|
18208
18719
|
agentName = options.name.trim();
|
|
18720
|
+
} else if (!isInteractive()) {
|
|
18721
|
+
console.error(
|
|
18722
|
+
chalk29.red("\u2717 --name flag is required in non-interactive mode")
|
|
18723
|
+
);
|
|
18724
|
+
console.error(chalk29.dim(" Usage: vm0 init --name <agent-name>"));
|
|
18725
|
+
process.exit(1);
|
|
18209
18726
|
} else {
|
|
18210
|
-
|
|
18211
|
-
|
|
18212
|
-
|
|
18213
|
-
|
|
18727
|
+
const dirName = path13.basename(process.cwd());
|
|
18728
|
+
const defaultName = validateAgentName(dirName) ? dirName : void 0;
|
|
18729
|
+
const name = await promptText(
|
|
18730
|
+
"Enter agent name",
|
|
18731
|
+
defaultName,
|
|
18732
|
+
(value) => {
|
|
18733
|
+
if (!validateAgentName(value)) {
|
|
18734
|
+
return "Must be 3-64 characters, alphanumeric and hyphens, start/end with letter or number";
|
|
18735
|
+
}
|
|
18736
|
+
return true;
|
|
18737
|
+
}
|
|
18738
|
+
);
|
|
18739
|
+
if (name === void 0) {
|
|
18740
|
+
console.log(chalk29.dim("Cancelled"));
|
|
18741
|
+
return;
|
|
18214
18742
|
}
|
|
18743
|
+
agentName = name;
|
|
18215
18744
|
}
|
|
18216
18745
|
if (!agentName || !validateAgentName(agentName)) {
|
|
18217
|
-
console.log(
|
|
18746
|
+
console.log(chalk29.red("\u2717 Invalid agent name"));
|
|
18218
18747
|
console.log(
|
|
18219
|
-
|
|
18748
|
+
chalk29.dim(" Must be 3-64 characters, alphanumeric and hyphens only")
|
|
18220
18749
|
);
|
|
18221
|
-
console.log(
|
|
18750
|
+
console.log(chalk29.dim(" Must start and end with letter or number"));
|
|
18222
18751
|
process.exit(1);
|
|
18223
18752
|
}
|
|
18224
18753
|
await writeFile7(VM0_YAML_FILE, generateVm0Yaml(agentName));
|
|
18225
18754
|
const vm0Status = existingFiles.includes(VM0_YAML_FILE) ? " (overwritten)" : "";
|
|
18226
|
-
console.log(
|
|
18755
|
+
console.log(chalk29.green(`\u2713 Created ${VM0_YAML_FILE}${vm0Status}`));
|
|
18227
18756
|
await writeFile7(AGENTS_MD_FILE, generateAgentsMd());
|
|
18228
18757
|
const agentsStatus = existingFiles.includes(AGENTS_MD_FILE) ? " (overwritten)" : "";
|
|
18229
|
-
console.log(
|
|
18758
|
+
console.log(chalk29.green(`\u2713 Created ${AGENTS_MD_FILE}${agentsStatus}`));
|
|
18230
18759
|
console.log();
|
|
18231
18760
|
console.log("Next steps:");
|
|
18232
18761
|
console.log(
|
|
18233
|
-
` 1. Get your Claude Code token: ${
|
|
18762
|
+
` 1. Get your Claude Code token: ${chalk29.cyan("claude setup-token")}`
|
|
18234
18763
|
);
|
|
18235
18764
|
console.log(` 2. Set the environment variable (or add to .env file):`);
|
|
18236
|
-
console.log(
|
|
18237
|
-
console.log(` 3. Run your agent: ${
|
|
18765
|
+
console.log(chalk29.dim(` export CLAUDE_CODE_OAUTH_TOKEN=<your-token>`));
|
|
18766
|
+
console.log(` 3. Run your agent: ${chalk29.cyan('vm0 cook "your prompt"')}`);
|
|
18238
18767
|
});
|
|
18239
18768
|
|
|
18240
18769
|
// src/commands/setup-github.ts
|
|
18241
|
-
import { Command as
|
|
18242
|
-
import
|
|
18243
|
-
import
|
|
18244
|
-
import { existsSync as existsSync10 } from "fs";
|
|
18770
|
+
import { Command as Command28 } from "commander";
|
|
18771
|
+
import chalk30 from "chalk";
|
|
18772
|
+
import { existsSync as existsSync11 } from "fs";
|
|
18245
18773
|
import { mkdir as mkdir7, readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
|
|
18246
18774
|
import { execSync, spawnSync } from "child_process";
|
|
18247
18775
|
import { parse as parseYaml5 } from "yaml";
|
|
@@ -18264,57 +18792,57 @@ function isGhAuthenticated() {
|
|
|
18264
18792
|
async function checkPrerequisites() {
|
|
18265
18793
|
console.log("Checking prerequisites...");
|
|
18266
18794
|
if (!isGhInstalled()) {
|
|
18267
|
-
console.log(
|
|
18795
|
+
console.log(chalk30.red("\u2717 GitHub CLI (gh) is not installed"));
|
|
18268
18796
|
console.log();
|
|
18269
18797
|
console.log("GitHub CLI is required for this command.");
|
|
18270
18798
|
console.log();
|
|
18271
|
-
console.log(` macOS: ${
|
|
18272
|
-
console.log(` Other: ${
|
|
18799
|
+
console.log(` macOS: ${chalk30.cyan("brew install gh")}`);
|
|
18800
|
+
console.log(` Other: ${chalk30.cyan("https://cli.github.com/")}`);
|
|
18273
18801
|
console.log();
|
|
18274
18802
|
console.log("After installation, run:");
|
|
18275
|
-
console.log(` ${
|
|
18803
|
+
console.log(` ${chalk30.cyan("gh auth login")}`);
|
|
18276
18804
|
console.log();
|
|
18277
18805
|
console.log("Then try again:");
|
|
18278
|
-
console.log(` ${
|
|
18806
|
+
console.log(` ${chalk30.cyan("vm0 setup-github")}`);
|
|
18279
18807
|
process.exit(1);
|
|
18280
18808
|
}
|
|
18281
|
-
console.log(
|
|
18809
|
+
console.log(chalk30.green("\u2713 GitHub CLI (gh) is installed"));
|
|
18282
18810
|
if (!isGhAuthenticated()) {
|
|
18283
|
-
console.log(
|
|
18811
|
+
console.log(chalk30.red("\u2717 GitHub CLI is not authenticated"));
|
|
18284
18812
|
console.log();
|
|
18285
18813
|
console.log("Please authenticate GitHub CLI first:");
|
|
18286
|
-
console.log(` ${
|
|
18814
|
+
console.log(` ${chalk30.cyan("gh auth login")}`);
|
|
18287
18815
|
console.log();
|
|
18288
18816
|
console.log("Then try again:");
|
|
18289
|
-
console.log(` ${
|
|
18817
|
+
console.log(` ${chalk30.cyan("vm0 setup-github")}`);
|
|
18290
18818
|
process.exit(1);
|
|
18291
18819
|
}
|
|
18292
|
-
console.log(
|
|
18820
|
+
console.log(chalk30.green("\u2713 GitHub CLI is authenticated"));
|
|
18293
18821
|
const token = await getToken();
|
|
18294
18822
|
if (!token) {
|
|
18295
|
-
console.log(
|
|
18823
|
+
console.log(chalk30.red("\u2717 VM0 not authenticated"));
|
|
18296
18824
|
console.log();
|
|
18297
18825
|
console.log("Please authenticate with VM0 first:");
|
|
18298
|
-
console.log(` ${
|
|
18826
|
+
console.log(` ${chalk30.cyan("vm0 auth login")}`);
|
|
18299
18827
|
console.log();
|
|
18300
18828
|
console.log("Then try again:");
|
|
18301
|
-
console.log(` ${
|
|
18829
|
+
console.log(` ${chalk30.cyan("vm0 setup-github")}`);
|
|
18302
18830
|
process.exit(1);
|
|
18303
18831
|
}
|
|
18304
|
-
console.log(
|
|
18305
|
-
if (!
|
|
18306
|
-
console.log(
|
|
18832
|
+
console.log(chalk30.green("\u2713 VM0 authenticated"));
|
|
18833
|
+
if (!existsSync11("vm0.yaml")) {
|
|
18834
|
+
console.log(chalk30.red("\u2717 vm0.yaml not found"));
|
|
18307
18835
|
console.log();
|
|
18308
18836
|
console.log("This command requires a vm0.yaml configuration file.");
|
|
18309
18837
|
console.log();
|
|
18310
18838
|
console.log("To create one, run:");
|
|
18311
|
-
console.log(` ${
|
|
18839
|
+
console.log(` ${chalk30.cyan("vm0 init")}`);
|
|
18312
18840
|
console.log();
|
|
18313
18841
|
console.log("Then try again:");
|
|
18314
|
-
console.log(` ${
|
|
18842
|
+
console.log(` ${chalk30.cyan("vm0 setup-github")}`);
|
|
18315
18843
|
process.exit(1);
|
|
18316
18844
|
}
|
|
18317
|
-
console.log(
|
|
18845
|
+
console.log(chalk30.green("\u2713 vm0.yaml found"));
|
|
18318
18846
|
return token;
|
|
18319
18847
|
}
|
|
18320
18848
|
function generatePublishYaml() {
|
|
@@ -18425,22 +18953,8 @@ function extractSecretsAndVars(config2) {
|
|
|
18425
18953
|
};
|
|
18426
18954
|
}
|
|
18427
18955
|
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
|
-
});
|
|
18956
|
+
const result = await promptConfirm(question, defaultYes);
|
|
18957
|
+
return result ?? false;
|
|
18444
18958
|
}
|
|
18445
18959
|
function setGitHubSecret(name, value) {
|
|
18446
18960
|
const result = spawnSync("gh", ["secret", "set", name], {
|
|
@@ -18482,7 +18996,7 @@ function displaySecretsTable(secretStatuses, varStatuses) {
|
|
|
18482
18996
|
if (secretStatuses.length > 0) {
|
|
18483
18997
|
console.log("\u2502 Secrets: \u2502");
|
|
18484
18998
|
for (const s of secretStatuses) {
|
|
18485
|
-
const status = s.found ?
|
|
18999
|
+
const status = s.found ? chalk30.green("\u2713") : chalk30.red("\u2717");
|
|
18486
19000
|
const source = s.found ? `(from ${s.source})` : "not found";
|
|
18487
19001
|
const paddedName = (s.name + " ").padEnd(23, ".");
|
|
18488
19002
|
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
@@ -18491,7 +19005,7 @@ function displaySecretsTable(secretStatuses, varStatuses) {
|
|
|
18491
19005
|
if (varStatuses.length > 0) {
|
|
18492
19006
|
console.log("\u2502 Variables: \u2502");
|
|
18493
19007
|
for (const v of varStatuses) {
|
|
18494
|
-
const status = v.found ?
|
|
19008
|
+
const status = v.found ? chalk30.green("\u2713") : chalk30.red("\u2717");
|
|
18495
19009
|
const source = v.found ? `(from ${v.source})` : "not found";
|
|
18496
19010
|
const paddedName = (v.name + " ").padEnd(23, ".");
|
|
18497
19011
|
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
@@ -18503,17 +19017,17 @@ function showManualSetupInstructions(secrets, vars) {
|
|
|
18503
19017
|
console.log("Skipped automatic setup. Configure secrets manually:");
|
|
18504
19018
|
console.log();
|
|
18505
19019
|
console.log(" Step 1: Get your VM0 token");
|
|
18506
|
-
console.log(` ${
|
|
19020
|
+
console.log(` ${chalk30.cyan("vm0 auth setup-token")}`);
|
|
18507
19021
|
console.log();
|
|
18508
19022
|
console.log(" Step 2: Set GitHub secrets");
|
|
18509
19023
|
for (const s of secrets) {
|
|
18510
|
-
console.log(` ${
|
|
19024
|
+
console.log(` ${chalk30.cyan(`gh secret set ${s}`)}`);
|
|
18511
19025
|
}
|
|
18512
19026
|
if (vars.length > 0) {
|
|
18513
19027
|
console.log();
|
|
18514
19028
|
console.log(" Step 3: Set GitHub variables");
|
|
18515
19029
|
for (const v of vars) {
|
|
18516
|
-
console.log(` ${
|
|
19030
|
+
console.log(` ${chalk30.cyan(`gh variable set ${v}`)}`);
|
|
18517
19031
|
}
|
|
18518
19032
|
}
|
|
18519
19033
|
}
|
|
@@ -18556,7 +19070,7 @@ function showWorkflowsCreatedMessage() {
|
|
|
18556
19070
|
console.log("\u2502 3. Push to main branch to trigger publish \u2502");
|
|
18557
19071
|
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
19072
|
}
|
|
18559
|
-
var setupGithubCommand = new
|
|
19073
|
+
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
19074
|
async (options) => {
|
|
18561
19075
|
const vm0Token = await checkPrerequisites();
|
|
18562
19076
|
if (!vm0Token) {
|
|
@@ -18568,10 +19082,10 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18568
19082
|
const config2 = parseYaml5(content);
|
|
18569
19083
|
const agents = config2.agents;
|
|
18570
19084
|
const agentName = Object.keys(agents)[0];
|
|
18571
|
-
console.log(
|
|
19085
|
+
console.log(chalk30.green(`\u2713 Agent: ${agentName}`));
|
|
18572
19086
|
const { secrets, vars } = extractSecretsAndVars(config2);
|
|
18573
19087
|
console.log(
|
|
18574
|
-
|
|
19088
|
+
chalk30.green(
|
|
18575
19089
|
`\u2713 Found ${secrets.length} secrets, ${vars.length} variables`
|
|
18576
19090
|
)
|
|
18577
19091
|
);
|
|
@@ -18579,10 +19093,10 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18579
19093
|
const publishPath = ".github/workflows/publish.yml";
|
|
18580
19094
|
const runPath = ".github/workflows/run.yml";
|
|
18581
19095
|
const existingFiles = [];
|
|
18582
|
-
if (
|
|
18583
|
-
if (
|
|
19096
|
+
if (existsSync11(publishPath)) existingFiles.push(publishPath);
|
|
19097
|
+
if (existsSync11(runPath)) existingFiles.push(runPath);
|
|
18584
19098
|
if (existingFiles.length > 0 && !options.force) {
|
|
18585
|
-
console.log(
|
|
19099
|
+
console.log(chalk30.yellow("\u26A0 Existing workflow files detected:"));
|
|
18586
19100
|
for (const file2 of existingFiles) {
|
|
18587
19101
|
console.log(` \u2022 ${file2}`);
|
|
18588
19102
|
}
|
|
@@ -18595,7 +19109,7 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18595
19109
|
if (!overwrite) {
|
|
18596
19110
|
console.log();
|
|
18597
19111
|
console.log("Aborted. To force overwrite, run:");
|
|
18598
|
-
console.log(` ${
|
|
19112
|
+
console.log(` ${chalk30.cyan("vm0 setup-github --force")}`);
|
|
18599
19113
|
process.exit(0);
|
|
18600
19114
|
}
|
|
18601
19115
|
}
|
|
@@ -18605,13 +19119,13 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18605
19119
|
await mkdir7(".github/workflows", { recursive: true });
|
|
18606
19120
|
await writeFile8(publishPath, generatePublishYaml());
|
|
18607
19121
|
const publishStatus = existingFiles.includes(publishPath) ? "Overwrote" : "Created";
|
|
18608
|
-
console.log(
|
|
19122
|
+
console.log(chalk30.green(`\u2713 ${publishStatus} ${publishPath}`));
|
|
18609
19123
|
await writeFile8(runPath, generateRunYaml(agentName, secrets, vars));
|
|
18610
19124
|
const runStatus = existingFiles.includes(runPath) ? "Overwrote" : "Created";
|
|
18611
|
-
console.log(
|
|
19125
|
+
console.log(chalk30.green(`\u2713 ${runStatus} ${runPath}`));
|
|
18612
19126
|
console.log();
|
|
18613
19127
|
if (options.skipSecrets) {
|
|
18614
|
-
console.log(
|
|
19128
|
+
console.log(chalk30.green("\u2713 Done (secrets setup skipped)"));
|
|
18615
19129
|
return;
|
|
18616
19130
|
}
|
|
18617
19131
|
const { secretStatuses, varStatuses } = await detectSecretValues(
|
|
@@ -18651,14 +19165,14 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18651
19165
|
if (s.found && s.value) {
|
|
18652
19166
|
const success2 = setGitHubSecret(s.name, s.value);
|
|
18653
19167
|
if (success2) {
|
|
18654
|
-
console.log(` ${
|
|
19168
|
+
console.log(` ${chalk30.green("\u2713")} ${s.name}`);
|
|
18655
19169
|
} else {
|
|
18656
|
-
console.log(` ${
|
|
19170
|
+
console.log(` ${chalk30.red("\u2717")} ${s.name} (failed)`);
|
|
18657
19171
|
failedSecrets.push(s.name);
|
|
18658
19172
|
}
|
|
18659
19173
|
} else {
|
|
18660
19174
|
console.log(
|
|
18661
|
-
` ${
|
|
19175
|
+
` ${chalk30.yellow("\u26A0")} ${s.name} (skipped - not found)`
|
|
18662
19176
|
);
|
|
18663
19177
|
}
|
|
18664
19178
|
}
|
|
@@ -18670,14 +19184,14 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18670
19184
|
if (v.found && v.value) {
|
|
18671
19185
|
const success2 = setGitHubVariable(v.name, v.value);
|
|
18672
19186
|
if (success2) {
|
|
18673
|
-
console.log(` ${
|
|
19187
|
+
console.log(` ${chalk30.green("\u2713")} ${v.name}`);
|
|
18674
19188
|
} else {
|
|
18675
|
-
console.log(` ${
|
|
19189
|
+
console.log(` ${chalk30.red("\u2717")} ${v.name} (failed)`);
|
|
18676
19190
|
failedVars.push(v.name);
|
|
18677
19191
|
}
|
|
18678
19192
|
} else {
|
|
18679
19193
|
console.log(
|
|
18680
|
-
` ${
|
|
19194
|
+
` ${chalk30.yellow("\u26A0")} ${v.name} (skipped - not found)`
|
|
18681
19195
|
);
|
|
18682
19196
|
}
|
|
18683
19197
|
}
|
|
@@ -18700,10 +19214,10 @@ var setupGithubCommand = new Command24().name("setup-github").description("Initi
|
|
|
18700
19214
|
);
|
|
18701
19215
|
|
|
18702
19216
|
// src/index.ts
|
|
18703
|
-
var program = new
|
|
18704
|
-
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.
|
|
19217
|
+
var program = new Command29();
|
|
19218
|
+
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.33.0");
|
|
18705
19219
|
program.command("info").description("Display environment information").action(async () => {
|
|
18706
|
-
console.log(
|
|
19220
|
+
console.log(chalk31.bold("System Information:"));
|
|
18707
19221
|
console.log(`Node Version: ${process.version}`);
|
|
18708
19222
|
console.log(`Platform: ${process.platform}`);
|
|
18709
19223
|
console.log(`Architecture: ${process.arch}`);
|