@vm0/cli 9.3.0 → 9.4.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 +956 -1160
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
5
|
-
import
|
|
4
|
+
import { Command as Command50 } from "commander";
|
|
5
|
+
import chalk53 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/lib/api/auth.ts
|
|
8
8
|
import chalk from "chalk";
|
|
@@ -354,7 +354,9 @@ var storedExecutionContextSchema = z3.object({
|
|
|
354
354
|
cliAgentType: z3.string(),
|
|
355
355
|
experimentalFirewall: experimentalFirewallSchema.optional(),
|
|
356
356
|
// Debug flag to force real Claude in mock environments (internal use only)
|
|
357
|
-
debugNoMockClaude: z3.boolean().optional()
|
|
357
|
+
debugNoMockClaude: z3.boolean().optional(),
|
|
358
|
+
// Dispatch timestamp for E2E timing metrics
|
|
359
|
+
apiStartTime: z3.number().optional()
|
|
358
360
|
});
|
|
359
361
|
var executionContextSchema = z3.object({
|
|
360
362
|
runId: z3.string().uuid(),
|
|
@@ -374,7 +376,9 @@ var executionContextSchema = z3.object({
|
|
|
374
376
|
// Experimental firewall configuration
|
|
375
377
|
experimentalFirewall: experimentalFirewallSchema.optional(),
|
|
376
378
|
// Debug flag to force real Claude in mock environments (internal use only)
|
|
377
|
-
debugNoMockClaude: z3.boolean().optional()
|
|
379
|
+
debugNoMockClaude: z3.boolean().optional(),
|
|
380
|
+
// Dispatch timestamp for E2E timing metrics
|
|
381
|
+
apiStartTime: z3.number().optional()
|
|
378
382
|
});
|
|
379
383
|
var runnersJobClaimContract = c.router({
|
|
380
384
|
claim: {
|
|
@@ -711,7 +715,36 @@ var eventsResponseSchema = z5.object({
|
|
|
711
715
|
run: runStateSchema,
|
|
712
716
|
framework: z5.string()
|
|
713
717
|
});
|
|
718
|
+
var runListItemSchema = z5.object({
|
|
719
|
+
id: z5.string(),
|
|
720
|
+
agentName: z5.string(),
|
|
721
|
+
status: runStatusSchema,
|
|
722
|
+
prompt: z5.string(),
|
|
723
|
+
createdAt: z5.string(),
|
|
724
|
+
startedAt: z5.string().nullable()
|
|
725
|
+
});
|
|
726
|
+
var runsListResponseSchema = z5.object({
|
|
727
|
+
runs: z5.array(runListItemSchema)
|
|
728
|
+
});
|
|
714
729
|
var runsMainContract = c3.router({
|
|
730
|
+
/**
|
|
731
|
+
* GET /api/agent/runs
|
|
732
|
+
* List agent runs (pending and running by default)
|
|
733
|
+
*/
|
|
734
|
+
list: {
|
|
735
|
+
method: "GET",
|
|
736
|
+
path: "/api/agent/runs",
|
|
737
|
+
headers: authHeadersSchema,
|
|
738
|
+
query: z5.object({
|
|
739
|
+
status: runStatusSchema.optional(),
|
|
740
|
+
limit: z5.coerce.number().min(1).max(100).default(50)
|
|
741
|
+
}),
|
|
742
|
+
responses: {
|
|
743
|
+
200: runsListResponseSchema,
|
|
744
|
+
401: apiErrorSchema
|
|
745
|
+
},
|
|
746
|
+
summary: "List agent runs"
|
|
747
|
+
},
|
|
715
748
|
/**
|
|
716
749
|
* POST /api/agent/runs
|
|
717
750
|
* Create and execute a new agent run
|
|
@@ -752,6 +785,33 @@ var runsByIdContract = c3.router({
|
|
|
752
785
|
summary: "Get agent run by ID"
|
|
753
786
|
}
|
|
754
787
|
});
|
|
788
|
+
var cancelRunResponseSchema = z5.object({
|
|
789
|
+
id: z5.string(),
|
|
790
|
+
status: z5.literal("cancelled"),
|
|
791
|
+
message: z5.string()
|
|
792
|
+
});
|
|
793
|
+
var runsCancelContract = c3.router({
|
|
794
|
+
/**
|
|
795
|
+
* POST /api/agent/runs/:id/cancel
|
|
796
|
+
* Cancel a pending or running run
|
|
797
|
+
*/
|
|
798
|
+
cancel: {
|
|
799
|
+
method: "POST",
|
|
800
|
+
path: "/api/agent/runs/:id/cancel",
|
|
801
|
+
headers: authHeadersSchema,
|
|
802
|
+
pathParams: z5.object({
|
|
803
|
+
id: z5.string().min(1, "Run ID is required")
|
|
804
|
+
}),
|
|
805
|
+
body: z5.undefined(),
|
|
806
|
+
responses: {
|
|
807
|
+
200: cancelRunResponseSchema,
|
|
808
|
+
400: apiErrorSchema,
|
|
809
|
+
401: apiErrorSchema,
|
|
810
|
+
404: apiErrorSchema
|
|
811
|
+
},
|
|
812
|
+
summary: "Cancel a pending or running run"
|
|
813
|
+
}
|
|
814
|
+
});
|
|
755
815
|
var runEventsContract = c3.router({
|
|
756
816
|
/**
|
|
757
817
|
* GET /api/agent/runs/:id/events
|
|
@@ -3149,10 +3209,10 @@ async function getRawHeaders() {
|
|
|
3149
3209
|
}
|
|
3150
3210
|
return headers;
|
|
3151
3211
|
}
|
|
3152
|
-
async function httpGet(
|
|
3212
|
+
async function httpGet(path15) {
|
|
3153
3213
|
const baseUrl = await getBaseUrl();
|
|
3154
3214
|
const headers = await getRawHeaders();
|
|
3155
|
-
return fetch(`${baseUrl}${
|
|
3215
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
3156
3216
|
method: "GET",
|
|
3157
3217
|
headers
|
|
3158
3218
|
});
|
|
@@ -3234,6 +3294,31 @@ async function getEvents(runId, options) {
|
|
|
3234
3294
|
}
|
|
3235
3295
|
handleError(result, "Failed to fetch events");
|
|
3236
3296
|
}
|
|
3297
|
+
async function listRuns(params) {
|
|
3298
|
+
const config = await getClientConfig();
|
|
3299
|
+
const client = initClient2(runsMainContract, config);
|
|
3300
|
+
const result = await client.list({
|
|
3301
|
+
query: {
|
|
3302
|
+
status: params?.status,
|
|
3303
|
+
limit: params?.limit ?? 50
|
|
3304
|
+
}
|
|
3305
|
+
});
|
|
3306
|
+
if (result.status === 200) {
|
|
3307
|
+
return result.body;
|
|
3308
|
+
}
|
|
3309
|
+
handleError(result, "Failed to list runs");
|
|
3310
|
+
}
|
|
3311
|
+
async function cancelRun(runId) {
|
|
3312
|
+
const config = await getClientConfig();
|
|
3313
|
+
const client = initClient2(runsCancelContract, config);
|
|
3314
|
+
const result = await client.cancel({
|
|
3315
|
+
params: { id: runId }
|
|
3316
|
+
});
|
|
3317
|
+
if (result.status === 200) {
|
|
3318
|
+
return result.body;
|
|
3319
|
+
}
|
|
3320
|
+
handleError(result, "Failed to cancel run");
|
|
3321
|
+
}
|
|
3237
3322
|
|
|
3238
3323
|
// src/lib/api/domains/sessions.ts
|
|
3239
3324
|
import { initClient as initClient3 } from "@ts-rest/core";
|
|
@@ -3632,49 +3717,49 @@ var cliComposeSchema = z24.object({
|
|
|
3632
3717
|
function formatZodError(error) {
|
|
3633
3718
|
const issue = error.issues[0];
|
|
3634
3719
|
if (!issue) return "Validation failed";
|
|
3635
|
-
const
|
|
3720
|
+
const path15 = issue.path.join(".");
|
|
3636
3721
|
const message = issue.message;
|
|
3637
|
-
if (!
|
|
3722
|
+
if (!path15) return message;
|
|
3638
3723
|
if (issue.code === "invalid_type") {
|
|
3639
3724
|
const received = issue.received;
|
|
3640
3725
|
const isMissing = received === "undefined" || message.includes("received undefined") || message === "Required";
|
|
3641
|
-
if (
|
|
3726
|
+
if (path15 === "version" && isMissing) {
|
|
3642
3727
|
return "Missing config.version";
|
|
3643
3728
|
}
|
|
3644
|
-
if (
|
|
3729
|
+
if (path15 === "agents" && isMissing) {
|
|
3645
3730
|
return "Missing agents object in config";
|
|
3646
3731
|
}
|
|
3647
|
-
if (
|
|
3648
|
-
const volumeKey =
|
|
3732
|
+
if (path15.startsWith("volumes.") && path15.endsWith(".name")) {
|
|
3733
|
+
const volumeKey = path15.split(".")[1];
|
|
3649
3734
|
return `Volume "${volumeKey}" must have a 'name' field (string)`;
|
|
3650
3735
|
}
|
|
3651
|
-
if (
|
|
3652
|
-
const volumeKey =
|
|
3736
|
+
if (path15.startsWith("volumes.") && path15.endsWith(".version")) {
|
|
3737
|
+
const volumeKey = path15.split(".")[1];
|
|
3653
3738
|
return `Volume "${volumeKey}" must have a 'version' field (string)`;
|
|
3654
3739
|
}
|
|
3655
3740
|
if (issue.expected === "array") {
|
|
3656
|
-
const fieldName =
|
|
3741
|
+
const fieldName = path15.replace(/^agents\.[^.]+\./, "agent.");
|
|
3657
3742
|
return `${fieldName} must be an array`;
|
|
3658
3743
|
}
|
|
3659
3744
|
if (issue.expected === "string" && received === "number") {
|
|
3660
|
-
const fieldName =
|
|
3745
|
+
const fieldName = path15.replace(/^agents\.[^.]+\./, "agent.");
|
|
3661
3746
|
const match = fieldName.match(/^(agent\.[^.]+)\.\d+$/);
|
|
3662
3747
|
if (match) {
|
|
3663
3748
|
return `Each entry in ${match[1]?.replace("agent.", "")} must be a string`;
|
|
3664
3749
|
}
|
|
3665
3750
|
}
|
|
3666
3751
|
}
|
|
3667
|
-
if (issue.code === "invalid_key" &&
|
|
3752
|
+
if (issue.code === "invalid_key" && path15.startsWith("agents.")) {
|
|
3668
3753
|
return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
|
|
3669
3754
|
}
|
|
3670
|
-
if (message === "Invalid key in record" &&
|
|
3755
|
+
if (message === "Invalid key in record" && path15.startsWith("agents.")) {
|
|
3671
3756
|
return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
|
|
3672
3757
|
}
|
|
3673
3758
|
if (issue.code === "custom") {
|
|
3674
3759
|
return message;
|
|
3675
3760
|
}
|
|
3676
|
-
if (
|
|
3677
|
-
const cleanPath =
|
|
3761
|
+
if (path15.startsWith("agents.")) {
|
|
3762
|
+
const cleanPath = path15.replace(/^agents\.[^.]+\./, "agent.");
|
|
3678
3763
|
if (message.startsWith("Invalid input:")) {
|
|
3679
3764
|
const match = message.match(/expected (\w+), received (\w+)/);
|
|
3680
3765
|
if (match && match[1] === "string" && match[2] === "number") {
|
|
@@ -3686,7 +3771,7 @@ function formatZodError(error) {
|
|
|
3686
3771
|
}
|
|
3687
3772
|
return `${cleanPath}: ${message}`;
|
|
3688
3773
|
}
|
|
3689
|
-
return `${
|
|
3774
|
+
return `${path15}: ${message}`;
|
|
3690
3775
|
}
|
|
3691
3776
|
function validateAgentName(name) {
|
|
3692
3777
|
return cliAgentNameSchema.safeParse(name).success;
|
|
@@ -5862,7 +5947,7 @@ var ApiClient = class {
|
|
|
5862
5947
|
/**
|
|
5863
5948
|
* Generic GET request
|
|
5864
5949
|
*/
|
|
5865
|
-
async get(
|
|
5950
|
+
async get(path15) {
|
|
5866
5951
|
const baseUrl = await this.getBaseUrl();
|
|
5867
5952
|
const token = await getToken();
|
|
5868
5953
|
if (!token) {
|
|
@@ -5875,7 +5960,7 @@ var ApiClient = class {
|
|
|
5875
5960
|
if (bypassSecret) {
|
|
5876
5961
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
5877
5962
|
}
|
|
5878
|
-
return fetch(`${baseUrl}${
|
|
5963
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
5879
5964
|
method: "GET",
|
|
5880
5965
|
headers
|
|
5881
5966
|
});
|
|
@@ -5883,7 +5968,7 @@ var ApiClient = class {
|
|
|
5883
5968
|
/**
|
|
5884
5969
|
* Generic POST request
|
|
5885
5970
|
*/
|
|
5886
|
-
async post(
|
|
5971
|
+
async post(path15, options) {
|
|
5887
5972
|
const baseUrl = await this.getBaseUrl();
|
|
5888
5973
|
const token = await getToken();
|
|
5889
5974
|
if (!token) {
|
|
@@ -5899,7 +5984,7 @@ var ApiClient = class {
|
|
|
5899
5984
|
if (bypassSecret) {
|
|
5900
5985
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
5901
5986
|
}
|
|
5902
|
-
return fetch(`${baseUrl}${
|
|
5987
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
5903
5988
|
method: "POST",
|
|
5904
5989
|
headers,
|
|
5905
5990
|
body: options?.body
|
|
@@ -5908,7 +5993,7 @@ var ApiClient = class {
|
|
|
5908
5993
|
/**
|
|
5909
5994
|
* Generic DELETE request
|
|
5910
5995
|
*/
|
|
5911
|
-
async delete(
|
|
5996
|
+
async delete(path15) {
|
|
5912
5997
|
const baseUrl = await this.getBaseUrl();
|
|
5913
5998
|
const token = await getToken();
|
|
5914
5999
|
if (!token) {
|
|
@@ -5921,7 +6006,7 @@ var ApiClient = class {
|
|
|
5921
6006
|
if (bypassSecret) {
|
|
5922
6007
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
5923
6008
|
}
|
|
5924
|
-
return fetch(`${baseUrl}${
|
|
6009
|
+
return fetch(`${baseUrl}${path15}`, {
|
|
5925
6010
|
method: "DELETE",
|
|
5926
6011
|
headers
|
|
5927
6012
|
});
|
|
@@ -6198,6 +6283,20 @@ function showNextSteps(result) {
|
|
|
6198
6283
|
);
|
|
6199
6284
|
}
|
|
6200
6285
|
}
|
|
6286
|
+
function handleGenericRunError(error, commandLabel) {
|
|
6287
|
+
if (error instanceof ApiRequestError && error.code === "concurrent_run_limit_exceeded") {
|
|
6288
|
+
console.error(chalk5.red(`\u2717 ${commandLabel} failed`));
|
|
6289
|
+
console.error(chalk5.dim(` ${error.message}`));
|
|
6290
|
+
console.log();
|
|
6291
|
+
console.log(" To view active runs:");
|
|
6292
|
+
console.log(chalk5.cyan(" vm0 run list"));
|
|
6293
|
+
console.log(" To cancel a run:");
|
|
6294
|
+
console.log(chalk5.cyan(" vm0 run kill <run-id>"));
|
|
6295
|
+
} else {
|
|
6296
|
+
console.error(chalk5.red(`\u2717 ${commandLabel} failed`));
|
|
6297
|
+
console.error(chalk5.dim(` ${error.message}`));
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
6201
6300
|
|
|
6202
6301
|
// src/commands/run/run.ts
|
|
6203
6302
|
var mainRunCommand = new Command3().name("run").description("Run an agent").argument(
|
|
@@ -6328,8 +6427,7 @@ var mainRunCommand = new Command3().name("run").description("Run an agent").argu
|
|
|
6328
6427
|
)
|
|
6329
6428
|
);
|
|
6330
6429
|
} else {
|
|
6331
|
-
|
|
6332
|
-
console.error(chalk6.dim(` ${error.message}`));
|
|
6430
|
+
handleGenericRunError(error, "Run");
|
|
6333
6431
|
}
|
|
6334
6432
|
} else {
|
|
6335
6433
|
console.error(chalk6.red("\u2717 An unexpected error occurred"));
|
|
@@ -6426,8 +6524,7 @@ var resumeCommand = new Command4().name("resume").description("Resume an agent r
|
|
|
6426
6524
|
} else if (error.message.includes("not found")) {
|
|
6427
6525
|
console.error(chalk7.red(`\u2717 Checkpoint not found: ${checkpointId}`));
|
|
6428
6526
|
} else {
|
|
6429
|
-
|
|
6430
|
-
console.error(chalk7.dim(` ${error.message}`));
|
|
6527
|
+
handleGenericRunError(error, "Resume");
|
|
6431
6528
|
}
|
|
6432
6529
|
} else {
|
|
6433
6530
|
console.error(chalk7.red("\u2717 An unexpected error occurred"));
|
|
@@ -6528,8 +6625,7 @@ var continueCommand = new Command5().name("continue").description(
|
|
|
6528
6625
|
chalk8.red(`\u2717 Agent session not found: ${agentSessionId}`)
|
|
6529
6626
|
);
|
|
6530
6627
|
} else {
|
|
6531
|
-
|
|
6532
|
-
console.error(chalk8.dim(` ${error.message}`));
|
|
6628
|
+
handleGenericRunError(error, "Continue");
|
|
6533
6629
|
}
|
|
6534
6630
|
} else {
|
|
6535
6631
|
console.error(chalk8.red("\u2717 An unexpected error occurred"));
|
|
@@ -6539,17 +6635,105 @@ var continueCommand = new Command5().name("continue").description(
|
|
|
6539
6635
|
}
|
|
6540
6636
|
);
|
|
6541
6637
|
|
|
6638
|
+
// src/commands/run/list.ts
|
|
6639
|
+
import { Command as Command6 } from "commander";
|
|
6640
|
+
import chalk9 from "chalk";
|
|
6641
|
+
var UUID_LENGTH = 36;
|
|
6642
|
+
function formatRunStatus(status, width) {
|
|
6643
|
+
const paddedStatus = width ? status.padEnd(width) : status;
|
|
6644
|
+
switch (status) {
|
|
6645
|
+
case "running":
|
|
6646
|
+
return chalk9.green(paddedStatus);
|
|
6647
|
+
case "pending":
|
|
6648
|
+
return chalk9.yellow(paddedStatus);
|
|
6649
|
+
case "completed":
|
|
6650
|
+
return chalk9.blue(paddedStatus);
|
|
6651
|
+
case "failed":
|
|
6652
|
+
case "timeout":
|
|
6653
|
+
return chalk9.red(paddedStatus);
|
|
6654
|
+
default:
|
|
6655
|
+
return paddedStatus;
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
var listCommand = new Command6().name("list").alias("ls").description("List active runs (pending and running)").action(async () => {
|
|
6659
|
+
try {
|
|
6660
|
+
const response = await listRuns({ limit: 100 });
|
|
6661
|
+
const activeRuns = response.runs;
|
|
6662
|
+
if (activeRuns.length === 0) {
|
|
6663
|
+
console.log(chalk9.dim("No active runs"));
|
|
6664
|
+
return;
|
|
6665
|
+
}
|
|
6666
|
+
const agentWidth = Math.max(
|
|
6667
|
+
5,
|
|
6668
|
+
...activeRuns.map((r) => r.agentName.length)
|
|
6669
|
+
);
|
|
6670
|
+
const statusWidth = 7;
|
|
6671
|
+
const header = [
|
|
6672
|
+
"ID".padEnd(UUID_LENGTH),
|
|
6673
|
+
"AGENT".padEnd(agentWidth),
|
|
6674
|
+
"STATUS".padEnd(statusWidth),
|
|
6675
|
+
"CREATED"
|
|
6676
|
+
].join(" ");
|
|
6677
|
+
console.log(chalk9.dim(header));
|
|
6678
|
+
for (const run of activeRuns) {
|
|
6679
|
+
const row = [
|
|
6680
|
+
run.id.padEnd(UUID_LENGTH),
|
|
6681
|
+
run.agentName.padEnd(agentWidth),
|
|
6682
|
+
formatRunStatus(run.status, statusWidth),
|
|
6683
|
+
formatRelativeTime(run.createdAt)
|
|
6684
|
+
].join(" ");
|
|
6685
|
+
console.log(row);
|
|
6686
|
+
}
|
|
6687
|
+
} catch (error) {
|
|
6688
|
+
console.error(chalk9.red("\u2717 Failed to list runs"));
|
|
6689
|
+
if (error instanceof Error) {
|
|
6690
|
+
if (error.message.includes("Not authenticated")) {
|
|
6691
|
+
console.error(chalk9.dim(" Run: vm0 auth login"));
|
|
6692
|
+
} else {
|
|
6693
|
+
console.error(chalk9.dim(` ${error.message}`));
|
|
6694
|
+
}
|
|
6695
|
+
}
|
|
6696
|
+
process.exit(1);
|
|
6697
|
+
}
|
|
6698
|
+
});
|
|
6699
|
+
|
|
6700
|
+
// src/commands/run/kill.ts
|
|
6701
|
+
import { Command as Command7 } from "commander";
|
|
6702
|
+
import chalk10 from "chalk";
|
|
6703
|
+
var killCommand = new Command7().name("kill").description("Kill (cancel) a pending or running run").argument("<run-id>", "Run ID to kill").action(async (runId) => {
|
|
6704
|
+
try {
|
|
6705
|
+
await cancelRun(runId);
|
|
6706
|
+
console.log(chalk10.green(`\u2713 Run ${runId} cancelled`));
|
|
6707
|
+
} catch (error) {
|
|
6708
|
+
console.error(chalk10.red("\u2717 Failed to kill run"));
|
|
6709
|
+
if (error instanceof Error) {
|
|
6710
|
+
if (error.message.includes("Not authenticated")) {
|
|
6711
|
+
console.error(chalk10.dim(" Run: vm0 auth login"));
|
|
6712
|
+
} else if (error.message.includes("not found") || error.message.includes("No such run")) {
|
|
6713
|
+
console.error(chalk10.dim(` Run not found: ${runId}`));
|
|
6714
|
+
} else if (error.message.includes("cannot be cancelled")) {
|
|
6715
|
+
console.error(chalk10.dim(` ${error.message}`));
|
|
6716
|
+
} else {
|
|
6717
|
+
console.error(chalk10.dim(` ${error.message}`));
|
|
6718
|
+
}
|
|
6719
|
+
}
|
|
6720
|
+
process.exit(1);
|
|
6721
|
+
}
|
|
6722
|
+
});
|
|
6723
|
+
|
|
6542
6724
|
// src/commands/run/index.ts
|
|
6543
6725
|
mainRunCommand.addCommand(resumeCommand);
|
|
6544
6726
|
mainRunCommand.addCommand(continueCommand);
|
|
6727
|
+
mainRunCommand.addCommand(listCommand);
|
|
6728
|
+
mainRunCommand.addCommand(killCommand);
|
|
6545
6729
|
var runCommand = mainRunCommand;
|
|
6546
6730
|
|
|
6547
6731
|
// src/commands/volume/index.ts
|
|
6548
|
-
import { Command as
|
|
6732
|
+
import { Command as Command14 } from "commander";
|
|
6549
6733
|
|
|
6550
6734
|
// src/commands/volume/init.ts
|
|
6551
|
-
import { Command as
|
|
6552
|
-
import
|
|
6735
|
+
import { Command as Command8 } from "commander";
|
|
6736
|
+
import chalk11 from "chalk";
|
|
6553
6737
|
import path6 from "path";
|
|
6554
6738
|
|
|
6555
6739
|
// src/lib/storage/storage-utils.ts
|
|
@@ -6600,17 +6784,17 @@ async function writeStorageConfig(storageName, basePath = process.cwd(), type =
|
|
|
6600
6784
|
}
|
|
6601
6785
|
|
|
6602
6786
|
// src/commands/volume/init.ts
|
|
6603
|
-
var initCommand = new
|
|
6787
|
+
var initCommand = new Command8().name("init").description("Initialize a volume in the current directory").option("-n, --name <name>", "Volume name (required in non-interactive mode)").action(async (options) => {
|
|
6604
6788
|
try {
|
|
6605
6789
|
const cwd = process.cwd();
|
|
6606
6790
|
const dirName = path6.basename(cwd);
|
|
6607
6791
|
const existingConfig = await readStorageConfig(cwd);
|
|
6608
6792
|
if (existingConfig) {
|
|
6609
6793
|
console.log(
|
|
6610
|
-
|
|
6794
|
+
chalk11.yellow(`Volume already initialized: ${existingConfig.name}`)
|
|
6611
6795
|
);
|
|
6612
6796
|
console.log(
|
|
6613
|
-
|
|
6797
|
+
chalk11.dim(`Config file: ${path6.join(cwd, ".vm0", "storage.yaml")}`)
|
|
6614
6798
|
);
|
|
6615
6799
|
return;
|
|
6616
6800
|
}
|
|
@@ -6619,10 +6803,10 @@ var initCommand = new Command6().name("init").description("Initialize a volume i
|
|
|
6619
6803
|
volumeName = options.name;
|
|
6620
6804
|
} else if (!isInteractive()) {
|
|
6621
6805
|
console.error(
|
|
6622
|
-
|
|
6806
|
+
chalk11.red("\u2717 --name flag is required in non-interactive mode")
|
|
6623
6807
|
);
|
|
6624
6808
|
console.error(
|
|
6625
|
-
|
|
6809
|
+
chalk11.dim(" Usage: vm0 volume init --name <volume-name>")
|
|
6626
6810
|
);
|
|
6627
6811
|
process.exit(1);
|
|
6628
6812
|
} else {
|
|
@@ -6638,43 +6822,43 @@ var initCommand = new Command6().name("init").description("Initialize a volume i
|
|
|
6638
6822
|
}
|
|
6639
6823
|
);
|
|
6640
6824
|
if (name === void 0) {
|
|
6641
|
-
console.log(
|
|
6825
|
+
console.log(chalk11.dim("Cancelled"));
|
|
6642
6826
|
return;
|
|
6643
6827
|
}
|
|
6644
6828
|
volumeName = name;
|
|
6645
6829
|
}
|
|
6646
6830
|
if (!isValidStorageName(volumeName)) {
|
|
6647
|
-
console.error(
|
|
6831
|
+
console.error(chalk11.red(`\u2717 Invalid volume name: "${volumeName}"`));
|
|
6648
6832
|
console.error(
|
|
6649
|
-
|
|
6833
|
+
chalk11.dim(
|
|
6650
6834
|
" Volume names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
6651
6835
|
)
|
|
6652
6836
|
);
|
|
6653
6837
|
console.error(
|
|
6654
|
-
|
|
6838
|
+
chalk11.dim(" Example: my-dataset, user-data-v2, training-set-2024")
|
|
6655
6839
|
);
|
|
6656
6840
|
process.exit(1);
|
|
6657
6841
|
}
|
|
6658
6842
|
await writeStorageConfig(volumeName, cwd);
|
|
6659
|
-
console.log(
|
|
6843
|
+
console.log(chalk11.green(`\u2713 Initialized volume: ${volumeName}`));
|
|
6660
6844
|
console.log(
|
|
6661
|
-
|
|
6845
|
+
chalk11.dim(
|
|
6662
6846
|
` Config saved to ${path6.join(cwd, ".vm0", "storage.yaml")}`
|
|
6663
6847
|
)
|
|
6664
6848
|
);
|
|
6665
6849
|
} catch (error) {
|
|
6666
|
-
console.error(
|
|
6850
|
+
console.error(chalk11.red("\u2717 Failed to initialize volume"));
|
|
6667
6851
|
if (error instanceof Error) {
|
|
6668
|
-
console.error(
|
|
6852
|
+
console.error(chalk11.dim(` ${error.message}`));
|
|
6669
6853
|
}
|
|
6670
6854
|
process.exit(1);
|
|
6671
6855
|
}
|
|
6672
6856
|
});
|
|
6673
6857
|
|
|
6674
6858
|
// src/commands/volume/push.ts
|
|
6675
|
-
import { Command as
|
|
6676
|
-
import
|
|
6677
|
-
var pushCommand = new
|
|
6859
|
+
import { Command as Command9 } from "commander";
|
|
6860
|
+
import chalk12 from "chalk";
|
|
6861
|
+
var pushCommand = new Command9().name("push").description("Push local files to cloud volume").option(
|
|
6678
6862
|
"-f, --force",
|
|
6679
6863
|
"Force upload even if content unchanged (recreate archive)"
|
|
6680
6864
|
).action(async (options) => {
|
|
@@ -6682,35 +6866,35 @@ var pushCommand = new Command7().name("push").description("Push local files to c
|
|
|
6682
6866
|
const cwd = process.cwd();
|
|
6683
6867
|
const config = await readStorageConfig(cwd);
|
|
6684
6868
|
if (!config) {
|
|
6685
|
-
console.error(
|
|
6686
|
-
console.error(
|
|
6869
|
+
console.error(chalk12.red("\u2717 No volume initialized in this directory"));
|
|
6870
|
+
console.error(chalk12.dim(" Run: vm0 volume init"));
|
|
6687
6871
|
process.exit(1);
|
|
6688
6872
|
}
|
|
6689
6873
|
console.log(`Pushing volume: ${config.name}`);
|
|
6690
6874
|
const result = await directUpload(config.name, "volume", cwd, {
|
|
6691
6875
|
onProgress: (message) => {
|
|
6692
|
-
console.log(
|
|
6876
|
+
console.log(chalk12.dim(message));
|
|
6693
6877
|
},
|
|
6694
6878
|
force: options.force
|
|
6695
6879
|
});
|
|
6696
6880
|
const shortVersion = result.versionId.slice(0, 8);
|
|
6697
6881
|
if (result.empty) {
|
|
6698
|
-
console.log(
|
|
6882
|
+
console.log(chalk12.dim("No files found (empty volume)"));
|
|
6699
6883
|
} else if (result.deduplicated) {
|
|
6700
|
-
console.log(
|
|
6884
|
+
console.log(chalk12.green("\u2713 Content unchanged (deduplicated)"));
|
|
6701
6885
|
} else {
|
|
6702
|
-
console.log(
|
|
6886
|
+
console.log(chalk12.green("\u2713 Upload complete"));
|
|
6703
6887
|
}
|
|
6704
|
-
console.log(
|
|
6705
|
-
console.log(
|
|
6706
|
-
console.log(
|
|
6888
|
+
console.log(chalk12.dim(` Version: ${shortVersion}`));
|
|
6889
|
+
console.log(chalk12.dim(` Files: ${result.fileCount.toLocaleString()}`));
|
|
6890
|
+
console.log(chalk12.dim(` Size: ${formatBytes(result.size)}`));
|
|
6707
6891
|
} catch (error) {
|
|
6708
|
-
console.error(
|
|
6892
|
+
console.error(chalk12.red("\u2717 Push failed"));
|
|
6709
6893
|
if (error instanceof Error) {
|
|
6710
6894
|
if (error.message.includes("Not authenticated")) {
|
|
6711
|
-
console.error(
|
|
6895
|
+
console.error(chalk12.dim(" Run: vm0 auth login"));
|
|
6712
6896
|
} else {
|
|
6713
|
-
console.error(
|
|
6897
|
+
console.error(chalk12.dim(` ${error.message}`));
|
|
6714
6898
|
}
|
|
6715
6899
|
}
|
|
6716
6900
|
process.exit(1);
|
|
@@ -6718,33 +6902,33 @@ var pushCommand = new Command7().name("push").description("Push local files to c
|
|
|
6718
6902
|
});
|
|
6719
6903
|
|
|
6720
6904
|
// src/commands/volume/pull.ts
|
|
6721
|
-
import { Command as
|
|
6722
|
-
import
|
|
6905
|
+
import { Command as Command10 } from "commander";
|
|
6906
|
+
import chalk14 from "chalk";
|
|
6723
6907
|
import path7 from "path";
|
|
6724
6908
|
import * as fs6 from "fs";
|
|
6725
6909
|
import * as os4 from "os";
|
|
6726
6910
|
import * as tar3 from "tar";
|
|
6727
6911
|
|
|
6728
6912
|
// src/lib/storage/pull-utils.ts
|
|
6729
|
-
import
|
|
6913
|
+
import chalk13 from "chalk";
|
|
6730
6914
|
async function handleEmptyStorageResponse(cwd) {
|
|
6731
|
-
console.log(
|
|
6915
|
+
console.log(chalk13.dim("Syncing local files..."));
|
|
6732
6916
|
const removedCount = await removeExtraFiles(cwd, /* @__PURE__ */ new Set());
|
|
6733
6917
|
if (removedCount > 0) {
|
|
6734
|
-
console.log(
|
|
6918
|
+
console.log(chalk13.green(`\u2713 Removed ${removedCount} files not in remote`));
|
|
6735
6919
|
}
|
|
6736
|
-
console.log(
|
|
6920
|
+
console.log(chalk13.green("\u2713 Synced (0 files)"));
|
|
6737
6921
|
return { removedCount };
|
|
6738
6922
|
}
|
|
6739
6923
|
|
|
6740
6924
|
// src/commands/volume/pull.ts
|
|
6741
|
-
var pullCommand = new
|
|
6925
|
+
var pullCommand = new Command10().name("pull").description("Pull cloud files to local directory").argument("[versionId]", "Version ID to pull (default: latest)").action(async (versionId) => {
|
|
6742
6926
|
try {
|
|
6743
6927
|
const cwd = process.cwd();
|
|
6744
6928
|
const config = await readStorageConfig(cwd);
|
|
6745
6929
|
if (!config) {
|
|
6746
|
-
console.error(
|
|
6747
|
-
console.error(
|
|
6930
|
+
console.error(chalk14.red("\u2717 No volume initialized in this directory"));
|
|
6931
|
+
console.error(chalk14.dim(" Run: vm0 volume init"));
|
|
6748
6932
|
process.exit(1);
|
|
6749
6933
|
}
|
|
6750
6934
|
if (versionId) {
|
|
@@ -6752,7 +6936,7 @@ var pullCommand = new Command8().name("pull").description("Pull cloud files to l
|
|
|
6752
6936
|
} else {
|
|
6753
6937
|
console.log(`Pulling volume: ${config.name}`);
|
|
6754
6938
|
}
|
|
6755
|
-
console.log(
|
|
6939
|
+
console.log(chalk14.dim("Getting download URL..."));
|
|
6756
6940
|
const downloadInfo = await getStorageDownload({
|
|
6757
6941
|
name: config.name,
|
|
6758
6942
|
type: "volume",
|
|
@@ -6766,18 +6950,18 @@ var pullCommand = new Command8().name("pull").description("Pull cloud files to l
|
|
|
6766
6950
|
if (!downloadUrl) {
|
|
6767
6951
|
throw new Error("No download URL returned");
|
|
6768
6952
|
}
|
|
6769
|
-
console.log(
|
|
6953
|
+
console.log(chalk14.dim("Downloading from S3..."));
|
|
6770
6954
|
const s3Response = await fetch(downloadUrl);
|
|
6771
6955
|
if (!s3Response.ok) {
|
|
6772
6956
|
throw new Error(`S3 download failed: ${s3Response.status}`);
|
|
6773
6957
|
}
|
|
6774
6958
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
6775
6959
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
6776
|
-
console.log(
|
|
6960
|
+
console.log(chalk14.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
|
|
6777
6961
|
const tmpDir = fs6.mkdtempSync(path7.join(os4.tmpdir(), "vm0-"));
|
|
6778
6962
|
const tarPath = path7.join(tmpDir, "volume.tar.gz");
|
|
6779
6963
|
await fs6.promises.writeFile(tarPath, tarBuffer);
|
|
6780
|
-
console.log(
|
|
6964
|
+
console.log(chalk14.dim("Syncing local files..."));
|
|
6781
6965
|
const remoteFiles = await listTarFiles(tarPath);
|
|
6782
6966
|
const remoteFilesSet = new Set(
|
|
6783
6967
|
remoteFiles.map((f) => f.replace(/\\/g, "/"))
|
|
@@ -6785,10 +6969,10 @@ var pullCommand = new Command8().name("pull").description("Pull cloud files to l
|
|
|
6785
6969
|
const removedCount = await removeExtraFiles(cwd, remoteFilesSet);
|
|
6786
6970
|
if (removedCount > 0) {
|
|
6787
6971
|
console.log(
|
|
6788
|
-
|
|
6972
|
+
chalk14.green(`\u2713 Removed ${removedCount} files not in remote`)
|
|
6789
6973
|
);
|
|
6790
6974
|
}
|
|
6791
|
-
console.log(
|
|
6975
|
+
console.log(chalk14.dim("Extracting files..."));
|
|
6792
6976
|
await tar3.extract({
|
|
6793
6977
|
file: tarPath,
|
|
6794
6978
|
cwd,
|
|
@@ -6796,14 +6980,14 @@ var pullCommand = new Command8().name("pull").description("Pull cloud files to l
|
|
|
6796
6980
|
});
|
|
6797
6981
|
await fs6.promises.unlink(tarPath);
|
|
6798
6982
|
await fs6.promises.rmdir(tmpDir);
|
|
6799
|
-
console.log(
|
|
6983
|
+
console.log(chalk14.green(`\u2713 Extracted ${remoteFiles.length} files`));
|
|
6800
6984
|
} catch (error) {
|
|
6801
|
-
console.error(
|
|
6985
|
+
console.error(chalk14.red("\u2717 Pull failed"));
|
|
6802
6986
|
if (error instanceof Error) {
|
|
6803
6987
|
if (error.message.includes("Not authenticated")) {
|
|
6804
|
-
console.error(
|
|
6988
|
+
console.error(chalk14.dim(" Run: vm0 auth login"));
|
|
6805
6989
|
} else {
|
|
6806
|
-
console.error(
|
|
6990
|
+
console.error(chalk14.dim(` ${error.message}`));
|
|
6807
6991
|
}
|
|
6808
6992
|
}
|
|
6809
6993
|
process.exit(1);
|
|
@@ -6811,24 +6995,24 @@ var pullCommand = new Command8().name("pull").description("Pull cloud files to l
|
|
|
6811
6995
|
});
|
|
6812
6996
|
|
|
6813
6997
|
// src/commands/volume/status.ts
|
|
6814
|
-
import { Command as
|
|
6815
|
-
import
|
|
6816
|
-
var statusCommand = new
|
|
6998
|
+
import { Command as Command11 } from "commander";
|
|
6999
|
+
import chalk15 from "chalk";
|
|
7000
|
+
var statusCommand = new Command11().name("status").description("Show status of cloud volume").action(async () => {
|
|
6817
7001
|
try {
|
|
6818
7002
|
const cwd = process.cwd();
|
|
6819
7003
|
const config = await readStorageConfig(cwd);
|
|
6820
7004
|
if (!config) {
|
|
6821
|
-
console.error(
|
|
6822
|
-
console.error(
|
|
7005
|
+
console.error(chalk15.red("\u2717 No volume initialized in this directory"));
|
|
7006
|
+
console.error(chalk15.dim(" Run: vm0 volume init"));
|
|
6823
7007
|
process.exit(1);
|
|
6824
7008
|
}
|
|
6825
7009
|
if (config.type !== "volume") {
|
|
6826
7010
|
console.error(
|
|
6827
|
-
|
|
7011
|
+
chalk15.red(
|
|
6828
7012
|
"\u2717 This directory is initialized as an artifact, not a volume"
|
|
6829
7013
|
)
|
|
6830
7014
|
);
|
|
6831
|
-
console.error(
|
|
7015
|
+
console.error(chalk15.dim(" Use: vm0 artifact status"));
|
|
6832
7016
|
process.exit(1);
|
|
6833
7017
|
}
|
|
6834
7018
|
console.log(`Checking volume: ${config.name}`);
|
|
@@ -6838,25 +7022,25 @@ var statusCommand = new Command9().name("status").description("Show status of cl
|
|
|
6838
7022
|
});
|
|
6839
7023
|
const shortVersion = info.versionId.slice(0, 8);
|
|
6840
7024
|
if ("empty" in info) {
|
|
6841
|
-
console.log(
|
|
6842
|
-
console.log(
|
|
7025
|
+
console.log(chalk15.green("\u2713 Found (empty)"));
|
|
7026
|
+
console.log(chalk15.dim(` Version: ${shortVersion}`));
|
|
6843
7027
|
} else {
|
|
6844
|
-
console.log(
|
|
6845
|
-
console.log(
|
|
6846
|
-
console.log(
|
|
6847
|
-
console.log(
|
|
7028
|
+
console.log(chalk15.green("\u2713 Found"));
|
|
7029
|
+
console.log(chalk15.dim(` Version: ${shortVersion}`));
|
|
7030
|
+
console.log(chalk15.dim(` Files: ${info.fileCount.toLocaleString()}`));
|
|
7031
|
+
console.log(chalk15.dim(` Size: ${formatBytes(info.size)}`));
|
|
6848
7032
|
}
|
|
6849
7033
|
} catch (error) {
|
|
6850
7034
|
if (error instanceof Error && error.message.includes("not found")) {
|
|
6851
|
-
console.error(
|
|
6852
|
-
console.error(
|
|
7035
|
+
console.error(chalk15.red("\u2717 Not found on remote"));
|
|
7036
|
+
console.error(chalk15.dim(" Run: vm0 volume push"));
|
|
6853
7037
|
} else {
|
|
6854
|
-
console.error(
|
|
7038
|
+
console.error(chalk15.red("\u2717 Status check failed"));
|
|
6855
7039
|
if (error instanceof Error) {
|
|
6856
7040
|
if (error.message.includes("Not authenticated")) {
|
|
6857
|
-
console.error(
|
|
7041
|
+
console.error(chalk15.dim(" Run: vm0 auth login"));
|
|
6858
7042
|
} else {
|
|
6859
|
-
console.error(
|
|
7043
|
+
console.error(chalk15.dim(` ${error.message}`));
|
|
6860
7044
|
}
|
|
6861
7045
|
}
|
|
6862
7046
|
}
|
|
@@ -6865,15 +7049,15 @@ var statusCommand = new Command9().name("status").description("Show status of cl
|
|
|
6865
7049
|
});
|
|
6866
7050
|
|
|
6867
7051
|
// src/commands/volume/list.ts
|
|
6868
|
-
import { Command as
|
|
6869
|
-
import
|
|
6870
|
-
var
|
|
7052
|
+
import { Command as Command12 } from "commander";
|
|
7053
|
+
import chalk16 from "chalk";
|
|
7054
|
+
var listCommand2 = new Command12().name("list").alias("ls").description("List all remote volumes").action(async () => {
|
|
6871
7055
|
try {
|
|
6872
7056
|
const items = await listStorages({ type: "volume" });
|
|
6873
7057
|
if (items.length === 0) {
|
|
6874
|
-
console.log(
|
|
7058
|
+
console.log(chalk16.dim("No volumes found"));
|
|
6875
7059
|
console.log(
|
|
6876
|
-
|
|
7060
|
+
chalk16.dim(" Create one with: vm0 volume init && vm0 volume push")
|
|
6877
7061
|
);
|
|
6878
7062
|
return;
|
|
6879
7063
|
}
|
|
@@ -6892,7 +7076,7 @@ var listCommand = new Command10().name("list").alias("ls").description("List all
|
|
|
6892
7076
|
"FILES".padStart(filesWidth),
|
|
6893
7077
|
"UPDATED"
|
|
6894
7078
|
].join(" ");
|
|
6895
|
-
console.log(
|
|
7079
|
+
console.log(chalk16.dim(header));
|
|
6896
7080
|
for (const item of items) {
|
|
6897
7081
|
const row = [
|
|
6898
7082
|
item.name.padEnd(nameWidth),
|
|
@@ -6903,12 +7087,12 @@ var listCommand = new Command10().name("list").alias("ls").description("List all
|
|
|
6903
7087
|
console.log(row);
|
|
6904
7088
|
}
|
|
6905
7089
|
} catch (error) {
|
|
6906
|
-
console.error(
|
|
7090
|
+
console.error(chalk16.red("\u2717 Failed to list volumes"));
|
|
6907
7091
|
if (error instanceof Error) {
|
|
6908
7092
|
if (error.message.includes("Not authenticated")) {
|
|
6909
|
-
console.error(
|
|
7093
|
+
console.error(chalk16.dim(" Run: vm0 auth login"));
|
|
6910
7094
|
} else {
|
|
6911
|
-
console.error(
|
|
7095
|
+
console.error(chalk16.dim(` ${error.message}`));
|
|
6912
7096
|
}
|
|
6913
7097
|
}
|
|
6914
7098
|
process.exit(1);
|
|
@@ -6916,11 +7100,11 @@ var listCommand = new Command10().name("list").alias("ls").description("List all
|
|
|
6916
7100
|
});
|
|
6917
7101
|
|
|
6918
7102
|
// src/commands/volume/clone.ts
|
|
6919
|
-
import { Command as
|
|
6920
|
-
import
|
|
7103
|
+
import { Command as Command13 } from "commander";
|
|
7104
|
+
import chalk18 from "chalk";
|
|
6921
7105
|
|
|
6922
7106
|
// src/lib/storage/clone-utils.ts
|
|
6923
|
-
import
|
|
7107
|
+
import chalk17 from "chalk";
|
|
6924
7108
|
import path8 from "path";
|
|
6925
7109
|
import * as fs7 from "fs";
|
|
6926
7110
|
import * as os5 from "os";
|
|
@@ -6930,18 +7114,18 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
6930
7114
|
if (fs7.existsSync(destination)) {
|
|
6931
7115
|
throw new Error(`Directory "${destination}" already exists`);
|
|
6932
7116
|
}
|
|
6933
|
-
console.log(
|
|
7117
|
+
console.log(chalk17.dim(`Checking remote ${typeLabel}...`));
|
|
6934
7118
|
const downloadInfo = await getStorageDownload({
|
|
6935
7119
|
name,
|
|
6936
7120
|
type,
|
|
6937
7121
|
version: options.version
|
|
6938
7122
|
});
|
|
6939
|
-
console.log(
|
|
7123
|
+
console.log(chalk17.dim(`Creating directory: ${destination}/`));
|
|
6940
7124
|
await fs7.promises.mkdir(destination, { recursive: true });
|
|
6941
7125
|
if ("empty" in downloadInfo) {
|
|
6942
7126
|
await writeStorageConfig(name, destination, type);
|
|
6943
|
-
console.log(
|
|
6944
|
-
console.log(
|
|
7127
|
+
console.log(chalk17.green(`\u2713 Cloned empty ${typeLabel}: ${name}`));
|
|
7128
|
+
console.log(chalk17.dim(`\u2713 Initialized .vm0/storage.yaml`));
|
|
6945
7129
|
return {
|
|
6946
7130
|
success: true,
|
|
6947
7131
|
fileCount: 0,
|
|
@@ -6953,7 +7137,7 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
6953
7137
|
if (!downloadUrl) {
|
|
6954
7138
|
throw new Error("No download URL returned");
|
|
6955
7139
|
}
|
|
6956
|
-
console.log(
|
|
7140
|
+
console.log(chalk17.dim("Downloading from S3..."));
|
|
6957
7141
|
const s3Response = await fetch(downloadUrl);
|
|
6958
7142
|
if (!s3Response.ok) {
|
|
6959
7143
|
await fs7.promises.rm(destination, { recursive: true, force: true });
|
|
@@ -6961,12 +7145,12 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
6961
7145
|
}
|
|
6962
7146
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
6963
7147
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
6964
|
-
console.log(
|
|
7148
|
+
console.log(chalk17.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
|
|
6965
7149
|
const tmpDir = fs7.mkdtempSync(path8.join(os5.tmpdir(), "vm0-clone-"));
|
|
6966
7150
|
const tarPath = path8.join(tmpDir, "archive.tar.gz");
|
|
6967
7151
|
await fs7.promises.writeFile(tarPath, tarBuffer);
|
|
6968
7152
|
const files = await listTarFiles(tarPath);
|
|
6969
|
-
console.log(
|
|
7153
|
+
console.log(chalk17.dim("Extracting files..."));
|
|
6970
7154
|
await tar4.extract({
|
|
6971
7155
|
file: tarPath,
|
|
6972
7156
|
cwd: destination,
|
|
@@ -6974,9 +7158,9 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
6974
7158
|
});
|
|
6975
7159
|
await fs7.promises.unlink(tarPath);
|
|
6976
7160
|
await fs7.promises.rmdir(tmpDir);
|
|
6977
|
-
console.log(
|
|
7161
|
+
console.log(chalk17.green(`\u2713 Extracted ${files.length} files`));
|
|
6978
7162
|
await writeStorageConfig(name, destination, type);
|
|
6979
|
-
console.log(
|
|
7163
|
+
console.log(chalk17.green(`\u2713 Initialized .vm0/storage.yaml`));
|
|
6980
7164
|
return {
|
|
6981
7165
|
success: true,
|
|
6982
7166
|
fileCount: downloadInfo.fileCount,
|
|
@@ -6986,22 +7170,22 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
6986
7170
|
}
|
|
6987
7171
|
|
|
6988
7172
|
// src/commands/volume/clone.ts
|
|
6989
|
-
var cloneCommand = new
|
|
7173
|
+
var cloneCommand = new Command13().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) => {
|
|
6990
7174
|
try {
|
|
6991
7175
|
const targetDir = destination || name;
|
|
6992
7176
|
console.log(`Cloning volume: ${name}`);
|
|
6993
7177
|
const result = await cloneStorage(name, "volume", targetDir);
|
|
6994
|
-
console.log(
|
|
7178
|
+
console.log(chalk18.green(`
|
|
6995
7179
|
\u2713 Successfully cloned volume: ${name}`));
|
|
6996
|
-
console.log(
|
|
6997
|
-
console.log(
|
|
7180
|
+
console.log(chalk18.dim(` Location: ${targetDir}/`));
|
|
7181
|
+
console.log(chalk18.dim(` Version: ${result.versionId.slice(0, 8)}`));
|
|
6998
7182
|
} catch (error) {
|
|
6999
|
-
console.error(
|
|
7183
|
+
console.error(chalk18.red("\u2717 Clone failed"));
|
|
7000
7184
|
if (error instanceof Error) {
|
|
7001
7185
|
if (error.message.includes("Not authenticated")) {
|
|
7002
|
-
console.error(
|
|
7186
|
+
console.error(chalk18.dim(" Run: vm0 auth login"));
|
|
7003
7187
|
} else {
|
|
7004
|
-
console.error(
|
|
7188
|
+
console.error(chalk18.dim(` ${error.message}`));
|
|
7005
7189
|
}
|
|
7006
7190
|
}
|
|
7007
7191
|
process.exit(1);
|
|
@@ -7009,16 +7193,16 @@ var cloneCommand = new Command11().name("clone").description("Clone a remote vol
|
|
|
7009
7193
|
});
|
|
7010
7194
|
|
|
7011
7195
|
// src/commands/volume/index.ts
|
|
7012
|
-
var volumeCommand = new
|
|
7196
|
+
var volumeCommand = new Command14().name("volume").description("Manage volumes (defined in compose, not versioned after run)").addCommand(initCommand).addCommand(pushCommand).addCommand(pullCommand).addCommand(statusCommand).addCommand(listCommand2).addCommand(cloneCommand);
|
|
7013
7197
|
|
|
7014
7198
|
// src/commands/artifact/index.ts
|
|
7015
|
-
import { Command as
|
|
7199
|
+
import { Command as Command21 } from "commander";
|
|
7016
7200
|
|
|
7017
7201
|
// src/commands/artifact/init.ts
|
|
7018
|
-
import { Command as
|
|
7019
|
-
import
|
|
7202
|
+
import { Command as Command15 } from "commander";
|
|
7203
|
+
import chalk19 from "chalk";
|
|
7020
7204
|
import path9 from "path";
|
|
7021
|
-
var initCommand2 = new
|
|
7205
|
+
var initCommand2 = new Command15().name("init").description("Initialize an artifact in the current directory").option(
|
|
7022
7206
|
"-n, --name <name>",
|
|
7023
7207
|
"Artifact name (required in non-interactive mode)"
|
|
7024
7208
|
).action(async (options) => {
|
|
@@ -7029,24 +7213,24 @@ var initCommand2 = new Command13().name("init").description("Initialize an artif
|
|
|
7029
7213
|
if (existingConfig) {
|
|
7030
7214
|
if (existingConfig.type === "artifact") {
|
|
7031
7215
|
console.log(
|
|
7032
|
-
|
|
7216
|
+
chalk19.yellow(
|
|
7033
7217
|
`Artifact already initialized: ${existingConfig.name}`
|
|
7034
7218
|
)
|
|
7035
7219
|
);
|
|
7036
7220
|
} else {
|
|
7037
7221
|
console.log(
|
|
7038
|
-
|
|
7222
|
+
chalk19.yellow(
|
|
7039
7223
|
`Directory already initialized as volume: ${existingConfig.name}`
|
|
7040
7224
|
)
|
|
7041
7225
|
);
|
|
7042
7226
|
console.log(
|
|
7043
|
-
|
|
7227
|
+
chalk19.dim(
|
|
7044
7228
|
" To change type, delete .vm0/storage.yaml and reinitialize"
|
|
7045
7229
|
)
|
|
7046
7230
|
);
|
|
7047
7231
|
}
|
|
7048
7232
|
console.log(
|
|
7049
|
-
|
|
7233
|
+
chalk19.dim(`Config file: ${path9.join(cwd, ".vm0", "storage.yaml")}`)
|
|
7050
7234
|
);
|
|
7051
7235
|
return;
|
|
7052
7236
|
}
|
|
@@ -7055,10 +7239,10 @@ var initCommand2 = new Command13().name("init").description("Initialize an artif
|
|
|
7055
7239
|
artifactName = options.name;
|
|
7056
7240
|
} else if (!isInteractive()) {
|
|
7057
7241
|
console.error(
|
|
7058
|
-
|
|
7242
|
+
chalk19.red("\u2717 --name flag is required in non-interactive mode")
|
|
7059
7243
|
);
|
|
7060
7244
|
console.error(
|
|
7061
|
-
|
|
7245
|
+
chalk19.dim(" Usage: vm0 artifact init --name <artifact-name>")
|
|
7062
7246
|
);
|
|
7063
7247
|
process.exit(1);
|
|
7064
7248
|
} else {
|
|
@@ -7074,43 +7258,43 @@ var initCommand2 = new Command13().name("init").description("Initialize an artif
|
|
|
7074
7258
|
}
|
|
7075
7259
|
);
|
|
7076
7260
|
if (name === void 0) {
|
|
7077
|
-
console.log(
|
|
7261
|
+
console.log(chalk19.dim("Cancelled"));
|
|
7078
7262
|
return;
|
|
7079
7263
|
}
|
|
7080
7264
|
artifactName = name;
|
|
7081
7265
|
}
|
|
7082
7266
|
if (!isValidStorageName(artifactName)) {
|
|
7083
|
-
console.error(
|
|
7267
|
+
console.error(chalk19.red(`\u2717 Invalid artifact name: "${artifactName}"`));
|
|
7084
7268
|
console.error(
|
|
7085
|
-
|
|
7269
|
+
chalk19.dim(
|
|
7086
7270
|
" Artifact names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
7087
7271
|
)
|
|
7088
7272
|
);
|
|
7089
7273
|
console.error(
|
|
7090
|
-
|
|
7274
|
+
chalk19.dim(" Example: my-project, user-workspace, code-artifact")
|
|
7091
7275
|
);
|
|
7092
7276
|
process.exit(1);
|
|
7093
7277
|
}
|
|
7094
7278
|
await writeStorageConfig(artifactName, cwd, "artifact");
|
|
7095
|
-
console.log(
|
|
7279
|
+
console.log(chalk19.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
7096
7280
|
console.log(
|
|
7097
|
-
|
|
7281
|
+
chalk19.dim(
|
|
7098
7282
|
` Config saved to ${path9.join(cwd, ".vm0", "storage.yaml")}`
|
|
7099
7283
|
)
|
|
7100
7284
|
);
|
|
7101
7285
|
} catch (error) {
|
|
7102
|
-
console.error(
|
|
7286
|
+
console.error(chalk19.red("\u2717 Failed to initialize artifact"));
|
|
7103
7287
|
if (error instanceof Error) {
|
|
7104
|
-
console.error(
|
|
7288
|
+
console.error(chalk19.dim(` ${error.message}`));
|
|
7105
7289
|
}
|
|
7106
7290
|
process.exit(1);
|
|
7107
7291
|
}
|
|
7108
7292
|
});
|
|
7109
7293
|
|
|
7110
7294
|
// src/commands/artifact/push.ts
|
|
7111
|
-
import { Command as
|
|
7112
|
-
import
|
|
7113
|
-
var pushCommand2 = new
|
|
7295
|
+
import { Command as Command16 } from "commander";
|
|
7296
|
+
import chalk20 from "chalk";
|
|
7297
|
+
var pushCommand2 = new Command16().name("push").description("Push local files to cloud artifact").option(
|
|
7114
7298
|
"-f, --force",
|
|
7115
7299
|
"Force upload even if content unchanged (recreate archive)"
|
|
7116
7300
|
).action(async (options) => {
|
|
@@ -7118,69 +7302,69 @@ var pushCommand2 = new Command14().name("push").description("Push local files to
|
|
|
7118
7302
|
const cwd = process.cwd();
|
|
7119
7303
|
const config = await readStorageConfig(cwd);
|
|
7120
7304
|
if (!config) {
|
|
7121
|
-
console.error(
|
|
7122
|
-
console.error(
|
|
7305
|
+
console.error(chalk20.red("\u2717 No artifact initialized in this directory"));
|
|
7306
|
+
console.error(chalk20.dim(" Run: vm0 artifact init"));
|
|
7123
7307
|
process.exit(1);
|
|
7124
7308
|
}
|
|
7125
7309
|
if (config.type !== "artifact") {
|
|
7126
7310
|
console.error(
|
|
7127
|
-
|
|
7311
|
+
chalk20.red(
|
|
7128
7312
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
7129
7313
|
)
|
|
7130
7314
|
);
|
|
7131
|
-
console.error(
|
|
7315
|
+
console.error(chalk20.dim(" Use: vm0 volume push"));
|
|
7132
7316
|
process.exit(1);
|
|
7133
7317
|
}
|
|
7134
7318
|
console.log(`Pushing artifact: ${config.name}`);
|
|
7135
7319
|
const result = await directUpload(config.name, "artifact", cwd, {
|
|
7136
7320
|
onProgress: (message) => {
|
|
7137
|
-
console.log(
|
|
7321
|
+
console.log(chalk20.dim(message));
|
|
7138
7322
|
},
|
|
7139
7323
|
force: options.force
|
|
7140
7324
|
});
|
|
7141
7325
|
const shortVersion = result.versionId.slice(0, 8);
|
|
7142
7326
|
if (result.empty) {
|
|
7143
|
-
console.log(
|
|
7327
|
+
console.log(chalk20.dim("No files found (empty artifact)"));
|
|
7144
7328
|
} else if (result.deduplicated) {
|
|
7145
|
-
console.log(
|
|
7329
|
+
console.log(chalk20.green("\u2713 Content unchanged (deduplicated)"));
|
|
7146
7330
|
} else {
|
|
7147
|
-
console.log(
|
|
7331
|
+
console.log(chalk20.green("\u2713 Upload complete"));
|
|
7148
7332
|
}
|
|
7149
|
-
console.log(
|
|
7150
|
-
console.log(
|
|
7151
|
-
console.log(
|
|
7333
|
+
console.log(chalk20.dim(` Version: ${shortVersion}`));
|
|
7334
|
+
console.log(chalk20.dim(` Files: ${result.fileCount.toLocaleString()}`));
|
|
7335
|
+
console.log(chalk20.dim(` Size: ${formatBytes(result.size)}`));
|
|
7152
7336
|
} catch (error) {
|
|
7153
|
-
console.error(
|
|
7337
|
+
console.error(chalk20.red("\u2717 Push failed"));
|
|
7154
7338
|
if (error instanceof Error) {
|
|
7155
|
-
console.error(
|
|
7339
|
+
console.error(chalk20.dim(` ${error.message}`));
|
|
7156
7340
|
}
|
|
7157
7341
|
process.exit(1);
|
|
7158
7342
|
}
|
|
7159
7343
|
});
|
|
7160
7344
|
|
|
7161
7345
|
// src/commands/artifact/pull.ts
|
|
7162
|
-
import { Command as
|
|
7163
|
-
import
|
|
7346
|
+
import { Command as Command17 } from "commander";
|
|
7347
|
+
import chalk21 from "chalk";
|
|
7164
7348
|
import path10 from "path";
|
|
7165
7349
|
import * as fs8 from "fs";
|
|
7166
7350
|
import * as os6 from "os";
|
|
7167
7351
|
import * as tar5 from "tar";
|
|
7168
|
-
var pullCommand2 = new
|
|
7352
|
+
var pullCommand2 = new Command17().name("pull").description("Pull cloud artifact to local directory").argument("[versionId]", "Version ID to pull (default: latest)").action(async (versionId) => {
|
|
7169
7353
|
try {
|
|
7170
7354
|
const cwd = process.cwd();
|
|
7171
7355
|
const config = await readStorageConfig(cwd);
|
|
7172
7356
|
if (!config) {
|
|
7173
|
-
console.error(
|
|
7174
|
-
console.error(
|
|
7357
|
+
console.error(chalk21.red("\u2717 No artifact initialized in this directory"));
|
|
7358
|
+
console.error(chalk21.dim(" Run: vm0 artifact init"));
|
|
7175
7359
|
process.exit(1);
|
|
7176
7360
|
}
|
|
7177
7361
|
if (config.type !== "artifact") {
|
|
7178
7362
|
console.error(
|
|
7179
|
-
|
|
7363
|
+
chalk21.red(
|
|
7180
7364
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
7181
7365
|
)
|
|
7182
7366
|
);
|
|
7183
|
-
console.error(
|
|
7367
|
+
console.error(chalk21.dim(" Use: vm0 volume pull"));
|
|
7184
7368
|
process.exit(1);
|
|
7185
7369
|
}
|
|
7186
7370
|
if (versionId) {
|
|
@@ -7188,7 +7372,7 @@ var pullCommand2 = new Command15().name("pull").description("Pull cloud artifact
|
|
|
7188
7372
|
} else {
|
|
7189
7373
|
console.log(`Pulling artifact: ${config.name}`);
|
|
7190
7374
|
}
|
|
7191
|
-
console.log(
|
|
7375
|
+
console.log(chalk21.dim("Getting download URL..."));
|
|
7192
7376
|
const downloadInfo = await getStorageDownload({
|
|
7193
7377
|
name: config.name,
|
|
7194
7378
|
type: "artifact",
|
|
@@ -7202,18 +7386,18 @@ var pullCommand2 = new Command15().name("pull").description("Pull cloud artifact
|
|
|
7202
7386
|
if (!downloadUrl) {
|
|
7203
7387
|
throw new Error("No download URL returned");
|
|
7204
7388
|
}
|
|
7205
|
-
console.log(
|
|
7389
|
+
console.log(chalk21.dim("Downloading from S3..."));
|
|
7206
7390
|
const s3Response = await fetch(downloadUrl);
|
|
7207
7391
|
if (!s3Response.ok) {
|
|
7208
7392
|
throw new Error(`S3 download failed: ${s3Response.status}`);
|
|
7209
7393
|
}
|
|
7210
7394
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
7211
7395
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
7212
|
-
console.log(
|
|
7396
|
+
console.log(chalk21.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
|
|
7213
7397
|
const tmpDir = fs8.mkdtempSync(path10.join(os6.tmpdir(), "vm0-"));
|
|
7214
7398
|
const tarPath = path10.join(tmpDir, "artifact.tar.gz");
|
|
7215
7399
|
await fs8.promises.writeFile(tarPath, tarBuffer);
|
|
7216
|
-
console.log(
|
|
7400
|
+
console.log(chalk21.dim("Syncing local files..."));
|
|
7217
7401
|
const remoteFiles = await listTarFiles(tarPath);
|
|
7218
7402
|
const remoteFilesSet = new Set(
|
|
7219
7403
|
remoteFiles.map((f) => f.replace(/\\/g, "/"))
|
|
@@ -7221,10 +7405,10 @@ var pullCommand2 = new Command15().name("pull").description("Pull cloud artifact
|
|
|
7221
7405
|
const removedCount = await removeExtraFiles(cwd, remoteFilesSet);
|
|
7222
7406
|
if (removedCount > 0) {
|
|
7223
7407
|
console.log(
|
|
7224
|
-
|
|
7408
|
+
chalk21.green(`\u2713 Removed ${removedCount} files not in remote`)
|
|
7225
7409
|
);
|
|
7226
7410
|
}
|
|
7227
|
-
console.log(
|
|
7411
|
+
console.log(chalk21.dim("Extracting files..."));
|
|
7228
7412
|
await tar5.extract({
|
|
7229
7413
|
file: tarPath,
|
|
7230
7414
|
cwd,
|
|
@@ -7232,35 +7416,35 @@ var pullCommand2 = new Command15().name("pull").description("Pull cloud artifact
|
|
|
7232
7416
|
});
|
|
7233
7417
|
await fs8.promises.unlink(tarPath);
|
|
7234
7418
|
await fs8.promises.rmdir(tmpDir);
|
|
7235
|
-
console.log(
|
|
7419
|
+
console.log(chalk21.green(`\u2713 Extracted ${remoteFiles.length} files`));
|
|
7236
7420
|
} catch (error) {
|
|
7237
|
-
console.error(
|
|
7421
|
+
console.error(chalk21.red("\u2717 Pull failed"));
|
|
7238
7422
|
if (error instanceof Error) {
|
|
7239
|
-
console.error(
|
|
7423
|
+
console.error(chalk21.dim(` ${error.message}`));
|
|
7240
7424
|
}
|
|
7241
7425
|
process.exit(1);
|
|
7242
7426
|
}
|
|
7243
7427
|
});
|
|
7244
7428
|
|
|
7245
7429
|
// src/commands/artifact/status.ts
|
|
7246
|
-
import { Command as
|
|
7247
|
-
import
|
|
7248
|
-
var statusCommand2 = new
|
|
7430
|
+
import { Command as Command18 } from "commander";
|
|
7431
|
+
import chalk22 from "chalk";
|
|
7432
|
+
var statusCommand2 = new Command18().name("status").description("Show status of cloud artifact").action(async () => {
|
|
7249
7433
|
try {
|
|
7250
7434
|
const cwd = process.cwd();
|
|
7251
7435
|
const config = await readStorageConfig(cwd);
|
|
7252
7436
|
if (!config) {
|
|
7253
|
-
console.error(
|
|
7254
|
-
console.error(
|
|
7437
|
+
console.error(chalk22.red("\u2717 No artifact initialized in this directory"));
|
|
7438
|
+
console.error(chalk22.dim(" Run: vm0 artifact init"));
|
|
7255
7439
|
process.exit(1);
|
|
7256
7440
|
}
|
|
7257
7441
|
if (config.type !== "artifact") {
|
|
7258
7442
|
console.error(
|
|
7259
|
-
|
|
7443
|
+
chalk22.red(
|
|
7260
7444
|
"\u2717 This directory is initialized as a volume, not an artifact"
|
|
7261
7445
|
)
|
|
7262
7446
|
);
|
|
7263
|
-
console.error(
|
|
7447
|
+
console.error(chalk22.dim(" Use: vm0 volume status"));
|
|
7264
7448
|
process.exit(1);
|
|
7265
7449
|
}
|
|
7266
7450
|
console.log(`Checking artifact: ${config.name}`);
|
|
@@ -7270,22 +7454,22 @@ var statusCommand2 = new Command16().name("status").description("Show status of
|
|
|
7270
7454
|
});
|
|
7271
7455
|
const shortVersion = info.versionId.slice(0, 8);
|
|
7272
7456
|
if ("empty" in info) {
|
|
7273
|
-
console.log(
|
|
7274
|
-
console.log(
|
|
7457
|
+
console.log(chalk22.green("\u2713 Found (empty)"));
|
|
7458
|
+
console.log(chalk22.dim(` Version: ${shortVersion}`));
|
|
7275
7459
|
} else {
|
|
7276
|
-
console.log(
|
|
7277
|
-
console.log(
|
|
7278
|
-
console.log(
|
|
7279
|
-
console.log(
|
|
7460
|
+
console.log(chalk22.green("\u2713 Found"));
|
|
7461
|
+
console.log(chalk22.dim(` Version: ${shortVersion}`));
|
|
7462
|
+
console.log(chalk22.dim(` Files: ${info.fileCount.toLocaleString()}`));
|
|
7463
|
+
console.log(chalk22.dim(` Size: ${formatBytes(info.size)}`));
|
|
7280
7464
|
}
|
|
7281
7465
|
} catch (error) {
|
|
7282
7466
|
if (error instanceof Error && error.message.includes("not found")) {
|
|
7283
|
-
console.error(
|
|
7284
|
-
console.error(
|
|
7467
|
+
console.error(chalk22.red("\u2717 Not found on remote"));
|
|
7468
|
+
console.error(chalk22.dim(" Run: vm0 artifact push"));
|
|
7285
7469
|
} else {
|
|
7286
|
-
console.error(
|
|
7470
|
+
console.error(chalk22.red("\u2717 Status check failed"));
|
|
7287
7471
|
if (error instanceof Error) {
|
|
7288
|
-
console.error(
|
|
7472
|
+
console.error(chalk22.dim(` ${error.message}`));
|
|
7289
7473
|
}
|
|
7290
7474
|
}
|
|
7291
7475
|
process.exit(1);
|
|
@@ -7293,15 +7477,15 @@ var statusCommand2 = new Command16().name("status").description("Show status of
|
|
|
7293
7477
|
});
|
|
7294
7478
|
|
|
7295
7479
|
// src/commands/artifact/list.ts
|
|
7296
|
-
import { Command as
|
|
7297
|
-
import
|
|
7298
|
-
var
|
|
7480
|
+
import { Command as Command19 } from "commander";
|
|
7481
|
+
import chalk23 from "chalk";
|
|
7482
|
+
var listCommand3 = new Command19().name("list").alias("ls").description("List all remote artifacts").action(async () => {
|
|
7299
7483
|
try {
|
|
7300
7484
|
const items = await listStorages({ type: "artifact" });
|
|
7301
7485
|
if (items.length === 0) {
|
|
7302
|
-
console.log(
|
|
7486
|
+
console.log(chalk23.dim("No artifacts found"));
|
|
7303
7487
|
console.log(
|
|
7304
|
-
|
|
7488
|
+
chalk23.dim(
|
|
7305
7489
|
" Create one with: vm0 artifact init && vm0 artifact push"
|
|
7306
7490
|
)
|
|
7307
7491
|
);
|
|
@@ -7322,7 +7506,7 @@ var listCommand2 = new Command17().name("list").alias("ls").description("List al
|
|
|
7322
7506
|
"FILES".padStart(filesWidth),
|
|
7323
7507
|
"UPDATED"
|
|
7324
7508
|
].join(" ");
|
|
7325
|
-
console.log(
|
|
7509
|
+
console.log(chalk23.dim(header));
|
|
7326
7510
|
for (const item of items) {
|
|
7327
7511
|
const row = [
|
|
7328
7512
|
item.name.padEnd(nameWidth),
|
|
@@ -7333,12 +7517,12 @@ var listCommand2 = new Command17().name("list").alias("ls").description("List al
|
|
|
7333
7517
|
console.log(row);
|
|
7334
7518
|
}
|
|
7335
7519
|
} catch (error) {
|
|
7336
|
-
console.error(
|
|
7520
|
+
console.error(chalk23.red("\u2717 Failed to list artifacts"));
|
|
7337
7521
|
if (error instanceof Error) {
|
|
7338
7522
|
if (error.message.includes("Not authenticated")) {
|
|
7339
|
-
console.error(
|
|
7523
|
+
console.error(chalk23.dim(" Run: vm0 auth login"));
|
|
7340
7524
|
} else {
|
|
7341
|
-
console.error(
|
|
7525
|
+
console.error(chalk23.dim(` ${error.message}`));
|
|
7342
7526
|
}
|
|
7343
7527
|
}
|
|
7344
7528
|
process.exit(1);
|
|
@@ -7346,24 +7530,24 @@ var listCommand2 = new Command17().name("list").alias("ls").description("List al
|
|
|
7346
7530
|
});
|
|
7347
7531
|
|
|
7348
7532
|
// src/commands/artifact/clone.ts
|
|
7349
|
-
import { Command as
|
|
7350
|
-
import
|
|
7351
|
-
var cloneCommand2 = new
|
|
7533
|
+
import { Command as Command20 } from "commander";
|
|
7534
|
+
import chalk24 from "chalk";
|
|
7535
|
+
var cloneCommand2 = new Command20().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) => {
|
|
7352
7536
|
try {
|
|
7353
7537
|
const targetDir = destination || name;
|
|
7354
7538
|
console.log(`Cloning artifact: ${name}`);
|
|
7355
7539
|
const result = await cloneStorage(name, "artifact", targetDir);
|
|
7356
|
-
console.log(
|
|
7540
|
+
console.log(chalk24.green(`
|
|
7357
7541
|
\u2713 Successfully cloned artifact: ${name}`));
|
|
7358
|
-
console.log(
|
|
7359
|
-
console.log(
|
|
7542
|
+
console.log(chalk24.dim(` Location: ${targetDir}/`));
|
|
7543
|
+
console.log(chalk24.dim(` Version: ${result.versionId.slice(0, 8)}`));
|
|
7360
7544
|
} catch (error) {
|
|
7361
|
-
console.error(
|
|
7545
|
+
console.error(chalk24.red("\u2717 Clone failed"));
|
|
7362
7546
|
if (error instanceof Error) {
|
|
7363
7547
|
if (error.message.includes("Not authenticated")) {
|
|
7364
|
-
console.error(
|
|
7548
|
+
console.error(chalk24.dim(" Run: vm0 auth login"));
|
|
7365
7549
|
} else {
|
|
7366
|
-
console.error(
|
|
7550
|
+
console.error(chalk24.dim(` ${error.message}`));
|
|
7367
7551
|
}
|
|
7368
7552
|
}
|
|
7369
7553
|
process.exit(1);
|
|
@@ -7371,11 +7555,11 @@ var cloneCommand2 = new Command18().name("clone").description("Clone a remote ar
|
|
|
7371
7555
|
});
|
|
7372
7556
|
|
|
7373
7557
|
// src/commands/artifact/index.ts
|
|
7374
|
-
var artifactCommand = new
|
|
7558
|
+
var artifactCommand = new Command21().name("artifact").description("Manage artifacts (specified at run, versioned after run)").addCommand(initCommand2).addCommand(pushCommand2).addCommand(pullCommand2).addCommand(statusCommand2).addCommand(listCommand3).addCommand(cloneCommand2);
|
|
7375
7559
|
|
|
7376
7560
|
// src/commands/cook.ts
|
|
7377
|
-
import { Command as
|
|
7378
|
-
import
|
|
7561
|
+
import { Command as Command22, Option as Option4 } from "commander";
|
|
7562
|
+
import chalk26 from "chalk";
|
|
7379
7563
|
import { readFile as readFile7, mkdir as mkdir6 } from "fs/promises";
|
|
7380
7564
|
import { existsSync as existsSync8 } from "fs";
|
|
7381
7565
|
import path11 from "path";
|
|
@@ -7385,7 +7569,7 @@ import { config as dotenvConfig2 } from "dotenv";
|
|
|
7385
7569
|
|
|
7386
7570
|
// src/lib/utils/update-checker.ts
|
|
7387
7571
|
import { spawn } from "child_process";
|
|
7388
|
-
import
|
|
7572
|
+
import chalk25 from "chalk";
|
|
7389
7573
|
var PACKAGE_NAME = "@vm0/cli";
|
|
7390
7574
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`;
|
|
7391
7575
|
var TIMEOUT_MS = 5e3;
|
|
@@ -7469,21 +7653,21 @@ function performUpgrade(packageManager) {
|
|
|
7469
7653
|
async function checkAndUpgrade(currentVersion, prompt) {
|
|
7470
7654
|
const latestVersion = await getLatestVersion();
|
|
7471
7655
|
if (latestVersion === null) {
|
|
7472
|
-
console.log(
|
|
7656
|
+
console.log(chalk25.yellow("Warning: Could not check for updates"));
|
|
7473
7657
|
console.log();
|
|
7474
7658
|
return false;
|
|
7475
7659
|
}
|
|
7476
7660
|
if (latestVersion === currentVersion) {
|
|
7477
7661
|
return false;
|
|
7478
7662
|
}
|
|
7479
|
-
console.log(
|
|
7663
|
+
console.log(chalk25.yellow("vm0 is currently in Early Access (EA)."));
|
|
7480
7664
|
console.log(
|
|
7481
|
-
|
|
7665
|
+
chalk25.yellow(
|
|
7482
7666
|
`Current version: ${currentVersion} -> Latest version: ${latestVersion}`
|
|
7483
7667
|
)
|
|
7484
7668
|
);
|
|
7485
7669
|
console.log(
|
|
7486
|
-
|
|
7670
|
+
chalk25.yellow(
|
|
7487
7671
|
"Please always use the latest version for best compatibility."
|
|
7488
7672
|
)
|
|
7489
7673
|
);
|
|
@@ -7492,33 +7676,33 @@ async function checkAndUpgrade(currentVersion, prompt) {
|
|
|
7492
7676
|
if (!isAutoUpgradeSupported(packageManager)) {
|
|
7493
7677
|
if (packageManager === "unknown") {
|
|
7494
7678
|
console.log(
|
|
7495
|
-
|
|
7679
|
+
chalk25.yellow("Could not detect your package manager for auto-upgrade.")
|
|
7496
7680
|
);
|
|
7497
7681
|
} else {
|
|
7498
7682
|
console.log(
|
|
7499
|
-
|
|
7683
|
+
chalk25.yellow(`Auto-upgrade is not supported for ${packageManager}.`)
|
|
7500
7684
|
);
|
|
7501
7685
|
}
|
|
7502
|
-
console.log(
|
|
7503
|
-
console.log(
|
|
7686
|
+
console.log(chalk25.yellow("Please upgrade manually:"));
|
|
7687
|
+
console.log(chalk25.cyan(` ${getManualUpgradeCommand(packageManager)}`));
|
|
7504
7688
|
console.log();
|
|
7505
7689
|
return false;
|
|
7506
7690
|
}
|
|
7507
7691
|
console.log(`Upgrading via ${packageManager}...`);
|
|
7508
7692
|
const success = await performUpgrade(packageManager);
|
|
7509
7693
|
if (success) {
|
|
7510
|
-
console.log(
|
|
7694
|
+
console.log(chalk25.green(`Upgraded to ${latestVersion}`));
|
|
7511
7695
|
console.log();
|
|
7512
7696
|
console.log("To continue, run:");
|
|
7513
|
-
console.log(
|
|
7697
|
+
console.log(chalk25.cyan(` ${buildRerunCommand(prompt)}`));
|
|
7514
7698
|
return true;
|
|
7515
7699
|
}
|
|
7516
7700
|
console.log();
|
|
7517
|
-
console.log(
|
|
7518
|
-
console.log(
|
|
7701
|
+
console.log(chalk25.red("Upgrade failed. Please run manually:"));
|
|
7702
|
+
console.log(chalk25.cyan(` ${getManualUpgradeCommand(packageManager)}`));
|
|
7519
7703
|
console.log();
|
|
7520
7704
|
console.log("Then re-run:");
|
|
7521
|
-
console.log(
|
|
7705
|
+
console.log(chalk25.cyan(` ${buildRerunCommand(prompt)}`));
|
|
7522
7706
|
return true;
|
|
7523
7707
|
}
|
|
7524
7708
|
|
|
@@ -7591,7 +7775,7 @@ async function saveCookState(state) {
|
|
|
7591
7775
|
var CONFIG_FILE2 = "vm0.yaml";
|
|
7592
7776
|
var ARTIFACT_DIR = "artifact";
|
|
7593
7777
|
function printCommand(cmd) {
|
|
7594
|
-
console.log(
|
|
7778
|
+
console.log(chalk26.dim(`> ${cmd}`));
|
|
7595
7779
|
}
|
|
7596
7780
|
function execVm0Command(args, options = {}) {
|
|
7597
7781
|
return new Promise((resolve, reject) => {
|
|
@@ -7718,7 +7902,7 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
7718
7902
|
);
|
|
7719
7903
|
if (serverVersion && existsSync8(artifactDir)) {
|
|
7720
7904
|
console.log();
|
|
7721
|
-
console.log(
|
|
7905
|
+
console.log(chalk26.bold("Pulling updated artifact:"));
|
|
7722
7906
|
printCommand(`cd ${ARTIFACT_DIR}`);
|
|
7723
7907
|
printCommand(`vm0 artifact pull ${serverVersion}`);
|
|
7724
7908
|
try {
|
|
@@ -7728,14 +7912,14 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
7728
7912
|
});
|
|
7729
7913
|
printCommand("cd ..");
|
|
7730
7914
|
} catch (error) {
|
|
7731
|
-
console.error(
|
|
7915
|
+
console.error(chalk26.red(`\u2717 Artifact pull failed`));
|
|
7732
7916
|
if (error instanceof Error) {
|
|
7733
|
-
console.error(
|
|
7917
|
+
console.error(chalk26.dim(` ${error.message}`));
|
|
7734
7918
|
}
|
|
7735
7919
|
}
|
|
7736
7920
|
}
|
|
7737
7921
|
}
|
|
7738
|
-
var cookCmd = new
|
|
7922
|
+
var cookCmd = new Command22().name("cook").description("Quick start: prepare, compose and run agent from vm0.yaml");
|
|
7739
7923
|
cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
7740
7924
|
"--env-file <path>",
|
|
7741
7925
|
"Load environment variables from file (priority: CLI flags > file > env vars)"
|
|
@@ -7743,15 +7927,15 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
|
7743
7927
|
// eslint-disable-next-line complexity -- TODO: refactor complex function
|
|
7744
7928
|
async (prompt, options) => {
|
|
7745
7929
|
if (!options.noAutoUpdate) {
|
|
7746
|
-
const shouldExit = await checkAndUpgrade("9.
|
|
7930
|
+
const shouldExit = await checkAndUpgrade("9.4.0", prompt);
|
|
7747
7931
|
if (shouldExit) {
|
|
7748
7932
|
process.exit(0);
|
|
7749
7933
|
}
|
|
7750
7934
|
}
|
|
7751
7935
|
const cwd = process.cwd();
|
|
7752
|
-
console.log(
|
|
7936
|
+
console.log(chalk26.bold(`Reading config: ${CONFIG_FILE2}`));
|
|
7753
7937
|
if (!existsSync8(CONFIG_FILE2)) {
|
|
7754
|
-
console.error(
|
|
7938
|
+
console.error(chalk26.red(`\u2717 Config file not found: ${CONFIG_FILE2}`));
|
|
7755
7939
|
process.exit(1);
|
|
7756
7940
|
}
|
|
7757
7941
|
let config;
|
|
@@ -7759,22 +7943,22 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
|
7759
7943
|
const content = await readFile7(CONFIG_FILE2, "utf8");
|
|
7760
7944
|
config = parseYaml4(content);
|
|
7761
7945
|
} catch (error) {
|
|
7762
|
-
console.error(
|
|
7946
|
+
console.error(chalk26.red("\u2717 Invalid YAML format"));
|
|
7763
7947
|
if (error instanceof Error) {
|
|
7764
|
-
console.error(
|
|
7948
|
+
console.error(chalk26.dim(` ${error.message}`));
|
|
7765
7949
|
}
|
|
7766
7950
|
process.exit(1);
|
|
7767
7951
|
}
|
|
7768
7952
|
const validation = validateAgentCompose(config);
|
|
7769
7953
|
if (!validation.valid) {
|
|
7770
|
-
console.error(
|
|
7954
|
+
console.error(chalk26.red(`\u2717 ${validation.error}`));
|
|
7771
7955
|
process.exit(1);
|
|
7772
7956
|
}
|
|
7773
7957
|
const agentNames = Object.keys(config.agents);
|
|
7774
7958
|
const agentName = agentNames[0];
|
|
7775
7959
|
const volumeCount = config.volumes ? Object.keys(config.volumes).length : 0;
|
|
7776
7960
|
console.log(
|
|
7777
|
-
|
|
7961
|
+
chalk26.green(`\u2713 Config validated: 1 agent, ${volumeCount} volume(s)`)
|
|
7778
7962
|
);
|
|
7779
7963
|
const requiredVarNames = extractRequiredVarNames(config);
|
|
7780
7964
|
if (requiredVarNames.length > 0) {
|
|
@@ -7785,12 +7969,12 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
|
7785
7969
|
);
|
|
7786
7970
|
if (missingVars.length > 0) {
|
|
7787
7971
|
console.log();
|
|
7788
|
-
console.error(
|
|
7972
|
+
console.error(chalk26.red("\u2717 Missing required variables:"));
|
|
7789
7973
|
for (const varName of missingVars) {
|
|
7790
|
-
console.error(
|
|
7974
|
+
console.error(chalk26.red(` ${varName}`));
|
|
7791
7975
|
}
|
|
7792
7976
|
console.error(
|
|
7793
|
-
|
|
7977
|
+
chalk26.dim(
|
|
7794
7978
|
"\n Provide via --env-file, or set as environment variables"
|
|
7795
7979
|
)
|
|
7796
7980
|
);
|
|
@@ -7798,22 +7982,22 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
|
7798
7982
|
}
|
|
7799
7983
|
} catch (error) {
|
|
7800
7984
|
if (error instanceof Error) {
|
|
7801
|
-
console.error(
|
|
7985
|
+
console.error(chalk26.red(`\u2717 ${error.message}`));
|
|
7802
7986
|
}
|
|
7803
7987
|
process.exit(1);
|
|
7804
7988
|
}
|
|
7805
7989
|
}
|
|
7806
7990
|
if (config.volumes && Object.keys(config.volumes).length > 0) {
|
|
7807
7991
|
console.log();
|
|
7808
|
-
console.log(
|
|
7992
|
+
console.log(chalk26.bold("Processing volumes:"));
|
|
7809
7993
|
for (const volumeConfig of Object.values(config.volumes)) {
|
|
7810
7994
|
const volumeDir = path11.join(cwd, volumeConfig.name);
|
|
7811
7995
|
if (!existsSync8(volumeDir)) {
|
|
7812
7996
|
console.error(
|
|
7813
|
-
|
|
7997
|
+
chalk26.red(`\u2717 Directory not found: ${volumeConfig.name}`)
|
|
7814
7998
|
);
|
|
7815
7999
|
console.error(
|
|
7816
|
-
|
|
8000
|
+
chalk26.dim(" Create the directory and add files first")
|
|
7817
8001
|
);
|
|
7818
8002
|
process.exit(1);
|
|
7819
8003
|
}
|
|
@@ -7837,16 +8021,16 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
|
7837
8021
|
});
|
|
7838
8022
|
printCommand("cd ..");
|
|
7839
8023
|
} catch (error) {
|
|
7840
|
-
console.error(
|
|
8024
|
+
console.error(chalk26.red(`\u2717 Failed`));
|
|
7841
8025
|
if (error instanceof Error) {
|
|
7842
|
-
console.error(
|
|
8026
|
+
console.error(chalk26.dim(` ${error.message}`));
|
|
7843
8027
|
}
|
|
7844
8028
|
process.exit(1);
|
|
7845
8029
|
}
|
|
7846
8030
|
}
|
|
7847
8031
|
}
|
|
7848
8032
|
console.log();
|
|
7849
|
-
console.log(
|
|
8033
|
+
console.log(chalk26.bold("Processing artifact:"));
|
|
7850
8034
|
const artifactDir = path11.join(cwd, ARTIFACT_DIR);
|
|
7851
8035
|
try {
|
|
7852
8036
|
if (!existsSync8(artifactDir)) {
|
|
@@ -7869,14 +8053,14 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
|
7869
8053
|
});
|
|
7870
8054
|
printCommand("cd ..");
|
|
7871
8055
|
} catch (error) {
|
|
7872
|
-
console.error(
|
|
8056
|
+
console.error(chalk26.red(`\u2717 Failed`));
|
|
7873
8057
|
if (error instanceof Error) {
|
|
7874
|
-
console.error(
|
|
8058
|
+
console.error(chalk26.dim(` ${error.message}`));
|
|
7875
8059
|
}
|
|
7876
8060
|
process.exit(1);
|
|
7877
8061
|
}
|
|
7878
8062
|
console.log();
|
|
7879
|
-
console.log(
|
|
8063
|
+
console.log(chalk26.bold("Composing agent:"));
|
|
7880
8064
|
const composeArgs = options.yes ? ["compose", "--yes", CONFIG_FILE2] : ["compose", CONFIG_FILE2];
|
|
7881
8065
|
printCommand(`vm0 ${composeArgs.join(" ")}`);
|
|
7882
8066
|
try {
|
|
@@ -7884,15 +8068,15 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
|
7884
8068
|
cwd
|
|
7885
8069
|
});
|
|
7886
8070
|
} catch (error) {
|
|
7887
|
-
console.error(
|
|
8071
|
+
console.error(chalk26.red(`\u2717 Compose failed`));
|
|
7888
8072
|
if (error instanceof Error) {
|
|
7889
|
-
console.error(
|
|
8073
|
+
console.error(chalk26.dim(` ${error.message}`));
|
|
7890
8074
|
}
|
|
7891
8075
|
process.exit(1);
|
|
7892
8076
|
}
|
|
7893
8077
|
if (prompt) {
|
|
7894
8078
|
console.log();
|
|
7895
|
-
console.log(
|
|
8079
|
+
console.log(chalk26.bold("Running agent:"));
|
|
7896
8080
|
printCommand(
|
|
7897
8081
|
`vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "${prompt}"`
|
|
7898
8082
|
);
|
|
@@ -7936,8 +8120,8 @@ cookCmd.command("logs").description("View logs from the last cook run").option("
|
|
|
7936
8120
|
async (options) => {
|
|
7937
8121
|
const state = await loadCookState();
|
|
7938
8122
|
if (!state.lastRunId) {
|
|
7939
|
-
console.error(
|
|
7940
|
-
console.error(
|
|
8123
|
+
console.error(chalk26.red("\u2717 No previous run found"));
|
|
8124
|
+
console.error(chalk26.dim(" Run 'vm0 cook <prompt>' first"));
|
|
7941
8125
|
process.exit(1);
|
|
7942
8126
|
}
|
|
7943
8127
|
const args = ["logs", state.lastRunId];
|
|
@@ -7983,8 +8167,8 @@ cookCmd.command("continue").description(
|
|
|
7983
8167
|
async (prompt, options) => {
|
|
7984
8168
|
const state = await loadCookState();
|
|
7985
8169
|
if (!state.lastSessionId) {
|
|
7986
|
-
console.error(
|
|
7987
|
-
console.error(
|
|
8170
|
+
console.error(chalk26.red("\u2717 No previous session found"));
|
|
8171
|
+
console.error(chalk26.dim(" Run 'vm0 cook <prompt>' first"));
|
|
7988
8172
|
process.exit(1);
|
|
7989
8173
|
}
|
|
7990
8174
|
const cwd = process.cwd();
|
|
@@ -8030,8 +8214,8 @@ cookCmd.command("resume").description(
|
|
|
8030
8214
|
async (prompt, options) => {
|
|
8031
8215
|
const state = await loadCookState();
|
|
8032
8216
|
if (!state.lastCheckpointId) {
|
|
8033
|
-
console.error(
|
|
8034
|
-
console.error(
|
|
8217
|
+
console.error(chalk26.red("\u2717 No previous checkpoint found"));
|
|
8218
|
+
console.error(chalk26.dim(" Run 'vm0 cook <prompt>' first"));
|
|
8035
8219
|
process.exit(1);
|
|
8036
8220
|
}
|
|
8037
8221
|
const cwd = process.cwd();
|
|
@@ -8071,8 +8255,8 @@ cookCmd.command("resume").description(
|
|
|
8071
8255
|
var cookCommand = cookCmd;
|
|
8072
8256
|
|
|
8073
8257
|
// src/commands/logs/index.ts
|
|
8074
|
-
import { Command as
|
|
8075
|
-
import
|
|
8258
|
+
import { Command as Command23 } from "commander";
|
|
8259
|
+
import chalk27 from "chalk";
|
|
8076
8260
|
|
|
8077
8261
|
// src/lib/utils/time-parser.ts
|
|
8078
8262
|
function parseTime(timeStr) {
|
|
@@ -8126,36 +8310,36 @@ function formatMetric(metric) {
|
|
|
8126
8310
|
}
|
|
8127
8311
|
function formatNetworkLog(entry) {
|
|
8128
8312
|
if (entry.mode === "sni" || !entry.method) {
|
|
8129
|
-
const actionColor = entry.action === "ALLOW" ?
|
|
8313
|
+
const actionColor = entry.action === "ALLOW" ? chalk27.green : chalk27.red;
|
|
8130
8314
|
const host = entry.host || "unknown";
|
|
8131
8315
|
const port = entry.port || 443;
|
|
8132
|
-
return `[${entry.timestamp}] ${
|
|
8316
|
+
return `[${entry.timestamp}] ${chalk27.cyan("SNI")} ${actionColor(entry.action || "ALLOW")} ${host}:${port} ${chalk27.dim(entry.rule_matched || "")}`;
|
|
8133
8317
|
}
|
|
8134
8318
|
let statusColor;
|
|
8135
8319
|
const status = entry.status || 0;
|
|
8136
8320
|
if (status >= 200 && status < 300) {
|
|
8137
|
-
statusColor =
|
|
8321
|
+
statusColor = chalk27.green;
|
|
8138
8322
|
} else if (status >= 300 && status < 400) {
|
|
8139
|
-
statusColor =
|
|
8323
|
+
statusColor = chalk27.yellow;
|
|
8140
8324
|
} else if (status >= 400) {
|
|
8141
|
-
statusColor =
|
|
8325
|
+
statusColor = chalk27.red;
|
|
8142
8326
|
} else {
|
|
8143
|
-
statusColor =
|
|
8327
|
+
statusColor = chalk27.gray;
|
|
8144
8328
|
}
|
|
8145
8329
|
let latencyColor;
|
|
8146
8330
|
const latencyMs = entry.latency_ms || 0;
|
|
8147
8331
|
if (latencyMs < 500) {
|
|
8148
|
-
latencyColor =
|
|
8332
|
+
latencyColor = chalk27.green;
|
|
8149
8333
|
} else if (latencyMs < 2e3) {
|
|
8150
|
-
latencyColor =
|
|
8334
|
+
latencyColor = chalk27.yellow;
|
|
8151
8335
|
} else {
|
|
8152
|
-
latencyColor =
|
|
8336
|
+
latencyColor = chalk27.red;
|
|
8153
8337
|
}
|
|
8154
8338
|
const method = entry.method || "???";
|
|
8155
8339
|
const requestSize = entry.request_size || 0;
|
|
8156
8340
|
const responseSize = entry.response_size || 0;
|
|
8157
8341
|
const url = entry.url || entry.host || "unknown";
|
|
8158
|
-
return `[${entry.timestamp}] ${method.padEnd(6)} ${statusColor(status)} ${latencyColor(latencyMs + "ms")} ${formatBytes(requestSize)}/${formatBytes(responseSize)} ${
|
|
8342
|
+
return `[${entry.timestamp}] ${method.padEnd(6)} ${statusColor(status)} ${latencyColor(latencyMs + "ms")} ${formatBytes(requestSize)}/${formatBytes(responseSize)} ${chalk27.dim(url)}`;
|
|
8159
8343
|
}
|
|
8160
8344
|
function renderAgentEvent(event, provider) {
|
|
8161
8345
|
const eventData = event.eventData;
|
|
@@ -8178,7 +8362,7 @@ function getLogType(options) {
|
|
|
8178
8362
|
].filter(Boolean).length;
|
|
8179
8363
|
if (selected > 1) {
|
|
8180
8364
|
console.error(
|
|
8181
|
-
|
|
8365
|
+
chalk27.red(
|
|
8182
8366
|
"Options --agent, --system, --metrics, and --network are mutually exclusive"
|
|
8183
8367
|
)
|
|
8184
8368
|
);
|
|
@@ -8189,7 +8373,7 @@ function getLogType(options) {
|
|
|
8189
8373
|
if (options.network) return "network";
|
|
8190
8374
|
return "agent";
|
|
8191
8375
|
}
|
|
8192
|
-
var logsCommand = new
|
|
8376
|
+
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(
|
|
8193
8377
|
"--since <time>",
|
|
8194
8378
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z, 1705312200)"
|
|
8195
8379
|
).option("--tail <n>", "Show last N entries (default: 5, max: 100)").option("--head <n>", "Show first N entries (max: 100)").action(
|
|
@@ -8198,7 +8382,7 @@ var logsCommand = new Command21().name("logs").description("View logs for an age
|
|
|
8198
8382
|
const logType = getLogType(options);
|
|
8199
8383
|
if (options.tail !== void 0 && options.head !== void 0) {
|
|
8200
8384
|
console.error(
|
|
8201
|
-
|
|
8385
|
+
chalk27.red("Options --tail and --head are mutually exclusive")
|
|
8202
8386
|
);
|
|
8203
8387
|
process.exit(1);
|
|
8204
8388
|
}
|
|
@@ -8235,7 +8419,7 @@ var logsCommand = new Command21().name("logs").description("View logs for an age
|
|
|
8235
8419
|
async function showAgentEvents(runId, options) {
|
|
8236
8420
|
const response = await apiClient.getAgentEvents(runId, options);
|
|
8237
8421
|
if (response.events.length === 0) {
|
|
8238
|
-
console.log(
|
|
8422
|
+
console.log(chalk27.yellow("No agent events found for this run"));
|
|
8239
8423
|
return;
|
|
8240
8424
|
}
|
|
8241
8425
|
const events = options.order === "desc" ? [...response.events].reverse() : response.events;
|
|
@@ -8245,7 +8429,7 @@ async function showAgentEvents(runId, options) {
|
|
|
8245
8429
|
if (response.hasMore) {
|
|
8246
8430
|
console.log();
|
|
8247
8431
|
console.log(
|
|
8248
|
-
|
|
8432
|
+
chalk27.dim(
|
|
8249
8433
|
`Showing ${response.events.length} events. Use --tail to see more.`
|
|
8250
8434
|
)
|
|
8251
8435
|
);
|
|
@@ -8254,21 +8438,21 @@ async function showAgentEvents(runId, options) {
|
|
|
8254
8438
|
async function showSystemLog(runId, options) {
|
|
8255
8439
|
const response = await apiClient.getSystemLog(runId, options);
|
|
8256
8440
|
if (!response.systemLog) {
|
|
8257
|
-
console.log(
|
|
8441
|
+
console.log(chalk27.yellow("No system log found for this run"));
|
|
8258
8442
|
return;
|
|
8259
8443
|
}
|
|
8260
8444
|
console.log(response.systemLog);
|
|
8261
8445
|
if (response.hasMore) {
|
|
8262
8446
|
console.log();
|
|
8263
8447
|
console.log(
|
|
8264
|
-
|
|
8448
|
+
chalk27.dim("More log entries available. Use --tail to see more.")
|
|
8265
8449
|
);
|
|
8266
8450
|
}
|
|
8267
8451
|
}
|
|
8268
8452
|
async function showMetrics(runId, options) {
|
|
8269
8453
|
const response = await apiClient.getMetrics(runId, options);
|
|
8270
8454
|
if (response.metrics.length === 0) {
|
|
8271
|
-
console.log(
|
|
8455
|
+
console.log(chalk27.yellow("No metrics found for this run"));
|
|
8272
8456
|
return;
|
|
8273
8457
|
}
|
|
8274
8458
|
const metrics = options.order === "desc" ? [...response.metrics].reverse() : response.metrics;
|
|
@@ -8278,7 +8462,7 @@ async function showMetrics(runId, options) {
|
|
|
8278
8462
|
if (response.hasMore) {
|
|
8279
8463
|
console.log();
|
|
8280
8464
|
console.log(
|
|
8281
|
-
|
|
8465
|
+
chalk27.dim(
|
|
8282
8466
|
`Showing ${response.metrics.length} metrics. Use --tail to see more.`
|
|
8283
8467
|
)
|
|
8284
8468
|
);
|
|
@@ -8288,7 +8472,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
8288
8472
|
const response = await apiClient.getNetworkLogs(runId, options);
|
|
8289
8473
|
if (response.networkLogs.length === 0) {
|
|
8290
8474
|
console.log(
|
|
8291
|
-
|
|
8475
|
+
chalk27.yellow(
|
|
8292
8476
|
"No network logs found for this run. Network logs are only captured when experimental_firewall is enabled on an experimental_runner"
|
|
8293
8477
|
)
|
|
8294
8478
|
);
|
|
@@ -8301,7 +8485,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
8301
8485
|
if (response.hasMore) {
|
|
8302
8486
|
console.log();
|
|
8303
8487
|
console.log(
|
|
8304
|
-
|
|
8488
|
+
chalk27.dim(
|
|
8305
8489
|
`Showing ${response.networkLogs.length} network logs. Use --tail to see more.`
|
|
8306
8490
|
)
|
|
8307
8491
|
);
|
|
@@ -8310,31 +8494,31 @@ async function showNetworkLogs(runId, options) {
|
|
|
8310
8494
|
function handleError2(error, runId) {
|
|
8311
8495
|
if (error instanceof Error) {
|
|
8312
8496
|
if (error.message.includes("Not authenticated")) {
|
|
8313
|
-
console.error(
|
|
8497
|
+
console.error(chalk27.red("Not authenticated. Run: vm0 auth login"));
|
|
8314
8498
|
} else if (error.message.includes("not found")) {
|
|
8315
|
-
console.error(
|
|
8499
|
+
console.error(chalk27.red(`Run not found: ${runId}`));
|
|
8316
8500
|
} else if (error.message.includes("Invalid time format")) {
|
|
8317
|
-
console.error(
|
|
8501
|
+
console.error(chalk27.red(error.message));
|
|
8318
8502
|
} else {
|
|
8319
|
-
console.error(
|
|
8320
|
-
console.error(
|
|
8503
|
+
console.error(chalk27.red("Failed to fetch logs"));
|
|
8504
|
+
console.error(chalk27.dim(` ${error.message}`));
|
|
8321
8505
|
}
|
|
8322
8506
|
} else {
|
|
8323
|
-
console.error(
|
|
8507
|
+
console.error(chalk27.red("An unexpected error occurred"));
|
|
8324
8508
|
}
|
|
8325
8509
|
}
|
|
8326
8510
|
|
|
8327
8511
|
// src/commands/scope/index.ts
|
|
8328
|
-
import { Command as
|
|
8512
|
+
import { Command as Command26 } from "commander";
|
|
8329
8513
|
|
|
8330
8514
|
// src/commands/scope/status.ts
|
|
8331
|
-
import { Command as
|
|
8332
|
-
import
|
|
8333
|
-
var statusCommand3 = new
|
|
8515
|
+
import { Command as Command24 } from "commander";
|
|
8516
|
+
import chalk28 from "chalk";
|
|
8517
|
+
var statusCommand3 = new Command24().name("status").description("View current scope status").action(async () => {
|
|
8334
8518
|
try {
|
|
8335
8519
|
const scope = await getScope();
|
|
8336
|
-
console.log(
|
|
8337
|
-
console.log(` Slug: ${
|
|
8520
|
+
console.log(chalk28.bold("Scope Information:"));
|
|
8521
|
+
console.log(` Slug: ${chalk28.green(scope.slug)}`);
|
|
8338
8522
|
console.log(` Type: ${scope.type}`);
|
|
8339
8523
|
console.log(
|
|
8340
8524
|
` Created: ${new Date(scope.createdAt).toLocaleDateString()}`
|
|
@@ -8342,29 +8526,29 @@ var statusCommand3 = new Command22().name("status").description("View current sc
|
|
|
8342
8526
|
} catch (error) {
|
|
8343
8527
|
if (error instanceof Error) {
|
|
8344
8528
|
if (error.message.includes("Not authenticated")) {
|
|
8345
|
-
console.error(
|
|
8529
|
+
console.error(chalk28.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
8346
8530
|
} else if (error.message.includes("No scope configured")) {
|
|
8347
|
-
console.log(
|
|
8531
|
+
console.log(chalk28.yellow("No scope configured"));
|
|
8348
8532
|
console.log();
|
|
8349
8533
|
console.log("Set your scope with:");
|
|
8350
|
-
console.log(
|
|
8534
|
+
console.log(chalk28.cyan(" vm0 scope set <slug>"));
|
|
8351
8535
|
console.log();
|
|
8352
8536
|
console.log("Example:");
|
|
8353
|
-
console.log(
|
|
8537
|
+
console.log(chalk28.dim(" vm0 scope set myusername"));
|
|
8354
8538
|
} else {
|
|
8355
|
-
console.error(
|
|
8539
|
+
console.error(chalk28.red(`\u2717 ${error.message}`));
|
|
8356
8540
|
}
|
|
8357
8541
|
} else {
|
|
8358
|
-
console.error(
|
|
8542
|
+
console.error(chalk28.red("\u2717 An unexpected error occurred"));
|
|
8359
8543
|
}
|
|
8360
8544
|
process.exit(1);
|
|
8361
8545
|
}
|
|
8362
8546
|
});
|
|
8363
8547
|
|
|
8364
8548
|
// src/commands/scope/set.ts
|
|
8365
|
-
import { Command as
|
|
8366
|
-
import
|
|
8367
|
-
var setCommand = new
|
|
8549
|
+
import { Command as Command25 } from "commander";
|
|
8550
|
+
import chalk29 from "chalk";
|
|
8551
|
+
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)").action(async (slug, options) => {
|
|
8368
8552
|
try {
|
|
8369
8553
|
let existingScope;
|
|
8370
8554
|
try {
|
|
@@ -8378,66 +8562,66 @@ var setCommand = new Command23().name("set").description("Set your scope slug").
|
|
|
8378
8562
|
if (existingScope) {
|
|
8379
8563
|
if (!options.force) {
|
|
8380
8564
|
console.error(
|
|
8381
|
-
|
|
8565
|
+
chalk29.yellow(`You already have a scope: ${existingScope.slug}`)
|
|
8382
8566
|
);
|
|
8383
8567
|
console.error();
|
|
8384
8568
|
console.error("To change your scope, use --force:");
|
|
8385
|
-
console.error(
|
|
8569
|
+
console.error(chalk29.cyan(` vm0 scope set ${slug} --force`));
|
|
8386
8570
|
console.error();
|
|
8387
8571
|
console.error(
|
|
8388
|
-
|
|
8572
|
+
chalk29.yellow(
|
|
8389
8573
|
"Warning: Changing your scope may break existing agent references."
|
|
8390
8574
|
)
|
|
8391
8575
|
);
|
|
8392
8576
|
process.exit(1);
|
|
8393
8577
|
}
|
|
8394
8578
|
scope = await updateScope({ slug, force: true });
|
|
8395
|
-
console.log(
|
|
8579
|
+
console.log(chalk29.green(`\u2713 Scope updated to ${scope.slug}`));
|
|
8396
8580
|
} else {
|
|
8397
8581
|
scope = await createScope({ slug });
|
|
8398
|
-
console.log(
|
|
8582
|
+
console.log(chalk29.green(`\u2713 Scope created: ${scope.slug}`));
|
|
8399
8583
|
}
|
|
8400
8584
|
console.log();
|
|
8401
8585
|
console.log("Your agents will now be namespaced as:");
|
|
8402
|
-
console.log(
|
|
8586
|
+
console.log(chalk29.cyan(` ${scope.slug}/<agent-name>`));
|
|
8403
8587
|
} catch (error) {
|
|
8404
8588
|
if (error instanceof Error) {
|
|
8405
8589
|
if (error.message.includes("Not authenticated")) {
|
|
8406
|
-
console.error(
|
|
8590
|
+
console.error(chalk29.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
8407
8591
|
} else if (error.message.includes("already exists")) {
|
|
8408
8592
|
console.error(
|
|
8409
|
-
|
|
8593
|
+
chalk29.red(
|
|
8410
8594
|
`\u2717 Scope "${slug}" is already taken. Please choose a different slug.`
|
|
8411
8595
|
)
|
|
8412
8596
|
);
|
|
8413
8597
|
} else if (error.message.includes("reserved")) {
|
|
8414
|
-
console.error(
|
|
8598
|
+
console.error(chalk29.red(`\u2717 ${error.message}`));
|
|
8415
8599
|
} else if (error.message.includes("vm0")) {
|
|
8416
8600
|
console.error(
|
|
8417
|
-
|
|
8601
|
+
chalk29.red(
|
|
8418
8602
|
"\u2717 Scope slugs cannot start with 'vm0' (reserved for system use)"
|
|
8419
8603
|
)
|
|
8420
8604
|
);
|
|
8421
8605
|
} else {
|
|
8422
|
-
console.error(
|
|
8606
|
+
console.error(chalk29.red(`\u2717 ${error.message}`));
|
|
8423
8607
|
}
|
|
8424
8608
|
} else {
|
|
8425
|
-
console.error(
|
|
8609
|
+
console.error(chalk29.red("\u2717 An unexpected error occurred"));
|
|
8426
8610
|
}
|
|
8427
8611
|
process.exit(1);
|
|
8428
8612
|
}
|
|
8429
8613
|
});
|
|
8430
8614
|
|
|
8431
8615
|
// src/commands/scope/index.ts
|
|
8432
|
-
var scopeCommand = new
|
|
8616
|
+
var scopeCommand = new Command26().name("scope").description("Manage your scope (namespace for agents)").addCommand(statusCommand3).addCommand(setCommand);
|
|
8433
8617
|
|
|
8434
8618
|
// src/commands/agent/index.ts
|
|
8435
|
-
import { Command as
|
|
8619
|
+
import { Command as Command29 } from "commander";
|
|
8436
8620
|
|
|
8437
8621
|
// src/commands/agent/list.ts
|
|
8438
|
-
import { Command as
|
|
8439
|
-
import
|
|
8440
|
-
var
|
|
8622
|
+
import { Command as Command27 } from "commander";
|
|
8623
|
+
import chalk30 from "chalk";
|
|
8624
|
+
var listCommand4 = new Command27().name("list").alias("ls").description("List all agent composes").action(async () => {
|
|
8441
8625
|
try {
|
|
8442
8626
|
const response = await httpGet("/api/agent/composes/list");
|
|
8443
8627
|
if (!response.ok) {
|
|
@@ -8446,9 +8630,9 @@ var listCommand3 = new Command25().name("list").alias("ls").description("List al
|
|
|
8446
8630
|
}
|
|
8447
8631
|
const data = await response.json();
|
|
8448
8632
|
if (data.composes.length === 0) {
|
|
8449
|
-
console.log(
|
|
8633
|
+
console.log(chalk30.dim("No agent composes found"));
|
|
8450
8634
|
console.log(
|
|
8451
|
-
|
|
8635
|
+
chalk30.dim(" Create one with: vm0 compose <agent-compose.yaml>")
|
|
8452
8636
|
);
|
|
8453
8637
|
return;
|
|
8454
8638
|
}
|
|
@@ -8456,9 +8640,9 @@ var listCommand3 = new Command25().name("list").alias("ls").description("List al
|
|
|
8456
8640
|
const header = ["NAME".padEnd(nameWidth), "VERSION", "UPDATED"].join(
|
|
8457
8641
|
" "
|
|
8458
8642
|
);
|
|
8459
|
-
console.log(
|
|
8643
|
+
console.log(chalk30.dim(header));
|
|
8460
8644
|
for (const compose of data.composes) {
|
|
8461
|
-
const versionShort = compose.headVersionId ? compose.headVersionId.slice(0, 8) :
|
|
8645
|
+
const versionShort = compose.headVersionId ? compose.headVersionId.slice(0, 8) : chalk30.dim("-");
|
|
8462
8646
|
const row = [
|
|
8463
8647
|
compose.name.padEnd(nameWidth),
|
|
8464
8648
|
versionShort,
|
|
@@ -8467,12 +8651,12 @@ var listCommand3 = new Command25().name("list").alias("ls").description("List al
|
|
|
8467
8651
|
console.log(row);
|
|
8468
8652
|
}
|
|
8469
8653
|
} catch (error) {
|
|
8470
|
-
console.error(
|
|
8654
|
+
console.error(chalk30.red("\u2717 Failed to list agent composes"));
|
|
8471
8655
|
if (error instanceof Error) {
|
|
8472
8656
|
if (error.message.includes("Not authenticated")) {
|
|
8473
|
-
console.error(
|
|
8657
|
+
console.error(chalk30.dim(" Run: vm0 auth login"));
|
|
8474
8658
|
} else {
|
|
8475
|
-
console.error(
|
|
8659
|
+
console.error(chalk30.dim(` ${error.message}`));
|
|
8476
8660
|
}
|
|
8477
8661
|
}
|
|
8478
8662
|
process.exit(1);
|
|
@@ -8480,8 +8664,8 @@ var listCommand3 = new Command25().name("list").alias("ls").description("List al
|
|
|
8480
8664
|
});
|
|
8481
8665
|
|
|
8482
8666
|
// src/commands/agent/status.ts
|
|
8483
|
-
import { Command as
|
|
8484
|
-
import
|
|
8667
|
+
import { Command as Command28 } from "commander";
|
|
8668
|
+
import chalk31 from "chalk";
|
|
8485
8669
|
|
|
8486
8670
|
// src/lib/domain/source-derivation.ts
|
|
8487
8671
|
import * as fs9 from "fs/promises";
|
|
@@ -8605,27 +8789,27 @@ function formatVariableSources(sources) {
|
|
|
8605
8789
|
if (sources.secrets.length > 0) {
|
|
8606
8790
|
console.log(` Secrets:`);
|
|
8607
8791
|
for (const secret of sources.secrets) {
|
|
8608
|
-
const sourceInfo =
|
|
8792
|
+
const sourceInfo = chalk31.dim(`(${secret.source})`);
|
|
8609
8793
|
console.log(` - ${secret.name.padEnd(20)} ${sourceInfo}`);
|
|
8610
8794
|
}
|
|
8611
8795
|
}
|
|
8612
8796
|
if (sources.vars.length > 0) {
|
|
8613
8797
|
console.log(` Vars:`);
|
|
8614
8798
|
for (const v of sources.vars) {
|
|
8615
|
-
const sourceInfo =
|
|
8799
|
+
const sourceInfo = chalk31.dim(`(${v.source})`);
|
|
8616
8800
|
console.log(` - ${v.name.padEnd(20)} ${sourceInfo}`);
|
|
8617
8801
|
}
|
|
8618
8802
|
}
|
|
8619
8803
|
if (sources.credentials.length > 0) {
|
|
8620
8804
|
console.log(` Credentials:`);
|
|
8621
8805
|
for (const cred of sources.credentials) {
|
|
8622
|
-
const sourceInfo =
|
|
8806
|
+
const sourceInfo = chalk31.dim(`(${cred.source})`);
|
|
8623
8807
|
console.log(` - ${cred.name.padEnd(20)} ${sourceInfo}`);
|
|
8624
8808
|
}
|
|
8625
8809
|
}
|
|
8626
8810
|
}
|
|
8627
8811
|
function formatAgentDetails(agentName, agent, agentSources, volumeConfigs) {
|
|
8628
|
-
console.log(` ${
|
|
8812
|
+
console.log(` ${chalk31.cyan(agentName)}:`);
|
|
8629
8813
|
console.log(` Framework: ${agent.framework}`);
|
|
8630
8814
|
if (agent.image) {
|
|
8631
8815
|
console.log(` Image: ${agent.image}`);
|
|
@@ -8644,16 +8828,16 @@ function formatAgentDetails(agentName, agent, agentSources, volumeConfigs) {
|
|
|
8644
8828
|
}
|
|
8645
8829
|
}
|
|
8646
8830
|
function formatComposeOutput(name, versionId, content, variableSources) {
|
|
8647
|
-
console.log(
|
|
8648
|
-
console.log(
|
|
8831
|
+
console.log(chalk31.bold("Name:") + ` ${name}`);
|
|
8832
|
+
console.log(chalk31.bold("Version:") + ` ${versionId}`);
|
|
8649
8833
|
console.log();
|
|
8650
|
-
console.log(
|
|
8834
|
+
console.log(chalk31.bold("Agents:"));
|
|
8651
8835
|
for (const [agentName, agent] of Object.entries(content.agents)) {
|
|
8652
8836
|
const agentSources = variableSources?.get(agentName);
|
|
8653
8837
|
formatAgentDetails(agentName, agent, agentSources, content.volumes);
|
|
8654
8838
|
}
|
|
8655
8839
|
}
|
|
8656
|
-
var statusCommand4 = new
|
|
8840
|
+
var statusCommand4 = new Command28().name("status").description("Show status of agent compose").argument(
|
|
8657
8841
|
"<name[:version]>",
|
|
8658
8842
|
"Agent name with optional version (e.g., my-agent:latest or my-agent:a1b2c3d4)"
|
|
8659
8843
|
).option("--no-sources", "Skip fetching skills to determine variable sources").action(async (argument, options) => {
|
|
@@ -8670,8 +8854,8 @@ var statusCommand4 = new Command26().name("status").description("Show status of
|
|
|
8670
8854
|
}
|
|
8671
8855
|
const compose = await getComposeByName(name);
|
|
8672
8856
|
if (!compose) {
|
|
8673
|
-
console.error(
|
|
8674
|
-
console.error(
|
|
8857
|
+
console.error(chalk31.red(`\u2717 Agent compose not found: ${name}`));
|
|
8858
|
+
console.error(chalk31.dim(" Run: vm0 agent list"));
|
|
8675
8859
|
process.exit(1);
|
|
8676
8860
|
}
|
|
8677
8861
|
let resolvedVersionId = compose.headVersionId;
|
|
@@ -8682,9 +8866,9 @@ var statusCommand4 = new Command26().name("status").description("Show status of
|
|
|
8682
8866
|
resolvedVersionId = versionInfo.versionId;
|
|
8683
8867
|
} catch (error) {
|
|
8684
8868
|
if (error instanceof Error && error.message.includes("not found")) {
|
|
8685
|
-
console.error(
|
|
8869
|
+
console.error(chalk31.red(`\u2717 Version not found: ${version}`));
|
|
8686
8870
|
console.error(
|
|
8687
|
-
|
|
8871
|
+
chalk31.dim(
|
|
8688
8872
|
` HEAD version: ${compose.headVersionId?.slice(0, 8)}`
|
|
8689
8873
|
)
|
|
8690
8874
|
);
|
|
@@ -8697,7 +8881,7 @@ var statusCommand4 = new Command26().name("status").description("Show status of
|
|
|
8697
8881
|
}
|
|
8698
8882
|
}
|
|
8699
8883
|
if (!resolvedVersionId || !compose.content) {
|
|
8700
|
-
console.error(
|
|
8884
|
+
console.error(chalk31.red(`\u2717 No version found for: ${name}`));
|
|
8701
8885
|
process.exit(1);
|
|
8702
8886
|
}
|
|
8703
8887
|
const content = compose.content;
|
|
@@ -8708,7 +8892,7 @@ var statusCommand4 = new Command26().name("status").description("Show status of
|
|
|
8708
8892
|
});
|
|
8709
8893
|
} catch {
|
|
8710
8894
|
console.error(
|
|
8711
|
-
|
|
8895
|
+
chalk31.yellow(
|
|
8712
8896
|
"\u26A0 Warning: Failed to fetch skill sources, showing basic info"
|
|
8713
8897
|
)
|
|
8714
8898
|
);
|
|
@@ -8720,12 +8904,12 @@ var statusCommand4 = new Command26().name("status").description("Show status of
|
|
|
8720
8904
|
variableSources
|
|
8721
8905
|
);
|
|
8722
8906
|
} catch (error) {
|
|
8723
|
-
console.error(
|
|
8907
|
+
console.error(chalk31.red("\u2717 Failed to get agent compose status"));
|
|
8724
8908
|
if (error instanceof Error) {
|
|
8725
8909
|
if (error.message.includes("Not authenticated")) {
|
|
8726
|
-
console.error(
|
|
8910
|
+
console.error(chalk31.dim(" Run: vm0 auth login"));
|
|
8727
8911
|
} else {
|
|
8728
|
-
console.error(
|
|
8912
|
+
console.error(chalk31.dim(` ${error.message}`));
|
|
8729
8913
|
}
|
|
8730
8914
|
}
|
|
8731
8915
|
process.exit(1);
|
|
@@ -8733,11 +8917,11 @@ var statusCommand4 = new Command26().name("status").description("Show status of
|
|
|
8733
8917
|
});
|
|
8734
8918
|
|
|
8735
8919
|
// src/commands/agent/index.ts
|
|
8736
|
-
var agentCommand = new
|
|
8920
|
+
var agentCommand = new Command29().name("agent").description("Manage agent composes").addCommand(listCommand4).addCommand(statusCommand4);
|
|
8737
8921
|
|
|
8738
8922
|
// src/commands/init.ts
|
|
8739
|
-
import { Command as
|
|
8740
|
-
import
|
|
8923
|
+
import { Command as Command30 } from "commander";
|
|
8924
|
+
import chalk32 from "chalk";
|
|
8741
8925
|
import path13 from "path";
|
|
8742
8926
|
import { existsSync as existsSync9 } from "fs";
|
|
8743
8927
|
import { writeFile as writeFile6 } from "fs/promises";
|
|
@@ -8775,14 +8959,14 @@ function checkExistingFiles() {
|
|
|
8775
8959
|
if (existsSync9(AGENTS_MD_FILE)) existingFiles.push(AGENTS_MD_FILE);
|
|
8776
8960
|
return existingFiles;
|
|
8777
8961
|
}
|
|
8778
|
-
var initCommand3 = new
|
|
8962
|
+
var initCommand3 = new Command30().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) => {
|
|
8779
8963
|
const existingFiles = checkExistingFiles();
|
|
8780
8964
|
if (existingFiles.length > 0 && !options.force) {
|
|
8781
8965
|
for (const file of existingFiles) {
|
|
8782
|
-
console.log(
|
|
8966
|
+
console.log(chalk32.red(`\u2717 ${file} already exists`));
|
|
8783
8967
|
}
|
|
8784
8968
|
console.log();
|
|
8785
|
-
console.log(`To overwrite: ${
|
|
8969
|
+
console.log(`To overwrite: ${chalk32.cyan("vm0 init --force")}`);
|
|
8786
8970
|
process.exit(1);
|
|
8787
8971
|
}
|
|
8788
8972
|
let agentName;
|
|
@@ -8790,9 +8974,9 @@ var initCommand3 = new Command28().name("init").description("Initialize a new VM
|
|
|
8790
8974
|
agentName = options.name.trim();
|
|
8791
8975
|
} else if (!isInteractive()) {
|
|
8792
8976
|
console.error(
|
|
8793
|
-
|
|
8977
|
+
chalk32.red("\u2717 --name flag is required in non-interactive mode")
|
|
8794
8978
|
);
|
|
8795
|
-
console.error(
|
|
8979
|
+
console.error(chalk32.dim(" Usage: vm0 init --name <agent-name>"));
|
|
8796
8980
|
process.exit(1);
|
|
8797
8981
|
} else {
|
|
8798
8982
|
const dirName = path13.basename(process.cwd());
|
|
@@ -8808,44 +8992,44 @@ var initCommand3 = new Command28().name("init").description("Initialize a new VM
|
|
|
8808
8992
|
}
|
|
8809
8993
|
);
|
|
8810
8994
|
if (name === void 0) {
|
|
8811
|
-
console.log(
|
|
8995
|
+
console.log(chalk32.dim("Cancelled"));
|
|
8812
8996
|
return;
|
|
8813
8997
|
}
|
|
8814
8998
|
agentName = name;
|
|
8815
8999
|
}
|
|
8816
9000
|
if (!agentName || !validateAgentName(agentName)) {
|
|
8817
|
-
console.log(
|
|
9001
|
+
console.log(chalk32.red("\u2717 Invalid agent name"));
|
|
8818
9002
|
console.log(
|
|
8819
|
-
|
|
9003
|
+
chalk32.dim(" Must be 3-64 characters, alphanumeric and hyphens only")
|
|
8820
9004
|
);
|
|
8821
|
-
console.log(
|
|
9005
|
+
console.log(chalk32.dim(" Must start and end with letter or number"));
|
|
8822
9006
|
process.exit(1);
|
|
8823
9007
|
}
|
|
8824
9008
|
await writeFile6(VM0_YAML_FILE, generateVm0Yaml(agentName));
|
|
8825
9009
|
const vm0Status = existingFiles.includes(VM0_YAML_FILE) ? " (overwritten)" : "";
|
|
8826
|
-
console.log(
|
|
9010
|
+
console.log(chalk32.green(`\u2713 Created ${VM0_YAML_FILE}${vm0Status}`));
|
|
8827
9011
|
await writeFile6(AGENTS_MD_FILE, generateAgentsMd());
|
|
8828
9012
|
const agentsStatus = existingFiles.includes(AGENTS_MD_FILE) ? " (overwritten)" : "";
|
|
8829
|
-
console.log(
|
|
9013
|
+
console.log(chalk32.green(`\u2713 Created ${AGENTS_MD_FILE}${agentsStatus}`));
|
|
8830
9014
|
console.log();
|
|
8831
9015
|
console.log("Next steps:");
|
|
8832
9016
|
console.log(
|
|
8833
|
-
` 1. Set model provider (one-time): ${
|
|
9017
|
+
` 1. Set model provider (one-time): ${chalk32.cyan("vm0 model-provider setup")}`
|
|
8834
9018
|
);
|
|
8835
9019
|
console.log(
|
|
8836
|
-
` 2. Edit ${
|
|
9020
|
+
` 2. Edit ${chalk32.cyan("AGENTS.md")} to customize your agent's workflow`
|
|
8837
9021
|
);
|
|
8838
9022
|
console.log(
|
|
8839
|
-
` 3. Run your agent: ${
|
|
9023
|
+
` 3. Run your agent: ${chalk32.cyan(`vm0 cook "let's start working."`)}`
|
|
8840
9024
|
);
|
|
8841
9025
|
});
|
|
8842
9026
|
|
|
8843
9027
|
// src/commands/schedule/index.ts
|
|
8844
|
-
import { Command as
|
|
9028
|
+
import { Command as Command37 } from "commander";
|
|
8845
9029
|
|
|
8846
9030
|
// src/commands/schedule/setup.ts
|
|
8847
|
-
import { Command as
|
|
8848
|
-
import
|
|
9031
|
+
import { Command as Command31 } from "commander";
|
|
9032
|
+
import chalk34 from "chalk";
|
|
8849
9033
|
|
|
8850
9034
|
// src/lib/domain/schedule-utils.ts
|
|
8851
9035
|
import { parse as parseYaml5 } from "yaml";
|
|
@@ -8987,7 +9171,7 @@ async function resolveScheduleByAgent(agentName) {
|
|
|
8987
9171
|
}
|
|
8988
9172
|
|
|
8989
9173
|
// src/commands/schedule/gather-configuration.ts
|
|
8990
|
-
import
|
|
9174
|
+
import chalk33 from "chalk";
|
|
8991
9175
|
var defaultPromptDeps = {
|
|
8992
9176
|
isInteractive,
|
|
8993
9177
|
promptConfirm,
|
|
@@ -9021,7 +9205,7 @@ async function handleSecrets(optionSecrets, existingSecretNames, deps) {
|
|
|
9021
9205
|
if (keepSecrets) {
|
|
9022
9206
|
return { secrets: {}, preserveExistingSecrets: true };
|
|
9023
9207
|
}
|
|
9024
|
-
console.log(
|
|
9208
|
+
console.log(chalk33.dim(" Note: You'll need to provide new secret values"));
|
|
9025
9209
|
return { secrets: {}, preserveExistingSecrets: false };
|
|
9026
9210
|
}
|
|
9027
9211
|
return { secrets: {}, preserveExistingSecrets: false };
|
|
@@ -9042,17 +9226,17 @@ async function handleVars(optionVars, existingVars, deps) {
|
|
|
9042
9226
|
return {};
|
|
9043
9227
|
}
|
|
9044
9228
|
function displayMissingRequirements(missingSecrets, missingVars) {
|
|
9045
|
-
console.log(
|
|
9229
|
+
console.log(chalk33.yellow("\nAgent requires the following configuration:"));
|
|
9046
9230
|
if (missingSecrets.length > 0) {
|
|
9047
|
-
console.log(
|
|
9231
|
+
console.log(chalk33.dim(" Secrets:"));
|
|
9048
9232
|
for (const name of missingSecrets) {
|
|
9049
|
-
console.log(
|
|
9233
|
+
console.log(chalk33.dim(` ${name}`));
|
|
9050
9234
|
}
|
|
9051
9235
|
}
|
|
9052
9236
|
if (missingVars.length > 0) {
|
|
9053
|
-
console.log(
|
|
9237
|
+
console.log(chalk33.dim(" Vars:"));
|
|
9054
9238
|
for (const name of missingVars) {
|
|
9055
|
-
console.log(
|
|
9239
|
+
console.log(chalk33.dim(` ${name}`));
|
|
9056
9240
|
}
|
|
9057
9241
|
}
|
|
9058
9242
|
console.log("");
|
|
@@ -9060,7 +9244,7 @@ function displayMissingRequirements(missingSecrets, missingVars) {
|
|
|
9060
9244
|
async function promptForMissingSecrets(missingSecrets, secrets, deps) {
|
|
9061
9245
|
for (const name of missingSecrets) {
|
|
9062
9246
|
const value = await deps.promptPassword(
|
|
9063
|
-
`Enter value for secret ${
|
|
9247
|
+
`Enter value for secret ${chalk33.cyan(name)}`
|
|
9064
9248
|
);
|
|
9065
9249
|
if (value) {
|
|
9066
9250
|
secrets[name] = value;
|
|
@@ -9070,7 +9254,7 @@ async function promptForMissingSecrets(missingSecrets, secrets, deps) {
|
|
|
9070
9254
|
async function promptForMissingVars(missingVars, vars, deps) {
|
|
9071
9255
|
for (const name of missingVars) {
|
|
9072
9256
|
const value = await deps.promptText(
|
|
9073
|
-
`Enter value for var ${
|
|
9257
|
+
`Enter value for var ${chalk33.cyan(name)}`,
|
|
9074
9258
|
""
|
|
9075
9259
|
);
|
|
9076
9260
|
if (value) {
|
|
@@ -9160,7 +9344,7 @@ function expandEnvVars(value) {
|
|
|
9160
9344
|
const envValue = process.env[varName];
|
|
9161
9345
|
if (envValue === void 0) {
|
|
9162
9346
|
console.warn(
|
|
9163
|
-
|
|
9347
|
+
chalk34.yellow(` Warning: Environment variable ${varName} not set`)
|
|
9164
9348
|
);
|
|
9165
9349
|
return match;
|
|
9166
9350
|
}
|
|
@@ -9227,7 +9411,7 @@ async function gatherFrequency(optionFrequency, existingFrequency) {
|
|
|
9227
9411
|
}
|
|
9228
9412
|
if (!isInteractive()) {
|
|
9229
9413
|
console.error(
|
|
9230
|
-
|
|
9414
|
+
chalk34.red("\u2717 --frequency is required (daily|weekly|monthly|once)")
|
|
9231
9415
|
);
|
|
9232
9416
|
process.exit(1);
|
|
9233
9417
|
}
|
|
@@ -9247,7 +9431,7 @@ async function gatherDay(frequency, optionDay, existingDay) {
|
|
|
9247
9431
|
const day2 = parseDayOption(optionDay, frequency);
|
|
9248
9432
|
if (day2 === void 0) {
|
|
9249
9433
|
console.error(
|
|
9250
|
-
|
|
9434
|
+
chalk34.red(
|
|
9251
9435
|
`\u2717 Invalid day: ${optionDay}. Use mon-sun for weekly or 1-31 for monthly.`
|
|
9252
9436
|
)
|
|
9253
9437
|
);
|
|
@@ -9256,7 +9440,7 @@ async function gatherDay(frequency, optionDay, existingDay) {
|
|
|
9256
9440
|
return day2;
|
|
9257
9441
|
}
|
|
9258
9442
|
if (!isInteractive()) {
|
|
9259
|
-
console.error(
|
|
9443
|
+
console.error(chalk34.red("\u2717 --day is required for weekly/monthly"));
|
|
9260
9444
|
process.exit(1);
|
|
9261
9445
|
}
|
|
9262
9446
|
if (frequency === "weekly") {
|
|
@@ -9275,7 +9459,7 @@ async function gatherDay(frequency, optionDay, existingDay) {
|
|
|
9275
9459
|
if (!dayStr) return null;
|
|
9276
9460
|
const day = parseInt(dayStr, 10);
|
|
9277
9461
|
if (isNaN(day) || day < 1 || day > 31) {
|
|
9278
|
-
console.error(
|
|
9462
|
+
console.error(chalk34.red("\u2717 Day must be between 1 and 31"));
|
|
9279
9463
|
process.exit(1);
|
|
9280
9464
|
}
|
|
9281
9465
|
return day;
|
|
@@ -9284,13 +9468,13 @@ async function gatherRecurringTime(optionTime, existingTime) {
|
|
|
9284
9468
|
if (optionTime) {
|
|
9285
9469
|
const validation = validateTimeFormat(optionTime);
|
|
9286
9470
|
if (validation !== true) {
|
|
9287
|
-
console.error(
|
|
9471
|
+
console.error(chalk34.red(`\u2717 Invalid time: ${validation}`));
|
|
9288
9472
|
process.exit(1);
|
|
9289
9473
|
}
|
|
9290
9474
|
return optionTime;
|
|
9291
9475
|
}
|
|
9292
9476
|
if (!isInteractive()) {
|
|
9293
|
-
console.error(
|
|
9477
|
+
console.error(chalk34.red("\u2717 --time is required (HH:MM format)"));
|
|
9294
9478
|
process.exit(1);
|
|
9295
9479
|
}
|
|
9296
9480
|
return await promptText(
|
|
@@ -9303,7 +9487,7 @@ async function gatherOneTimeSchedule(optionDay, optionTime, existingTime) {
|
|
|
9303
9487
|
if (optionDay && optionTime) {
|
|
9304
9488
|
if (!validateDateFormat(optionDay)) {
|
|
9305
9489
|
console.error(
|
|
9306
|
-
|
|
9490
|
+
chalk34.red(
|
|
9307
9491
|
`\u2717 Invalid date format: ${optionDay}. Use YYYY-MM-DD format.`
|
|
9308
9492
|
)
|
|
9309
9493
|
);
|
|
@@ -9311,16 +9495,16 @@ async function gatherOneTimeSchedule(optionDay, optionTime, existingTime) {
|
|
|
9311
9495
|
}
|
|
9312
9496
|
if (!validateTimeFormat(optionTime)) {
|
|
9313
9497
|
console.error(
|
|
9314
|
-
|
|
9498
|
+
chalk34.red(`\u2717 Invalid time format: ${optionTime}. Use HH:MM format.`)
|
|
9315
9499
|
);
|
|
9316
9500
|
process.exit(1);
|
|
9317
9501
|
}
|
|
9318
9502
|
return `${optionDay} ${optionTime}`;
|
|
9319
9503
|
}
|
|
9320
9504
|
if (!isInteractive()) {
|
|
9321
|
-
console.error(
|
|
9505
|
+
console.error(chalk34.red("\u2717 One-time schedules require interactive mode"));
|
|
9322
9506
|
console.error(
|
|
9323
|
-
|
|
9507
|
+
chalk34.dim(" Or provide --day (YYYY-MM-DD) and --time (HH:MM) flags")
|
|
9324
9508
|
);
|
|
9325
9509
|
process.exit(1);
|
|
9326
9510
|
}
|
|
@@ -9351,7 +9535,7 @@ async function gatherTimezone(optionTimezone, existingTimezone) {
|
|
|
9351
9535
|
async function gatherPromptText(optionPrompt, existingPrompt) {
|
|
9352
9536
|
if (optionPrompt) return optionPrompt;
|
|
9353
9537
|
if (!isInteractive()) {
|
|
9354
|
-
console.error(
|
|
9538
|
+
console.error(chalk34.red("\u2717 --prompt is required"));
|
|
9355
9539
|
process.exit(1);
|
|
9356
9540
|
}
|
|
9357
9541
|
return await promptText(
|
|
@@ -9362,8 +9546,8 @@ async function gatherPromptText(optionPrompt, existingPrompt) {
|
|
|
9362
9546
|
async function resolveAgent(agentName) {
|
|
9363
9547
|
const compose = await getComposeByName(agentName);
|
|
9364
9548
|
if (!compose) {
|
|
9365
|
-
console.error(
|
|
9366
|
-
console.error(
|
|
9549
|
+
console.error(chalk34.red(`\u2717 Agent not found: ${agentName}`));
|
|
9550
|
+
console.error(chalk34.dim(" Make sure the agent is composed first"));
|
|
9367
9551
|
process.exit(1);
|
|
9368
9552
|
}
|
|
9369
9553
|
return {
|
|
@@ -9410,7 +9594,7 @@ async function buildAndDeploy(params) {
|
|
|
9410
9594
|
const expandedSecrets = expandEnvVarsInObject(params.secrets);
|
|
9411
9595
|
console.log(
|
|
9412
9596
|
`
|
|
9413
|
-
Deploying schedule for agent ${
|
|
9597
|
+
Deploying schedule for agent ${chalk34.cyan(params.agentName)}...`
|
|
9414
9598
|
);
|
|
9415
9599
|
const deployResult = await deploySchedule({
|
|
9416
9600
|
name: params.scheduleName,
|
|
@@ -9426,12 +9610,12 @@ Deploying schedule for agent ${chalk32.cyan(params.agentName)}...`
|
|
|
9426
9610
|
return deployResult;
|
|
9427
9611
|
}
|
|
9428
9612
|
function handleSetupError(error) {
|
|
9429
|
-
console.error(
|
|
9613
|
+
console.error(chalk34.red("\u2717 Failed to setup schedule"));
|
|
9430
9614
|
if (error instanceof Error) {
|
|
9431
9615
|
if (error.message.includes("Not authenticated")) {
|
|
9432
|
-
console.error(
|
|
9616
|
+
console.error(chalk34.dim(" Run: vm0 auth login"));
|
|
9433
9617
|
} else {
|
|
9434
|
-
console.error(
|
|
9618
|
+
console.error(chalk34.dim(` ${error.message}`));
|
|
9435
9619
|
}
|
|
9436
9620
|
}
|
|
9437
9621
|
process.exit(1);
|
|
@@ -9439,56 +9623,56 @@ function handleSetupError(error) {
|
|
|
9439
9623
|
function displayDeployResult(agentName, deployResult) {
|
|
9440
9624
|
if (deployResult.created) {
|
|
9441
9625
|
console.log(
|
|
9442
|
-
|
|
9626
|
+
chalk34.green(`\u2713 Created schedule for agent ${chalk34.cyan(agentName)}`)
|
|
9443
9627
|
);
|
|
9444
9628
|
} else {
|
|
9445
9629
|
console.log(
|
|
9446
|
-
|
|
9630
|
+
chalk34.green(`\u2713 Updated schedule for agent ${chalk34.cyan(agentName)}`)
|
|
9447
9631
|
);
|
|
9448
9632
|
}
|
|
9449
|
-
console.log(
|
|
9633
|
+
console.log(chalk34.dim(` Timezone: ${deployResult.schedule.timezone}`));
|
|
9450
9634
|
if (deployResult.schedule.cronExpression) {
|
|
9451
|
-
console.log(
|
|
9635
|
+
console.log(chalk34.dim(` Cron: ${deployResult.schedule.cronExpression}`));
|
|
9452
9636
|
if (deployResult.schedule.nextRunAt) {
|
|
9453
9637
|
const nextRun = formatInTimezone(
|
|
9454
9638
|
deployResult.schedule.nextRunAt,
|
|
9455
9639
|
deployResult.schedule.timezone
|
|
9456
9640
|
);
|
|
9457
|
-
console.log(
|
|
9641
|
+
console.log(chalk34.dim(` Next run: ${nextRun}`));
|
|
9458
9642
|
}
|
|
9459
9643
|
} else if (deployResult.schedule.atTime) {
|
|
9460
9644
|
const atTimeFormatted = formatInTimezone(
|
|
9461
9645
|
deployResult.schedule.atTime,
|
|
9462
9646
|
deployResult.schedule.timezone
|
|
9463
9647
|
);
|
|
9464
|
-
console.log(
|
|
9648
|
+
console.log(chalk34.dim(` At: ${atTimeFormatted}`));
|
|
9465
9649
|
}
|
|
9466
9650
|
}
|
|
9467
9651
|
async function tryEnableSchedule(scheduleName, composeId, agentName) {
|
|
9468
9652
|
try {
|
|
9469
9653
|
await enableSchedule({ name: scheduleName, composeId });
|
|
9470
9654
|
console.log(
|
|
9471
|
-
|
|
9655
|
+
chalk34.green(`\u2713 Enabled schedule for agent ${chalk34.cyan(agentName)}`)
|
|
9472
9656
|
);
|
|
9473
9657
|
} catch (error) {
|
|
9474
|
-
console.error(
|
|
9658
|
+
console.error(chalk34.yellow("\u26A0 Failed to enable schedule"));
|
|
9475
9659
|
if (error instanceof ApiRequestError) {
|
|
9476
9660
|
if (error.code === "SCHEDULE_PAST") {
|
|
9477
|
-
console.error(
|
|
9661
|
+
console.error(chalk34.dim(" Scheduled time has already passed"));
|
|
9478
9662
|
} else {
|
|
9479
|
-
console.error(
|
|
9663
|
+
console.error(chalk34.dim(` ${error.message}`));
|
|
9480
9664
|
}
|
|
9481
9665
|
} else if (error instanceof Error) {
|
|
9482
|
-
console.error(
|
|
9666
|
+
console.error(chalk34.dim(` ${error.message}`));
|
|
9483
9667
|
}
|
|
9484
9668
|
console.log(
|
|
9485
|
-
` To enable manually: ${
|
|
9669
|
+
` To enable manually: ${chalk34.cyan(`vm0 schedule enable ${agentName}`)}`
|
|
9486
9670
|
);
|
|
9487
9671
|
}
|
|
9488
9672
|
}
|
|
9489
9673
|
function showEnableHint(agentName) {
|
|
9490
9674
|
console.log();
|
|
9491
|
-
console.log(` To enable: ${
|
|
9675
|
+
console.log(` To enable: ${chalk34.cyan(`vm0 schedule enable ${agentName}`)}`);
|
|
9492
9676
|
}
|
|
9493
9677
|
async function handleScheduleEnabling(params) {
|
|
9494
9678
|
const { scheduleName, composeId, agentName, enableFlag, shouldPromptEnable } = params;
|
|
@@ -9509,13 +9693,13 @@ async function handleScheduleEnabling(params) {
|
|
|
9509
9693
|
showEnableHint(agentName);
|
|
9510
9694
|
}
|
|
9511
9695
|
}
|
|
9512
|
-
var setupCommand = new
|
|
9696
|
+
var setupCommand = new Command31().name("setup").description("Create or edit a schedule for an agent").argument("<agent-name>", "Agent name to configure schedule for").option("-f, --frequency <type>", "Frequency: daily|weekly|monthly|once").option("-t, --time <HH:MM>", "Time to run (24-hour format)").option("-d, --day <day>", "Day of week (mon-sun) or day of month (1-31)").option("-z, --timezone <tz>", "IANA timezone").option("-p, --prompt <text>", "Prompt to run").option("--var <name=value>", "Variable (can be repeated)", collect, []).option("--secret <name=value>", "Secret (can be repeated)", collect, []).option("--artifact-name <name>", "Artifact name", "artifact").option("-e, --enable", "Enable schedule immediately after creation").action(async (agentName, options) => {
|
|
9513
9697
|
try {
|
|
9514
9698
|
const { composeId, scheduleName, composeContent } = await resolveAgent(agentName);
|
|
9515
9699
|
const requiredConfig = extractRequiredConfiguration(composeContent);
|
|
9516
9700
|
const existingSchedule = await findExistingSchedule(agentName);
|
|
9517
9701
|
console.log(
|
|
9518
|
-
|
|
9702
|
+
chalk34.dim(
|
|
9519
9703
|
existingSchedule ? `Editing existing schedule for agent ${agentName}` : `Creating new schedule for agent ${agentName}`
|
|
9520
9704
|
)
|
|
9521
9705
|
);
|
|
@@ -9525,12 +9709,12 @@ var setupCommand = new Command29().name("setup").description("Create or edit a s
|
|
|
9525
9709
|
defaults.frequency
|
|
9526
9710
|
);
|
|
9527
9711
|
if (!frequency) {
|
|
9528
|
-
console.log(
|
|
9712
|
+
console.log(chalk34.dim("Cancelled"));
|
|
9529
9713
|
return;
|
|
9530
9714
|
}
|
|
9531
9715
|
const timing = await gatherTiming(frequency, options, defaults);
|
|
9532
9716
|
if (!timing) {
|
|
9533
|
-
console.log(
|
|
9717
|
+
console.log(chalk34.dim("Cancelled"));
|
|
9534
9718
|
return;
|
|
9535
9719
|
}
|
|
9536
9720
|
const { day, time, atTime } = timing;
|
|
@@ -9539,7 +9723,7 @@ var setupCommand = new Command29().name("setup").description("Create or edit a s
|
|
|
9539
9723
|
existingSchedule?.timezone
|
|
9540
9724
|
);
|
|
9541
9725
|
if (!timezone) {
|
|
9542
|
-
console.log(
|
|
9726
|
+
console.log(chalk34.dim("Cancelled"));
|
|
9543
9727
|
return;
|
|
9544
9728
|
}
|
|
9545
9729
|
const promptText_ = await gatherPromptText(
|
|
@@ -9547,7 +9731,7 @@ var setupCommand = new Command29().name("setup").description("Create or edit a s
|
|
|
9547
9731
|
existingSchedule?.prompt
|
|
9548
9732
|
);
|
|
9549
9733
|
if (!promptText_) {
|
|
9550
|
-
console.log(
|
|
9734
|
+
console.log(chalk34.dim("Cancelled"));
|
|
9551
9735
|
return;
|
|
9552
9736
|
}
|
|
9553
9737
|
const config = await gatherConfiguration({
|
|
@@ -9585,15 +9769,15 @@ var setupCommand = new Command29().name("setup").description("Create or edit a s
|
|
|
9585
9769
|
});
|
|
9586
9770
|
|
|
9587
9771
|
// src/commands/schedule/list.ts
|
|
9588
|
-
import { Command as
|
|
9589
|
-
import
|
|
9590
|
-
var
|
|
9772
|
+
import { Command as Command32 } from "commander";
|
|
9773
|
+
import chalk35 from "chalk";
|
|
9774
|
+
var listCommand5 = new Command32().name("list").alias("ls").description("List all schedules").action(async () => {
|
|
9591
9775
|
try {
|
|
9592
9776
|
const result = await listSchedules();
|
|
9593
9777
|
if (result.schedules.length === 0) {
|
|
9594
|
-
console.log(
|
|
9778
|
+
console.log(chalk35.dim("No schedules found"));
|
|
9595
9779
|
console.log(
|
|
9596
|
-
|
|
9780
|
+
chalk35.dim(" Create one with: vm0 schedule setup <agent-name>")
|
|
9597
9781
|
);
|
|
9598
9782
|
return;
|
|
9599
9783
|
}
|
|
@@ -9613,10 +9797,10 @@ var listCommand4 = new Command30().name("list").alias("ls").description("List al
|
|
|
9613
9797
|
"STATUS".padEnd(8),
|
|
9614
9798
|
"NEXT RUN"
|
|
9615
9799
|
].join(" ");
|
|
9616
|
-
console.log(
|
|
9800
|
+
console.log(chalk35.dim(header));
|
|
9617
9801
|
for (const schedule of result.schedules) {
|
|
9618
9802
|
const trigger = schedule.cronExpression ? `${schedule.cronExpression} (${schedule.timezone})` : schedule.atTime || "-";
|
|
9619
|
-
const status = schedule.enabled ?
|
|
9803
|
+
const status = schedule.enabled ? chalk35.green("enabled") : chalk35.yellow("disabled");
|
|
9620
9804
|
const nextRun = schedule.enabled ? formatRelativeTime2(schedule.nextRunAt) : "-";
|
|
9621
9805
|
const row = [
|
|
9622
9806
|
schedule.composeName.padEnd(agentWidth),
|
|
@@ -9628,12 +9812,12 @@ var listCommand4 = new Command30().name("list").alias("ls").description("List al
|
|
|
9628
9812
|
console.log(row);
|
|
9629
9813
|
}
|
|
9630
9814
|
} catch (error) {
|
|
9631
|
-
console.error(
|
|
9815
|
+
console.error(chalk35.red("\u2717 Failed to list schedules"));
|
|
9632
9816
|
if (error instanceof Error) {
|
|
9633
9817
|
if (error.message.includes("Not authenticated")) {
|
|
9634
|
-
console.error(
|
|
9818
|
+
console.error(chalk35.dim(" Run: vm0 auth login"));
|
|
9635
9819
|
} else {
|
|
9636
|
-
console.error(
|
|
9820
|
+
console.error(chalk35.dim(` ${error.message}`));
|
|
9637
9821
|
}
|
|
9638
9822
|
}
|
|
9639
9823
|
process.exit(1);
|
|
@@ -9641,45 +9825,45 @@ var listCommand4 = new Command30().name("list").alias("ls").description("List al
|
|
|
9641
9825
|
});
|
|
9642
9826
|
|
|
9643
9827
|
// src/commands/schedule/status.ts
|
|
9644
|
-
import { Command as
|
|
9645
|
-
import
|
|
9828
|
+
import { Command as Command33 } from "commander";
|
|
9829
|
+
import chalk36 from "chalk";
|
|
9646
9830
|
function formatDateTimeStyled(dateStr) {
|
|
9647
|
-
if (!dateStr) return
|
|
9831
|
+
if (!dateStr) return chalk36.dim("-");
|
|
9648
9832
|
const formatted = formatDateTime(dateStr);
|
|
9649
|
-
return formatted.replace(/\(([^)]+)\)$/,
|
|
9833
|
+
return formatted.replace(/\(([^)]+)\)$/, chalk36.dim("($1)"));
|
|
9650
9834
|
}
|
|
9651
9835
|
function formatTrigger(schedule) {
|
|
9652
9836
|
if (schedule.cronExpression) {
|
|
9653
9837
|
return schedule.cronExpression;
|
|
9654
9838
|
}
|
|
9655
9839
|
if (schedule.atTime) {
|
|
9656
|
-
return `${schedule.atTime} ${
|
|
9840
|
+
return `${schedule.atTime} ${chalk36.dim("(one-time)")}`;
|
|
9657
9841
|
}
|
|
9658
|
-
return
|
|
9842
|
+
return chalk36.dim("-");
|
|
9659
9843
|
}
|
|
9660
|
-
function
|
|
9844
|
+
function formatRunStatus2(status) {
|
|
9661
9845
|
switch (status) {
|
|
9662
9846
|
case "completed":
|
|
9663
|
-
return
|
|
9847
|
+
return chalk36.green(status);
|
|
9664
9848
|
case "failed":
|
|
9665
9849
|
case "timeout":
|
|
9666
|
-
return
|
|
9850
|
+
return chalk36.red(status);
|
|
9667
9851
|
case "running":
|
|
9668
|
-
return
|
|
9852
|
+
return chalk36.blue(status);
|
|
9669
9853
|
case "pending":
|
|
9670
|
-
return
|
|
9854
|
+
return chalk36.yellow(status);
|
|
9671
9855
|
default:
|
|
9672
9856
|
return status;
|
|
9673
9857
|
}
|
|
9674
9858
|
}
|
|
9675
9859
|
function printRunConfiguration(schedule) {
|
|
9676
|
-
const statusText = schedule.enabled ?
|
|
9860
|
+
const statusText = schedule.enabled ? chalk36.green("enabled") : chalk36.yellow("disabled");
|
|
9677
9861
|
console.log(`${"Status:".padEnd(16)}${statusText}`);
|
|
9678
9862
|
console.log(
|
|
9679
|
-
`${"Agent:".padEnd(16)}${schedule.composeName} ${
|
|
9863
|
+
`${"Agent:".padEnd(16)}${schedule.composeName} ${chalk36.dim(`(${schedule.scopeSlug})`)}`
|
|
9680
9864
|
);
|
|
9681
9865
|
const promptPreview = schedule.prompt.length > 60 ? schedule.prompt.slice(0, 57) + "..." : schedule.prompt;
|
|
9682
|
-
console.log(`${"Prompt:".padEnd(16)}${
|
|
9866
|
+
console.log(`${"Prompt:".padEnd(16)}${chalk36.dim(promptPreview)}`);
|
|
9683
9867
|
if (schedule.vars && Object.keys(schedule.vars).length > 0) {
|
|
9684
9868
|
console.log(
|
|
9685
9869
|
`${"Variables:".padEnd(16)}${Object.keys(schedule.vars).join(", ")}`
|
|
@@ -9716,35 +9900,35 @@ async function printRecentRuns(name, composeId, limit) {
|
|
|
9716
9900
|
console.log();
|
|
9717
9901
|
console.log("Recent Runs:");
|
|
9718
9902
|
console.log(
|
|
9719
|
-
|
|
9903
|
+
chalk36.dim("RUN ID STATUS CREATED")
|
|
9720
9904
|
);
|
|
9721
9905
|
for (const run of runs) {
|
|
9722
9906
|
const id = run.id;
|
|
9723
|
-
const status =
|
|
9907
|
+
const status = formatRunStatus2(run.status).padEnd(10);
|
|
9724
9908
|
const created = formatDateTimeStyled(run.createdAt);
|
|
9725
9909
|
console.log(`${id} ${status} ${created}`);
|
|
9726
9910
|
}
|
|
9727
9911
|
}
|
|
9728
9912
|
} catch {
|
|
9729
9913
|
console.log();
|
|
9730
|
-
console.log(
|
|
9914
|
+
console.log(chalk36.dim("Recent Runs: (unable to fetch)"));
|
|
9731
9915
|
}
|
|
9732
9916
|
}
|
|
9733
9917
|
function handleStatusError(error, agentName) {
|
|
9734
|
-
console.error(
|
|
9918
|
+
console.error(chalk36.red("\u2717 Failed to get schedule status"));
|
|
9735
9919
|
if (error instanceof Error) {
|
|
9736
9920
|
if (error.message.includes("Not authenticated")) {
|
|
9737
|
-
console.error(
|
|
9921
|
+
console.error(chalk36.dim(" Run: vm0 auth login"));
|
|
9738
9922
|
} else if (error.message.includes("not found") || error.message.includes("Not found") || error.message.includes("No schedule found")) {
|
|
9739
|
-
console.error(
|
|
9740
|
-
console.error(
|
|
9923
|
+
console.error(chalk36.dim(` No schedule found for agent "${agentName}"`));
|
|
9924
|
+
console.error(chalk36.dim(" Run: vm0 schedule list"));
|
|
9741
9925
|
} else {
|
|
9742
|
-
console.error(
|
|
9926
|
+
console.error(chalk36.dim(` ${error.message}`));
|
|
9743
9927
|
}
|
|
9744
9928
|
}
|
|
9745
9929
|
process.exit(1);
|
|
9746
9930
|
}
|
|
9747
|
-
var statusCommand5 = new
|
|
9931
|
+
var statusCommand5 = new Command33().name("status").description("Show detailed status of a schedule").argument("<agent-name>", "Agent name").option(
|
|
9748
9932
|
"-l, --limit <number>",
|
|
9749
9933
|
"Number of recent runs to show (0 to hide)",
|
|
9750
9934
|
"5"
|
|
@@ -9754,8 +9938,8 @@ var statusCommand5 = new Command31().name("status").description("Show detailed s
|
|
|
9754
9938
|
const { name, composeId } = resolved;
|
|
9755
9939
|
const schedule = await getScheduleByName({ name, composeId });
|
|
9756
9940
|
console.log();
|
|
9757
|
-
console.log(`Schedule for agent: ${
|
|
9758
|
-
console.log(
|
|
9941
|
+
console.log(`Schedule for agent: ${chalk36.cyan(agentName)}`);
|
|
9942
|
+
console.log(chalk36.dim("\u2501".repeat(50)));
|
|
9759
9943
|
printRunConfiguration(schedule);
|
|
9760
9944
|
printTimeSchedule(schedule);
|
|
9761
9945
|
const limit = Math.min(
|
|
@@ -9770,24 +9954,24 @@ var statusCommand5 = new Command31().name("status").description("Show detailed s
|
|
|
9770
9954
|
});
|
|
9771
9955
|
|
|
9772
9956
|
// src/commands/schedule/delete.ts
|
|
9773
|
-
import { Command as
|
|
9774
|
-
import
|
|
9775
|
-
var deleteCommand = new
|
|
9957
|
+
import { Command as Command34 } from "commander";
|
|
9958
|
+
import chalk37 from "chalk";
|
|
9959
|
+
var deleteCommand = new Command34().name("delete").alias("rm").description("Delete a schedule").argument("<agent-name>", "Agent name").option("-f, --force", "Skip confirmation prompt").action(async (agentName, options) => {
|
|
9776
9960
|
try {
|
|
9777
9961
|
const resolved = await resolveScheduleByAgent(agentName);
|
|
9778
9962
|
if (!options.force) {
|
|
9779
9963
|
if (!isInteractive()) {
|
|
9780
9964
|
console.error(
|
|
9781
|
-
|
|
9965
|
+
chalk37.red("\u2717 --force required in non-interactive mode")
|
|
9782
9966
|
);
|
|
9783
9967
|
process.exit(1);
|
|
9784
9968
|
}
|
|
9785
9969
|
const confirmed = await promptConfirm(
|
|
9786
|
-
`Delete schedule for agent ${
|
|
9970
|
+
`Delete schedule for agent ${chalk37.cyan(agentName)}?`,
|
|
9787
9971
|
false
|
|
9788
9972
|
);
|
|
9789
9973
|
if (!confirmed) {
|
|
9790
|
-
console.log(
|
|
9974
|
+
console.log(chalk37.dim("Cancelled"));
|
|
9791
9975
|
return;
|
|
9792
9976
|
}
|
|
9793
9977
|
}
|
|
@@ -9796,20 +9980,20 @@ var deleteCommand = new Command32().name("delete").alias("rm").description("Dele
|
|
|
9796
9980
|
composeId: resolved.composeId
|
|
9797
9981
|
});
|
|
9798
9982
|
console.log(
|
|
9799
|
-
|
|
9983
|
+
chalk37.green(`\u2713 Deleted schedule for agent ${chalk37.cyan(agentName)}`)
|
|
9800
9984
|
);
|
|
9801
9985
|
} catch (error) {
|
|
9802
|
-
console.error(
|
|
9986
|
+
console.error(chalk37.red("\u2717 Failed to delete schedule"));
|
|
9803
9987
|
if (error instanceof Error) {
|
|
9804
9988
|
if (error.message.includes("Not authenticated")) {
|
|
9805
|
-
console.error(
|
|
9989
|
+
console.error(chalk37.dim(" Run: vm0 auth login"));
|
|
9806
9990
|
} else if (error.message.toLowerCase().includes("not found") || error.message.includes("No schedule found")) {
|
|
9807
9991
|
console.error(
|
|
9808
|
-
|
|
9992
|
+
chalk37.dim(` No schedule found for agent "${agentName}"`)
|
|
9809
9993
|
);
|
|
9810
|
-
console.error(
|
|
9994
|
+
console.error(chalk37.dim(" Run: vm0 schedule list"));
|
|
9811
9995
|
} else {
|
|
9812
|
-
console.error(
|
|
9996
|
+
console.error(chalk37.dim(` ${error.message}`));
|
|
9813
9997
|
}
|
|
9814
9998
|
}
|
|
9815
9999
|
process.exit(1);
|
|
@@ -9817,9 +10001,9 @@ var deleteCommand = new Command32().name("delete").alias("rm").description("Dele
|
|
|
9817
10001
|
});
|
|
9818
10002
|
|
|
9819
10003
|
// src/commands/schedule/enable.ts
|
|
9820
|
-
import { Command as
|
|
9821
|
-
import
|
|
9822
|
-
var enableCommand = new
|
|
10004
|
+
import { Command as Command35 } from "commander";
|
|
10005
|
+
import chalk38 from "chalk";
|
|
10006
|
+
var enableCommand = new Command35().name("enable").description("Enable a schedule").argument("<agent-name>", "Agent name").action(async (agentName) => {
|
|
9823
10007
|
try {
|
|
9824
10008
|
const resolved = await resolveScheduleByAgent(agentName);
|
|
9825
10009
|
await enableSchedule({
|
|
@@ -9827,34 +10011,34 @@ var enableCommand = new Command33().name("enable").description("Enable a schedul
|
|
|
9827
10011
|
composeId: resolved.composeId
|
|
9828
10012
|
});
|
|
9829
10013
|
console.log(
|
|
9830
|
-
|
|
10014
|
+
chalk38.green(`\u2713 Enabled schedule for agent ${chalk38.cyan(agentName)}`)
|
|
9831
10015
|
);
|
|
9832
10016
|
} catch (error) {
|
|
9833
|
-
console.error(
|
|
10017
|
+
console.error(chalk38.red("\u2717 Failed to enable schedule"));
|
|
9834
10018
|
if (error instanceof ApiRequestError) {
|
|
9835
10019
|
if (error.code === "SCHEDULE_PAST") {
|
|
9836
|
-
console.error(
|
|
9837
|
-
console.error(
|
|
10020
|
+
console.error(chalk38.dim(" Scheduled time has already passed"));
|
|
10021
|
+
console.error(chalk38.dim(` Run: vm0 schedule setup ${agentName}`));
|
|
9838
10022
|
} else if (error.code === "NOT_FOUND") {
|
|
9839
10023
|
console.error(
|
|
9840
|
-
|
|
10024
|
+
chalk38.dim(` No schedule found for agent "${agentName}"`)
|
|
9841
10025
|
);
|
|
9842
|
-
console.error(
|
|
10026
|
+
console.error(chalk38.dim(" Run: vm0 schedule list"));
|
|
9843
10027
|
} else if (error.code === "UNAUTHORIZED") {
|
|
9844
|
-
console.error(
|
|
10028
|
+
console.error(chalk38.dim(" Run: vm0 auth login"));
|
|
9845
10029
|
} else {
|
|
9846
|
-
console.error(
|
|
10030
|
+
console.error(chalk38.dim(` ${error.message}`));
|
|
9847
10031
|
}
|
|
9848
10032
|
} else if (error instanceof Error) {
|
|
9849
10033
|
if (error.message.includes("Not authenticated")) {
|
|
9850
|
-
console.error(
|
|
10034
|
+
console.error(chalk38.dim(" Run: vm0 auth login"));
|
|
9851
10035
|
} else if (error.message.includes("No schedule found")) {
|
|
9852
10036
|
console.error(
|
|
9853
|
-
|
|
10037
|
+
chalk38.dim(` No schedule found for agent "${agentName}"`)
|
|
9854
10038
|
);
|
|
9855
|
-
console.error(
|
|
10039
|
+
console.error(chalk38.dim(" Run: vm0 schedule list"));
|
|
9856
10040
|
} else {
|
|
9857
|
-
console.error(
|
|
10041
|
+
console.error(chalk38.dim(` ${error.message}`));
|
|
9858
10042
|
}
|
|
9859
10043
|
}
|
|
9860
10044
|
process.exit(1);
|
|
@@ -9862,9 +10046,9 @@ var enableCommand = new Command33().name("enable").description("Enable a schedul
|
|
|
9862
10046
|
});
|
|
9863
10047
|
|
|
9864
10048
|
// src/commands/schedule/disable.ts
|
|
9865
|
-
import { Command as
|
|
9866
|
-
import
|
|
9867
|
-
var disableCommand = new
|
|
10049
|
+
import { Command as Command36 } from "commander";
|
|
10050
|
+
import chalk39 from "chalk";
|
|
10051
|
+
var disableCommand = new Command36().name("disable").description("Disable a schedule").argument("<agent-name>", "Agent name").action(async (agentName) => {
|
|
9868
10052
|
try {
|
|
9869
10053
|
const resolved = await resolveScheduleByAgent(agentName);
|
|
9870
10054
|
await disableSchedule({
|
|
@@ -9872,20 +10056,20 @@ var disableCommand = new Command34().name("disable").description("Disable a sche
|
|
|
9872
10056
|
composeId: resolved.composeId
|
|
9873
10057
|
});
|
|
9874
10058
|
console.log(
|
|
9875
|
-
|
|
10059
|
+
chalk39.green(`\u2713 Disabled schedule for agent ${chalk39.cyan(agentName)}`)
|
|
9876
10060
|
);
|
|
9877
10061
|
} catch (error) {
|
|
9878
|
-
console.error(
|
|
10062
|
+
console.error(chalk39.red("\u2717 Failed to disable schedule"));
|
|
9879
10063
|
if (error instanceof Error) {
|
|
9880
10064
|
if (error.message.includes("Not authenticated")) {
|
|
9881
|
-
console.error(
|
|
10065
|
+
console.error(chalk39.dim(" Run: vm0 auth login"));
|
|
9882
10066
|
} else if (error.message.toLowerCase().includes("not found") || error.message.includes("No schedule found")) {
|
|
9883
10067
|
console.error(
|
|
9884
|
-
|
|
10068
|
+
chalk39.dim(` No schedule found for agent "${agentName}"`)
|
|
9885
10069
|
);
|
|
9886
|
-
console.error(
|
|
10070
|
+
console.error(chalk39.dim(" Run: vm0 schedule list"));
|
|
9887
10071
|
} else {
|
|
9888
|
-
console.error(
|
|
10072
|
+
console.error(chalk39.dim(` ${error.message}`));
|
|
9889
10073
|
}
|
|
9890
10074
|
}
|
|
9891
10075
|
process.exit(1);
|
|
@@ -9893,11 +10077,11 @@ var disableCommand = new Command34().name("disable").description("Disable a sche
|
|
|
9893
10077
|
});
|
|
9894
10078
|
|
|
9895
10079
|
// src/commands/schedule/index.ts
|
|
9896
|
-
var scheduleCommand = new
|
|
10080
|
+
var scheduleCommand = new Command37().name("schedule").description("Manage agent schedules").addCommand(setupCommand).addCommand(listCommand5).addCommand(statusCommand5).addCommand(deleteCommand).addCommand(enableCommand).addCommand(disableCommand);
|
|
9897
10081
|
|
|
9898
10082
|
// src/commands/usage.ts
|
|
9899
|
-
import { Command as
|
|
9900
|
-
import
|
|
10083
|
+
import { Command as Command38 } from "commander";
|
|
10084
|
+
import chalk40 from "chalk";
|
|
9901
10085
|
|
|
9902
10086
|
// src/lib/utils/duration-formatter.ts
|
|
9903
10087
|
function formatDuration(ms) {
|
|
@@ -9970,7 +10154,7 @@ function fillMissingDates(daily, startDate, endDate) {
|
|
|
9970
10154
|
result.sort((a, b) => b.date.localeCompare(a.date));
|
|
9971
10155
|
return result;
|
|
9972
10156
|
}
|
|
9973
|
-
var usageCommand = new
|
|
10157
|
+
var usageCommand = new Command38().name("usage").description("View usage statistics").option("--since <date>", "Start date (ISO format or relative: 7d, 30d)").option(
|
|
9974
10158
|
"--until <date>",
|
|
9975
10159
|
"End date (ISO format or relative, defaults to now)"
|
|
9976
10160
|
).action(async (options) => {
|
|
@@ -9984,7 +10168,7 @@ var usageCommand = new Command36().name("usage").description("View usage statist
|
|
|
9984
10168
|
endDate = new Date(untilMs);
|
|
9985
10169
|
} catch {
|
|
9986
10170
|
console.error(
|
|
9987
|
-
|
|
10171
|
+
chalk40.red(
|
|
9988
10172
|
"\u2717 Invalid --until format. Use ISO (2026-01-01) or relative (7d, 30d)"
|
|
9989
10173
|
)
|
|
9990
10174
|
);
|
|
@@ -9999,7 +10183,7 @@ var usageCommand = new Command36().name("usage").description("View usage statist
|
|
|
9999
10183
|
startDate = new Date(sinceMs);
|
|
10000
10184
|
} catch {
|
|
10001
10185
|
console.error(
|
|
10002
|
-
|
|
10186
|
+
chalk40.red(
|
|
10003
10187
|
"\u2717 Invalid --since format. Use ISO (2026-01-01) or relative (7d, 30d)"
|
|
10004
10188
|
)
|
|
10005
10189
|
);
|
|
@@ -10009,13 +10193,13 @@ var usageCommand = new Command36().name("usage").description("View usage statist
|
|
|
10009
10193
|
startDate = new Date(endDate.getTime() - DEFAULT_RANGE_MS);
|
|
10010
10194
|
}
|
|
10011
10195
|
if (startDate >= endDate) {
|
|
10012
|
-
console.error(
|
|
10196
|
+
console.error(chalk40.red("\u2717 --since must be before --until"));
|
|
10013
10197
|
process.exit(1);
|
|
10014
10198
|
}
|
|
10015
10199
|
const rangeMs = endDate.getTime() - startDate.getTime();
|
|
10016
10200
|
if (rangeMs > MAX_RANGE_MS) {
|
|
10017
10201
|
console.error(
|
|
10018
|
-
|
|
10202
|
+
chalk40.red(
|
|
10019
10203
|
"\u2717 Time range exceeds maximum of 30 days. Use --until to specify an end date"
|
|
10020
10204
|
)
|
|
10021
10205
|
);
|
|
@@ -10032,19 +10216,19 @@ var usageCommand = new Command36().name("usage").description("View usage statist
|
|
|
10032
10216
|
);
|
|
10033
10217
|
console.log();
|
|
10034
10218
|
console.log(
|
|
10035
|
-
|
|
10219
|
+
chalk40.bold(
|
|
10036
10220
|
`Usage Summary (${formatDateRange(usage.period.start, usage.period.end)})`
|
|
10037
10221
|
)
|
|
10038
10222
|
);
|
|
10039
10223
|
console.log();
|
|
10040
|
-
console.log(
|
|
10224
|
+
console.log(chalk40.dim("DATE RUNS RUN TIME"));
|
|
10041
10225
|
for (const day of filledDaily) {
|
|
10042
10226
|
const dateDisplay = formatDateDisplay(day.date).padEnd(10);
|
|
10043
10227
|
const runsDisplay = String(day.run_count).padStart(6);
|
|
10044
10228
|
const timeDisplay = formatDuration(day.run_time_ms);
|
|
10045
10229
|
console.log(`${dateDisplay}${runsDisplay} ${timeDisplay}`);
|
|
10046
10230
|
}
|
|
10047
|
-
console.log(
|
|
10231
|
+
console.log(chalk40.dim("\u2500".repeat(29)));
|
|
10048
10232
|
const totalRunsDisplay = String(usage.summary.total_runs).padStart(6);
|
|
10049
10233
|
const totalTimeDisplay = formatDuration(usage.summary.total_run_time_ms);
|
|
10050
10234
|
console.log(
|
|
@@ -10054,68 +10238,68 @@ var usageCommand = new Command36().name("usage").description("View usage statist
|
|
|
10054
10238
|
} catch (error) {
|
|
10055
10239
|
if (error instanceof Error) {
|
|
10056
10240
|
if (error.message.includes("Not authenticated")) {
|
|
10057
|
-
console.error(
|
|
10058
|
-
console.error(
|
|
10241
|
+
console.error(chalk40.red("\u2717 Not authenticated"));
|
|
10242
|
+
console.error(chalk40.dim(" Run: vm0 auth login"));
|
|
10059
10243
|
} else {
|
|
10060
|
-
console.error(
|
|
10244
|
+
console.error(chalk40.red(`\u2717 ${error.message}`));
|
|
10061
10245
|
}
|
|
10062
10246
|
} else {
|
|
10063
|
-
console.error(
|
|
10247
|
+
console.error(chalk40.red("\u2717 An unexpected error occurred"));
|
|
10064
10248
|
}
|
|
10065
10249
|
process.exit(1);
|
|
10066
10250
|
}
|
|
10067
10251
|
});
|
|
10068
10252
|
|
|
10069
10253
|
// src/commands/credential/index.ts
|
|
10070
|
-
import { Command as
|
|
10254
|
+
import { Command as Command42 } from "commander";
|
|
10071
10255
|
|
|
10072
10256
|
// src/commands/credential/list.ts
|
|
10073
|
-
import { Command as
|
|
10074
|
-
import
|
|
10075
|
-
var
|
|
10257
|
+
import { Command as Command39 } from "commander";
|
|
10258
|
+
import chalk41 from "chalk";
|
|
10259
|
+
var listCommand6 = new Command39().name("list").alias("ls").description("List all credentials").action(async () => {
|
|
10076
10260
|
try {
|
|
10077
10261
|
const result = await listCredentials();
|
|
10078
10262
|
if (result.credentials.length === 0) {
|
|
10079
|
-
console.log(
|
|
10263
|
+
console.log(chalk41.dim("No credentials found"));
|
|
10080
10264
|
console.log();
|
|
10081
10265
|
console.log("To add a credential:");
|
|
10082
|
-
console.log(
|
|
10266
|
+
console.log(chalk41.cyan(" vm0 credential set MY_API_KEY <value>"));
|
|
10083
10267
|
return;
|
|
10084
10268
|
}
|
|
10085
|
-
console.log(
|
|
10269
|
+
console.log(chalk41.bold("Credentials:"));
|
|
10086
10270
|
console.log();
|
|
10087
10271
|
for (const credential of result.credentials) {
|
|
10088
|
-
const typeIndicator = credential.type === "model-provider" ?
|
|
10089
|
-
console.log(` ${
|
|
10272
|
+
const typeIndicator = credential.type === "model-provider" ? chalk41.dim(" [model-provider]") : "";
|
|
10273
|
+
console.log(` ${chalk41.cyan(credential.name)}${typeIndicator}`);
|
|
10090
10274
|
if (credential.description) {
|
|
10091
|
-
console.log(` ${
|
|
10275
|
+
console.log(` ${chalk41.dim(credential.description)}`);
|
|
10092
10276
|
}
|
|
10093
10277
|
console.log(
|
|
10094
|
-
` ${
|
|
10278
|
+
` ${chalk41.dim(`Updated: ${new Date(credential.updatedAt).toLocaleString()}`)}`
|
|
10095
10279
|
);
|
|
10096
10280
|
console.log();
|
|
10097
10281
|
}
|
|
10098
10282
|
console.log(
|
|
10099
|
-
|
|
10283
|
+
chalk41.dim(`Total: ${result.credentials.length} credential(s)`)
|
|
10100
10284
|
);
|
|
10101
10285
|
} catch (error) {
|
|
10102
10286
|
if (error instanceof Error) {
|
|
10103
10287
|
if (error.message.includes("Not authenticated")) {
|
|
10104
|
-
console.error(
|
|
10288
|
+
console.error(chalk41.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
10105
10289
|
} else {
|
|
10106
|
-
console.error(
|
|
10290
|
+
console.error(chalk41.red(`\u2717 ${error.message}`));
|
|
10107
10291
|
}
|
|
10108
10292
|
} else {
|
|
10109
|
-
console.error(
|
|
10293
|
+
console.error(chalk41.red("\u2717 An unexpected error occurred"));
|
|
10110
10294
|
}
|
|
10111
10295
|
process.exit(1);
|
|
10112
10296
|
}
|
|
10113
10297
|
});
|
|
10114
10298
|
|
|
10115
10299
|
// src/commands/credential/set.ts
|
|
10116
|
-
import { Command as
|
|
10117
|
-
import
|
|
10118
|
-
var setCommand2 = new
|
|
10300
|
+
import { Command as Command40 } from "commander";
|
|
10301
|
+
import chalk42 from "chalk";
|
|
10302
|
+
var setCommand2 = new Command40().name("set").description("Create or update a credential").argument("<name>", "Credential name (uppercase, e.g., MY_API_KEY)").argument("<value>", "Credential value").option("-d, --description <description>", "Optional description").action(
|
|
10119
10303
|
async (name, value, options) => {
|
|
10120
10304
|
try {
|
|
10121
10305
|
const credential = await setCredential({
|
|
@@ -10123,29 +10307,29 @@ var setCommand2 = new Command38().name("set").description("Create or update a cr
|
|
|
10123
10307
|
value,
|
|
10124
10308
|
description: options.description
|
|
10125
10309
|
});
|
|
10126
|
-
console.log(
|
|
10310
|
+
console.log(chalk42.green(`\u2713 Credential "${credential.name}" saved`));
|
|
10127
10311
|
console.log();
|
|
10128
10312
|
console.log("Use in vm0.yaml:");
|
|
10129
|
-
console.log(
|
|
10130
|
-
console.log(
|
|
10313
|
+
console.log(chalk42.cyan(` environment:`));
|
|
10314
|
+
console.log(chalk42.cyan(` ${name}: \${{ credentials.${name} }}`));
|
|
10131
10315
|
} catch (error) {
|
|
10132
10316
|
if (error instanceof Error) {
|
|
10133
10317
|
if (error.message.includes("Not authenticated")) {
|
|
10134
10318
|
console.error(
|
|
10135
|
-
|
|
10319
|
+
chalk42.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
10136
10320
|
);
|
|
10137
10321
|
} else if (error.message.includes("must contain only uppercase")) {
|
|
10138
|
-
console.error(
|
|
10322
|
+
console.error(chalk42.red(`\u2717 ${error.message}`));
|
|
10139
10323
|
console.log();
|
|
10140
10324
|
console.log("Examples of valid credential names:");
|
|
10141
|
-
console.log(
|
|
10142
|
-
console.log(
|
|
10143
|
-
console.log(
|
|
10325
|
+
console.log(chalk42.dim(" MY_API_KEY"));
|
|
10326
|
+
console.log(chalk42.dim(" GITHUB_TOKEN"));
|
|
10327
|
+
console.log(chalk42.dim(" AWS_ACCESS_KEY_ID"));
|
|
10144
10328
|
} else {
|
|
10145
|
-
console.error(
|
|
10329
|
+
console.error(chalk42.red(`\u2717 ${error.message}`));
|
|
10146
10330
|
}
|
|
10147
10331
|
} else {
|
|
10148
|
-
console.error(
|
|
10332
|
+
console.error(chalk42.red("\u2717 An unexpected error occurred"));
|
|
10149
10333
|
}
|
|
10150
10334
|
process.exit(1);
|
|
10151
10335
|
}
|
|
@@ -10153,20 +10337,20 @@ var setCommand2 = new Command38().name("set").description("Create or update a cr
|
|
|
10153
10337
|
);
|
|
10154
10338
|
|
|
10155
10339
|
// src/commands/credential/delete.ts
|
|
10156
|
-
import { Command as
|
|
10157
|
-
import
|
|
10158
|
-
var deleteCommand2 = new
|
|
10340
|
+
import { Command as Command41 } from "commander";
|
|
10341
|
+
import chalk43 from "chalk";
|
|
10342
|
+
var deleteCommand2 = new Command41().name("delete").description("Delete a credential").argument("<name>", "Credential name to delete").option("-y, --yes", "Skip confirmation prompt").action(async (name, options) => {
|
|
10159
10343
|
try {
|
|
10160
10344
|
try {
|
|
10161
10345
|
await getCredential(name);
|
|
10162
10346
|
} catch {
|
|
10163
|
-
console.error(
|
|
10347
|
+
console.error(chalk43.red(`\u2717 Credential "${name}" not found`));
|
|
10164
10348
|
process.exit(1);
|
|
10165
10349
|
}
|
|
10166
10350
|
if (!options.yes) {
|
|
10167
10351
|
if (!isInteractive()) {
|
|
10168
10352
|
console.error(
|
|
10169
|
-
|
|
10353
|
+
chalk43.red("\u2717 --yes flag is required in non-interactive mode")
|
|
10170
10354
|
);
|
|
10171
10355
|
process.exit(1);
|
|
10172
10356
|
}
|
|
@@ -10175,43 +10359,43 @@ var deleteCommand2 = new Command39().name("delete").description("Delete a creden
|
|
|
10175
10359
|
false
|
|
10176
10360
|
);
|
|
10177
10361
|
if (!confirmed) {
|
|
10178
|
-
console.log(
|
|
10362
|
+
console.log(chalk43.dim("Cancelled"));
|
|
10179
10363
|
return;
|
|
10180
10364
|
}
|
|
10181
10365
|
}
|
|
10182
10366
|
await deleteCredential(name);
|
|
10183
|
-
console.log(
|
|
10367
|
+
console.log(chalk43.green(`\u2713 Credential "${name}" deleted`));
|
|
10184
10368
|
} catch (error) {
|
|
10185
10369
|
if (error instanceof Error) {
|
|
10186
10370
|
if (error.message.includes("Not authenticated")) {
|
|
10187
|
-
console.error(
|
|
10371
|
+
console.error(chalk43.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
10188
10372
|
} else {
|
|
10189
|
-
console.error(
|
|
10373
|
+
console.error(chalk43.red(`\u2717 ${error.message}`));
|
|
10190
10374
|
}
|
|
10191
10375
|
} else {
|
|
10192
|
-
console.error(
|
|
10376
|
+
console.error(chalk43.red("\u2717 An unexpected error occurred"));
|
|
10193
10377
|
}
|
|
10194
10378
|
process.exit(1);
|
|
10195
10379
|
}
|
|
10196
10380
|
});
|
|
10197
10381
|
|
|
10198
10382
|
// src/commands/credential/index.ts
|
|
10199
|
-
var credentialCommand = new
|
|
10383
|
+
var credentialCommand = new Command42().name("credential").description("Manage stored credentials for agent runs").addCommand(listCommand6).addCommand(setCommand2).addCommand(deleteCommand2);
|
|
10200
10384
|
|
|
10201
10385
|
// src/commands/model-provider/index.ts
|
|
10202
|
-
import { Command as
|
|
10386
|
+
import { Command as Command47 } from "commander";
|
|
10203
10387
|
|
|
10204
10388
|
// src/commands/model-provider/list.ts
|
|
10205
|
-
import { Command as
|
|
10206
|
-
import
|
|
10207
|
-
var
|
|
10389
|
+
import { Command as Command43 } from "commander";
|
|
10390
|
+
import chalk44 from "chalk";
|
|
10391
|
+
var listCommand7 = new Command43().name("list").alias("ls").description("List all model providers").action(async () => {
|
|
10208
10392
|
try {
|
|
10209
10393
|
const result = await listModelProviders();
|
|
10210
10394
|
if (result.modelProviders.length === 0) {
|
|
10211
|
-
console.log(
|
|
10395
|
+
console.log(chalk44.dim("No model providers configured"));
|
|
10212
10396
|
console.log();
|
|
10213
10397
|
console.log("To add a model provider:");
|
|
10214
|
-
console.log(
|
|
10398
|
+
console.log(chalk44.cyan(" vm0 model-provider setup"));
|
|
10215
10399
|
return;
|
|
10216
10400
|
}
|
|
10217
10401
|
const byFramework = result.modelProviders.reduce(
|
|
@@ -10225,15 +10409,15 @@ var listCommand6 = new Command41().name("list").alias("ls").description("List al
|
|
|
10225
10409
|
},
|
|
10226
10410
|
{}
|
|
10227
10411
|
);
|
|
10228
|
-
console.log(
|
|
10412
|
+
console.log(chalk44.bold("Model Providers:"));
|
|
10229
10413
|
console.log();
|
|
10230
10414
|
for (const [framework, providers] of Object.entries(byFramework)) {
|
|
10231
|
-
console.log(` ${
|
|
10415
|
+
console.log(` ${chalk44.cyan(framework)}:`);
|
|
10232
10416
|
for (const provider of providers) {
|
|
10233
|
-
const defaultTag = provider.isDefault ?
|
|
10417
|
+
const defaultTag = provider.isDefault ? chalk44.green(" (default)") : "";
|
|
10234
10418
|
console.log(` ${provider.type}${defaultTag}`);
|
|
10235
10419
|
console.log(
|
|
10236
|
-
|
|
10420
|
+
chalk44.dim(
|
|
10237
10421
|
` Updated: ${new Date(provider.updatedAt).toLocaleString()}`
|
|
10238
10422
|
)
|
|
10239
10423
|
);
|
|
@@ -10241,25 +10425,25 @@ var listCommand6 = new Command41().name("list").alias("ls").description("List al
|
|
|
10241
10425
|
console.log();
|
|
10242
10426
|
}
|
|
10243
10427
|
console.log(
|
|
10244
|
-
|
|
10428
|
+
chalk44.dim(`Total: ${result.modelProviders.length} provider(s)`)
|
|
10245
10429
|
);
|
|
10246
10430
|
} catch (error) {
|
|
10247
10431
|
if (error instanceof Error) {
|
|
10248
10432
|
if (error.message.includes("Not authenticated")) {
|
|
10249
|
-
console.error(
|
|
10433
|
+
console.error(chalk44.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
10250
10434
|
} else {
|
|
10251
|
-
console.error(
|
|
10435
|
+
console.error(chalk44.red(`\u2717 ${error.message}`));
|
|
10252
10436
|
}
|
|
10253
10437
|
} else {
|
|
10254
|
-
console.error(
|
|
10438
|
+
console.error(chalk44.red("\u2717 An unexpected error occurred"));
|
|
10255
10439
|
}
|
|
10256
10440
|
process.exit(1);
|
|
10257
10441
|
}
|
|
10258
10442
|
});
|
|
10259
10443
|
|
|
10260
10444
|
// src/commands/model-provider/setup.ts
|
|
10261
|
-
import { Command as
|
|
10262
|
-
import
|
|
10445
|
+
import { Command as Command44 } from "commander";
|
|
10446
|
+
import chalk45 from "chalk";
|
|
10263
10447
|
import prompts2 from "prompts";
|
|
10264
10448
|
var providerChoices = Object.entries(MODEL_PROVIDER_TYPES).map(
|
|
10265
10449
|
([type, config]) => ({
|
|
@@ -10267,7 +10451,7 @@ var providerChoices = Object.entries(MODEL_PROVIDER_TYPES).map(
|
|
|
10267
10451
|
value: type
|
|
10268
10452
|
})
|
|
10269
10453
|
);
|
|
10270
|
-
var setupCommand2 = new
|
|
10454
|
+
var setupCommand2 = new Command44().name("setup").description("Configure a model provider").option("-t, --type <type>", "Provider type (for non-interactive mode)").option(
|
|
10271
10455
|
"-c, --credential <credential>",
|
|
10272
10456
|
"Credential value (for non-interactive mode)"
|
|
10273
10457
|
).option("--convert", "Convert existing user credential to model provider").action(
|
|
@@ -10278,11 +10462,11 @@ var setupCommand2 = new Command42().name("setup").description("Configure a model
|
|
|
10278
10462
|
const shouldConvert = options.convert ?? false;
|
|
10279
10463
|
if (options.type && options.credential) {
|
|
10280
10464
|
if (!Object.keys(MODEL_PROVIDER_TYPES).includes(options.type)) {
|
|
10281
|
-
console.error(
|
|
10465
|
+
console.error(chalk45.red(`\u2717 Invalid type "${options.type}"`));
|
|
10282
10466
|
console.log();
|
|
10283
10467
|
console.log("Valid types:");
|
|
10284
10468
|
for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
|
|
10285
|
-
console.log(` ${
|
|
10469
|
+
console.log(` ${chalk45.cyan(t)} - ${config.label}`);
|
|
10286
10470
|
}
|
|
10287
10471
|
process.exit(1);
|
|
10288
10472
|
}
|
|
@@ -10290,16 +10474,16 @@ var setupCommand2 = new Command42().name("setup").description("Configure a model
|
|
|
10290
10474
|
credential = options.credential;
|
|
10291
10475
|
} else if (options.type || options.credential) {
|
|
10292
10476
|
console.error(
|
|
10293
|
-
|
|
10477
|
+
chalk45.red("\u2717 Both --type and --credential are required")
|
|
10294
10478
|
);
|
|
10295
10479
|
process.exit(1);
|
|
10296
10480
|
} else {
|
|
10297
10481
|
if (!isInteractive()) {
|
|
10298
|
-
console.error(
|
|
10482
|
+
console.error(chalk45.red("\u2717 Interactive mode requires a TTY"));
|
|
10299
10483
|
console.log();
|
|
10300
10484
|
console.log("Use non-interactive mode:");
|
|
10301
10485
|
console.log(
|
|
10302
|
-
|
|
10486
|
+
chalk45.cyan(
|
|
10303
10487
|
' vm0 model-provider setup --type <type> --credential "<value>"'
|
|
10304
10488
|
)
|
|
10305
10489
|
);
|
|
@@ -10330,19 +10514,19 @@ var setupCommand2 = new Command42().name("setup").description("Configure a model
|
|
|
10330
10514
|
const provider2 = await convertModelProviderCredential(type);
|
|
10331
10515
|
const defaultNote2 = provider2.isDefault ? ` (default for ${provider2.framework})` : "";
|
|
10332
10516
|
console.log(
|
|
10333
|
-
|
|
10517
|
+
chalk45.green(
|
|
10334
10518
|
`\u2713 Converted "${checkResult.credentialName}" to model provider${defaultNote2}`
|
|
10335
10519
|
)
|
|
10336
10520
|
);
|
|
10337
10521
|
return;
|
|
10338
10522
|
} else {
|
|
10339
|
-
console.log(
|
|
10523
|
+
console.log(chalk45.dim("Aborted"));
|
|
10340
10524
|
process.exit(0);
|
|
10341
10525
|
}
|
|
10342
10526
|
}
|
|
10343
10527
|
const config = MODEL_PROVIDER_TYPES[type];
|
|
10344
10528
|
console.log();
|
|
10345
|
-
console.log(
|
|
10529
|
+
console.log(chalk45.dim(config.helpText));
|
|
10346
10530
|
console.log();
|
|
10347
10531
|
const credentialResponse = await prompts2(
|
|
10348
10532
|
{
|
|
@@ -10363,24 +10547,24 @@ var setupCommand2 = new Command42().name("setup").description("Configure a model
|
|
|
10363
10547
|
const action = created ? "created" : "updated";
|
|
10364
10548
|
const defaultNote = provider.isDefault ? ` (default for ${provider.framework})` : "";
|
|
10365
10549
|
console.log(
|
|
10366
|
-
|
|
10550
|
+
chalk45.green(`\u2713 Model provider "${type}" ${action}${defaultNote}`)
|
|
10367
10551
|
);
|
|
10368
10552
|
} catch (error) {
|
|
10369
10553
|
if (error instanceof Error) {
|
|
10370
10554
|
if (error.message.includes("already exists")) {
|
|
10371
|
-
console.error(
|
|
10555
|
+
console.error(chalk45.red(`\u2717 ${error.message}`));
|
|
10372
10556
|
console.log();
|
|
10373
10557
|
console.log("To convert the existing credential, run:");
|
|
10374
|
-
console.log(
|
|
10558
|
+
console.log(chalk45.cyan(" vm0 model-provider setup --convert"));
|
|
10375
10559
|
} else if (error.message.includes("Not authenticated")) {
|
|
10376
10560
|
console.error(
|
|
10377
|
-
|
|
10561
|
+
chalk45.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
10378
10562
|
);
|
|
10379
10563
|
} else {
|
|
10380
|
-
console.error(
|
|
10564
|
+
console.error(chalk45.red(`\u2717 ${error.message}`));
|
|
10381
10565
|
}
|
|
10382
10566
|
} else {
|
|
10383
|
-
console.error(
|
|
10567
|
+
console.error(chalk45.red("\u2717 An unexpected error occurred"));
|
|
10384
10568
|
}
|
|
10385
10569
|
process.exit(1);
|
|
10386
10570
|
}
|
|
@@ -10388,84 +10572,85 @@ var setupCommand2 = new Command42().name("setup").description("Configure a model
|
|
|
10388
10572
|
);
|
|
10389
10573
|
|
|
10390
10574
|
// src/commands/model-provider/delete.ts
|
|
10391
|
-
import { Command as
|
|
10392
|
-
import
|
|
10393
|
-
var deleteCommand3 = new
|
|
10575
|
+
import { Command as Command45 } from "commander";
|
|
10576
|
+
import chalk46 from "chalk";
|
|
10577
|
+
var deleteCommand3 = new Command45().name("delete").description("Delete a model provider").argument("<type>", "Model provider type to delete").action(async (type) => {
|
|
10394
10578
|
try {
|
|
10395
10579
|
if (!Object.keys(MODEL_PROVIDER_TYPES).includes(type)) {
|
|
10396
|
-
console.error(
|
|
10580
|
+
console.error(chalk46.red(`\u2717 Invalid type "${type}"`));
|
|
10397
10581
|
console.log();
|
|
10398
10582
|
console.log("Valid types:");
|
|
10399
10583
|
for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
|
|
10400
|
-
console.log(` ${
|
|
10584
|
+
console.log(` ${chalk46.cyan(t)} - ${config.label}`);
|
|
10401
10585
|
}
|
|
10402
10586
|
process.exit(1);
|
|
10403
10587
|
}
|
|
10404
10588
|
await deleteModelProvider(type);
|
|
10405
|
-
console.log(
|
|
10589
|
+
console.log(chalk46.green(`\u2713 Model provider "${type}" deleted`));
|
|
10406
10590
|
} catch (error) {
|
|
10407
10591
|
if (error instanceof Error) {
|
|
10408
10592
|
if (error.message.includes("not found")) {
|
|
10409
|
-
console.error(
|
|
10593
|
+
console.error(chalk46.red(`\u2717 Model provider "${type}" not found`));
|
|
10410
10594
|
} else if (error.message.includes("Not authenticated")) {
|
|
10411
|
-
console.error(
|
|
10595
|
+
console.error(chalk46.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
10412
10596
|
} else {
|
|
10413
|
-
console.error(
|
|
10597
|
+
console.error(chalk46.red(`\u2717 ${error.message}`));
|
|
10414
10598
|
}
|
|
10415
10599
|
} else {
|
|
10416
|
-
console.error(
|
|
10600
|
+
console.error(chalk46.red("\u2717 An unexpected error occurred"));
|
|
10417
10601
|
}
|
|
10418
10602
|
process.exit(1);
|
|
10419
10603
|
}
|
|
10420
10604
|
});
|
|
10421
10605
|
|
|
10422
10606
|
// src/commands/model-provider/set-default.ts
|
|
10423
|
-
import { Command as
|
|
10424
|
-
import
|
|
10425
|
-
var setDefaultCommand = new
|
|
10607
|
+
import { Command as Command46 } from "commander";
|
|
10608
|
+
import chalk47 from "chalk";
|
|
10609
|
+
var setDefaultCommand = new Command46().name("set-default").description("Set a model provider as default for its framework").argument("<type>", "Model provider type to set as default").action(async (type) => {
|
|
10426
10610
|
try {
|
|
10427
10611
|
if (!Object.keys(MODEL_PROVIDER_TYPES).includes(type)) {
|
|
10428
|
-
console.error(
|
|
10612
|
+
console.error(chalk47.red(`\u2717 Invalid type "${type}"`));
|
|
10429
10613
|
console.log();
|
|
10430
10614
|
console.log("Valid types:");
|
|
10431
10615
|
for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
|
|
10432
|
-
console.log(` ${
|
|
10616
|
+
console.log(` ${chalk47.cyan(t)} - ${config.label}`);
|
|
10433
10617
|
}
|
|
10434
10618
|
process.exit(1);
|
|
10435
10619
|
}
|
|
10436
10620
|
const provider = await setModelProviderDefault(type);
|
|
10437
10621
|
console.log(
|
|
10438
|
-
|
|
10622
|
+
chalk47.green(
|
|
10439
10623
|
`\u2713 Default for ${provider.framework} set to "${provider.type}"`
|
|
10440
10624
|
)
|
|
10441
10625
|
);
|
|
10442
10626
|
} catch (error) {
|
|
10443
10627
|
if (error instanceof Error) {
|
|
10444
10628
|
if (error.message.includes("not found")) {
|
|
10445
|
-
console.error(
|
|
10629
|
+
console.error(chalk47.red(`\u2717 Model provider "${type}" not found`));
|
|
10446
10630
|
} else if (error.message.includes("Not authenticated")) {
|
|
10447
|
-
console.error(
|
|
10631
|
+
console.error(chalk47.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
10448
10632
|
} else {
|
|
10449
|
-
console.error(
|
|
10633
|
+
console.error(chalk47.red(`\u2717 ${error.message}`));
|
|
10450
10634
|
}
|
|
10451
10635
|
} else {
|
|
10452
|
-
console.error(
|
|
10636
|
+
console.error(chalk47.red("\u2717 An unexpected error occurred"));
|
|
10453
10637
|
}
|
|
10454
10638
|
process.exit(1);
|
|
10455
10639
|
}
|
|
10456
10640
|
});
|
|
10457
10641
|
|
|
10458
10642
|
// src/commands/model-provider/index.ts
|
|
10459
|
-
var modelProviderCommand = new
|
|
10643
|
+
var modelProviderCommand = new Command47().name("model-provider").description("Manage model providers for agent runs").addCommand(listCommand7).addCommand(setupCommand2).addCommand(deleteCommand3).addCommand(setDefaultCommand);
|
|
10460
10644
|
|
|
10461
10645
|
// src/commands/onboard.ts
|
|
10462
|
-
import { Command as
|
|
10463
|
-
import
|
|
10464
|
-
import { mkdir as
|
|
10646
|
+
import { Command as Command48 } from "commander";
|
|
10647
|
+
import chalk51 from "chalk";
|
|
10648
|
+
import { mkdir as mkdir7 } from "fs/promises";
|
|
10465
10649
|
import { existsSync as existsSync10 } from "fs";
|
|
10650
|
+
import path14 from "path";
|
|
10466
10651
|
|
|
10467
10652
|
// src/lib/ui/welcome-box.ts
|
|
10468
|
-
import
|
|
10653
|
+
import chalk48 from "chalk";
|
|
10469
10654
|
function renderWelcomeBox(lines, width) {
|
|
10470
10655
|
const maxLineLength = Math.max(...lines.map((line) => line.length));
|
|
10471
10656
|
const boxWidth = width ?? maxLineLength + 4;
|
|
@@ -10473,28 +10658,28 @@ function renderWelcomeBox(lines, width) {
|
|
|
10473
10658
|
const horizontalLine = "\u2500".repeat(innerWidth);
|
|
10474
10659
|
const topBorder = `\u250C${horizontalLine}\u2510`;
|
|
10475
10660
|
const bottomBorder = `\u2514${horizontalLine}\u2518`;
|
|
10476
|
-
console.log(
|
|
10661
|
+
console.log(chalk48.cyan(topBorder));
|
|
10477
10662
|
for (const line of lines) {
|
|
10478
10663
|
const padding = innerWidth - line.length;
|
|
10479
10664
|
const leftPad = Math.floor(padding / 2);
|
|
10480
10665
|
const rightPad = padding - leftPad;
|
|
10481
10666
|
const centeredLine = " ".repeat(leftPad) + line + " ".repeat(rightPad);
|
|
10482
|
-
console.log(
|
|
10667
|
+
console.log(chalk48.cyan("\u2502") + centeredLine + chalk48.cyan("\u2502"));
|
|
10483
10668
|
}
|
|
10484
|
-
console.log(
|
|
10669
|
+
console.log(chalk48.cyan(bottomBorder));
|
|
10485
10670
|
}
|
|
10486
10671
|
function renderOnboardWelcome() {
|
|
10487
10672
|
renderWelcomeBox([
|
|
10488
10673
|
"",
|
|
10489
10674
|
"Welcome to VM0!",
|
|
10490
10675
|
"",
|
|
10491
|
-
"Let's
|
|
10676
|
+
"Let's create your first agent.",
|
|
10492
10677
|
""
|
|
10493
10678
|
]);
|
|
10494
10679
|
}
|
|
10495
10680
|
|
|
10496
10681
|
// src/lib/ui/progress-line.ts
|
|
10497
|
-
import
|
|
10682
|
+
import chalk49 from "chalk";
|
|
10498
10683
|
var STATUS_SYMBOLS = {
|
|
10499
10684
|
completed: "\u25CF",
|
|
10500
10685
|
"in-progress": "\u25D0",
|
|
@@ -10504,14 +10689,14 @@ var STATUS_SYMBOLS = {
|
|
|
10504
10689
|
function getStatusColor(status) {
|
|
10505
10690
|
switch (status) {
|
|
10506
10691
|
case "completed":
|
|
10507
|
-
return
|
|
10692
|
+
return chalk49.green;
|
|
10508
10693
|
case "in-progress":
|
|
10509
|
-
return
|
|
10694
|
+
return chalk49.yellow;
|
|
10510
10695
|
case "failed":
|
|
10511
|
-
return
|
|
10696
|
+
return chalk49.red;
|
|
10512
10697
|
case "pending":
|
|
10513
10698
|
default:
|
|
10514
|
-
return
|
|
10699
|
+
return chalk49.dim;
|
|
10515
10700
|
}
|
|
10516
10701
|
}
|
|
10517
10702
|
function renderProgressLine(steps) {
|
|
@@ -10522,7 +10707,7 @@ function renderProgressLine(steps) {
|
|
|
10522
10707
|
const color = getStatusColor(step.status);
|
|
10523
10708
|
console.log(color(`${symbol} ${step.label}`));
|
|
10524
10709
|
if (i < steps.length - 1) {
|
|
10525
|
-
console.log(
|
|
10710
|
+
console.log(chalk49.dim("\u2502"));
|
|
10526
10711
|
}
|
|
10527
10712
|
}
|
|
10528
10713
|
}
|
|
@@ -10531,6 +10716,7 @@ function createOnboardProgress() {
|
|
|
10531
10716
|
{ label: "Authentication", status: "pending" },
|
|
10532
10717
|
{ label: "Model Provider Setup", status: "pending" },
|
|
10533
10718
|
{ label: "Create Agent", status: "pending" },
|
|
10719
|
+
{ label: "Claude Plugin Install", status: "pending" },
|
|
10534
10720
|
{ label: "Complete", status: "pending" }
|
|
10535
10721
|
];
|
|
10536
10722
|
return {
|
|
@@ -10675,295 +10861,102 @@ async function setupModelProvider(type, credential, options) {
|
|
|
10675
10861
|
}
|
|
10676
10862
|
|
|
10677
10863
|
// src/lib/domain/onboard/claude-setup.ts
|
|
10678
|
-
import {
|
|
10679
|
-
import
|
|
10680
|
-
var
|
|
10681
|
-
var
|
|
10682
|
-
|
|
10683
|
-
|
|
10684
|
-
|
|
10685
|
-
|
|
10686
|
-
|
|
10687
|
-
|
|
10688
|
-
|
|
10689
|
-
|
|
10690
|
-
|
|
10691
|
-
|
|
10692
|
-
|
|
10693
|
-
|
|
10694
|
-
|
|
10695
|
-
|
|
10696
|
-
|
|
10697
|
-
|
|
10698
|
-
|
|
10699
|
-
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
10719
|
-
|
|
10720
|
-
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
|
|
10742
|
-
|
|
10743
|
-
|
|
10744
|
-
|
|
10745
|
-
|
|
10746
|
-
|
|
10747
|
-
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
### Step 4: Test the Agent
|
|
10756
|
-
|
|
10757
|
-
After creating both files, the user runs:
|
|
10758
|
-
|
|
10759
|
-
\`\`\`bash
|
|
10760
|
-
vm0 cook "start working"
|
|
10761
|
-
\`\`\`
|
|
10762
|
-
|
|
10763
|
-
This command:
|
|
10764
|
-
1. Uploads the configuration to VM0
|
|
10765
|
-
2. Runs the agent in a secure sandbox
|
|
10766
|
-
3. Downloads results to the \`artifact/\` directory
|
|
10767
|
-
|
|
10768
|
-
## Available Skills
|
|
10769
|
-
|
|
10770
|
-
Skills give agents access to external services. Add them to vm0.yaml when needed.
|
|
10771
|
-
|
|
10772
|
-
**Popular Skills:**
|
|
10773
|
-
|
|
10774
|
-
| Skill | Use Case |
|
|
10775
|
-
|-------|----------|
|
|
10776
|
-
| \`github\` | Read/write issues, PRs, files |
|
|
10777
|
-
| \`slack\` | Send messages to channels |
|
|
10778
|
-
| \`notion\` | Access Notion pages/databases |
|
|
10779
|
-
| \`firecrawl\` | Scrape and extract web content |
|
|
10780
|
-
| \`supabase\` | Database operations |
|
|
10781
|
-
| \`google-sheets\` | Read/write spreadsheets |
|
|
10782
|
-
| \`linear\` | Project management |
|
|
10783
|
-
| \`discord\` | Send Discord messages |
|
|
10784
|
-
| \`gmail\` | Send emails |
|
|
10785
|
-
| \`openai\` | Embeddings, additional AI calls |
|
|
10786
|
-
|
|
10787
|
-
**All 79 skills:** https://github.com/vm0-ai/vm0-skills
|
|
10788
|
-
|
|
10789
|
-
**Skill URL format:**
|
|
10790
|
-
\`\`\`
|
|
10791
|
-
https://github.com/vm0-ai/vm0-skills/tree/main/[skill-name]
|
|
10792
|
-
\`\`\`
|
|
10793
|
-
|
|
10794
|
-
## Examples
|
|
10795
|
-
|
|
10796
|
-
### HackerNews Curator
|
|
10797
|
-
|
|
10798
|
-
**AGENTS.md:**
|
|
10799
|
-
\`\`\`markdown
|
|
10800
|
-
# HackerNews AI Curator
|
|
10801
|
-
|
|
10802
|
-
You are a content curator that finds AI-related articles on HackerNews.
|
|
10803
|
-
|
|
10804
|
-
## Workflow
|
|
10805
|
-
|
|
10806
|
-
1. Go to https://news.ycombinator.com
|
|
10807
|
-
2. Read the top 30 stories
|
|
10808
|
-
3. Filter for AI, ML, and LLM related content
|
|
10809
|
-
4. For each relevant article, extract:
|
|
10810
|
-
- Title and URL
|
|
10811
|
-
- 2-3 sentence summary
|
|
10812
|
-
- Why it matters
|
|
10813
|
-
5. Write findings to \`daily-digest.md\`
|
|
10814
|
-
|
|
10815
|
-
## Output
|
|
10816
|
-
|
|
10817
|
-
Create \`daily-digest.md\` with today's date as the header.
|
|
10818
|
-
Format as a bulleted list with links.
|
|
10819
|
-
\`\`\`
|
|
10820
|
-
|
|
10821
|
-
**vm0.yaml:**
|
|
10822
|
-
\`\`\`yaml
|
|
10823
|
-
version: "1.0"
|
|
10824
|
-
|
|
10825
|
-
agents:
|
|
10826
|
-
hn-curator:
|
|
10827
|
-
framework: claude-code
|
|
10828
|
-
instructions: AGENTS.md
|
|
10829
|
-
\`\`\`
|
|
10830
|
-
|
|
10831
|
-
### GitHub Issue Reporter
|
|
10832
|
-
|
|
10833
|
-
**AGENTS.md:**
|
|
10834
|
-
\`\`\`markdown
|
|
10835
|
-
# GitHub Issue Reporter
|
|
10836
|
-
|
|
10837
|
-
You are a GitHub analyst that creates issue summary reports.
|
|
10838
|
-
|
|
10839
|
-
## Workflow
|
|
10840
|
-
|
|
10841
|
-
1. List all open issues in the repository
|
|
10842
|
-
2. Group by labels: bug, feature, documentation, other
|
|
10843
|
-
3. For each group, report:
|
|
10844
|
-
- Total count
|
|
10845
|
-
- Oldest issue (with age in days)
|
|
10846
|
-
- Most commented issue
|
|
10847
|
-
4. Write report to \`issue-report.md\`
|
|
10848
|
-
|
|
10849
|
-
## Output
|
|
10850
|
-
|
|
10851
|
-
Create \`issue-report.md\` with sections for each label group.
|
|
10852
|
-
Include links to referenced issues.
|
|
10853
|
-
\`\`\`
|
|
10854
|
-
|
|
10855
|
-
**vm0.yaml:**
|
|
10856
|
-
\`\`\`yaml
|
|
10857
|
-
version: "1.0"
|
|
10858
|
-
|
|
10859
|
-
agents:
|
|
10860
|
-
issue-reporter:
|
|
10861
|
-
framework: claude-code
|
|
10862
|
-
instructions: AGENTS.md
|
|
10863
|
-
skills:
|
|
10864
|
-
- https://github.com/vm0-ai/vm0-skills/tree/main/github
|
|
10865
|
-
environment:
|
|
10866
|
-
GITHUB_REPO: "\${{ vars.GITHUB_REPO }}"
|
|
10867
|
-
\`\`\`
|
|
10868
|
-
|
|
10869
|
-
### Slack Daily Digest
|
|
10870
|
-
|
|
10871
|
-
**AGENTS.md:**
|
|
10872
|
-
\`\`\`markdown
|
|
10873
|
-
# Slack Daily Digest
|
|
10874
|
-
|
|
10875
|
-
You are an assistant that posts daily summaries to Slack.
|
|
10876
|
-
|
|
10877
|
-
## Workflow
|
|
10878
|
-
|
|
10879
|
-
1. Read the contents of \`updates.md\` from the input volume
|
|
10880
|
-
2. Summarize the key points (max 5 bullets)
|
|
10881
|
-
3. Format as a Slack message with emoji headers
|
|
10882
|
-
4. Post to the #daily-updates channel
|
|
10883
|
-
|
|
10884
|
-
## Output
|
|
10885
|
-
|
|
10886
|
-
Post the summary to Slack. Write a copy to \`sent-message.md\`.
|
|
10887
|
-
\`\`\`
|
|
10888
|
-
|
|
10889
|
-
**vm0.yaml:**
|
|
10890
|
-
\`\`\`yaml
|
|
10891
|
-
version: "1.0"
|
|
10892
|
-
|
|
10893
|
-
agents:
|
|
10894
|
-
slack-digest:
|
|
10895
|
-
framework: claude-code
|
|
10896
|
-
instructions: AGENTS.md
|
|
10897
|
-
skills:
|
|
10898
|
-
- https://github.com/vm0-ai/vm0-skills/tree/main/slack
|
|
10899
|
-
environment:
|
|
10900
|
-
SLACK_CHANNEL: "\${{ vars.SLACK_CHANNEL }}"
|
|
10901
|
-
\`\`\`
|
|
10902
|
-
|
|
10903
|
-
## Environment Variables
|
|
10904
|
-
|
|
10905
|
-
Use environment variables for sensitive data and configuration:
|
|
10906
|
-
|
|
10907
|
-
\`\`\`yaml
|
|
10908
|
-
environment:
|
|
10909
|
-
# Secrets (encrypted, for API keys)
|
|
10910
|
-
API_KEY: "\${{ secrets.API_KEY }}"
|
|
10911
|
-
|
|
10912
|
-
# Variables (plain text, for config)
|
|
10913
|
-
REPO_NAME: "\${{ vars.REPO_NAME }}"
|
|
10914
|
-
|
|
10915
|
-
# Credentials (from vm0 credential storage)
|
|
10916
|
-
MY_TOKEN: "\${{ credentials.MY_TOKEN }}"
|
|
10917
|
-
\`\`\`
|
|
10918
|
-
|
|
10919
|
-
Set credentials with (names must be UPPERCASE):
|
|
10920
|
-
\`\`\`bash
|
|
10921
|
-
vm0 credential set API_KEY "your-api-key"
|
|
10922
|
-
\`\`\`
|
|
10923
|
-
|
|
10924
|
-
## Troubleshooting
|
|
10925
|
-
|
|
10926
|
-
**Agent doesn't follow instructions:**
|
|
10927
|
-
- Make steps more specific and explicit
|
|
10928
|
-
- Add "Do not..." constraints for unwanted behavior
|
|
10929
|
-
- Break complex steps into smaller sub-steps
|
|
10930
|
-
|
|
10931
|
-
**Agent can't access a service:**
|
|
10932
|
-
- Add the required skill to vm0.yaml
|
|
10933
|
-
- Set up credentials with \`vm0 credential set\`
|
|
10934
|
-
|
|
10935
|
-
**Output is in wrong format:**
|
|
10936
|
-
- Provide an exact template in the instructions
|
|
10937
|
-
- Include a small example of expected output
|
|
10938
|
-
|
|
10939
|
-
## Next Steps After Creating Files
|
|
10940
|
-
|
|
10941
|
-
\`\`\`bash
|
|
10942
|
-
# Run your agent
|
|
10943
|
-
vm0 cook "start working"
|
|
10944
|
-
|
|
10945
|
-
# View logs if needed
|
|
10946
|
-
vm0 logs [run-id]
|
|
10947
|
-
|
|
10948
|
-
# Results are in artifact/ directory
|
|
10949
|
-
ls artifact/
|
|
10950
|
-
|
|
10951
|
-
# Continue from where agent left off
|
|
10952
|
-
vm0 cook continue "keep going"
|
|
10953
|
-
|
|
10954
|
-
# Resume from a checkpoint
|
|
10955
|
-
vm0 cook resume "try again"
|
|
10956
|
-
\`\`\`
|
|
10957
|
-
`;
|
|
10864
|
+
import { spawn as spawn3 } from "child_process";
|
|
10865
|
+
import chalk50 from "chalk";
|
|
10866
|
+
var MARKETPLACE_NAME = "vm0-skills";
|
|
10867
|
+
var MARKETPLACE_REPO = "vm0-ai/vm0-skills";
|
|
10868
|
+
var PLUGIN_ID = "vm0@vm0-skills";
|
|
10869
|
+
var PRIMARY_SKILL_NAME = "vm0-agent";
|
|
10870
|
+
async function runClaudeCommand(args, cwd) {
|
|
10871
|
+
return new Promise((resolve) => {
|
|
10872
|
+
const child = spawn3("claude", args, {
|
|
10873
|
+
shell: true,
|
|
10874
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
10875
|
+
cwd
|
|
10876
|
+
});
|
|
10877
|
+
let stdout = "";
|
|
10878
|
+
let stderr = "";
|
|
10879
|
+
child.stdout?.on("data", (data) => {
|
|
10880
|
+
stdout += data.toString();
|
|
10881
|
+
});
|
|
10882
|
+
child.stderr?.on("data", (data) => {
|
|
10883
|
+
stderr += data.toString();
|
|
10884
|
+
});
|
|
10885
|
+
child.on("error", (err) => {
|
|
10886
|
+
resolve({
|
|
10887
|
+
success: false,
|
|
10888
|
+
output: stdout,
|
|
10889
|
+
error: err.message
|
|
10890
|
+
});
|
|
10891
|
+
});
|
|
10892
|
+
child.on("close", (code) => {
|
|
10893
|
+
resolve({
|
|
10894
|
+
success: code === 0,
|
|
10895
|
+
output: stdout,
|
|
10896
|
+
error: stderr || void 0
|
|
10897
|
+
});
|
|
10898
|
+
});
|
|
10899
|
+
});
|
|
10900
|
+
}
|
|
10901
|
+
function handlePluginError(error, context) {
|
|
10902
|
+
const displayContext = context ?? "Claude plugin";
|
|
10903
|
+
console.error(chalk50.red(`Failed to install ${displayContext}`));
|
|
10904
|
+
if (error instanceof Error) {
|
|
10905
|
+
console.error(chalk50.red(error.message));
|
|
10906
|
+
}
|
|
10907
|
+
console.error(
|
|
10908
|
+
chalk50.dim("Please ensure Claude CLI is installed and accessible.")
|
|
10909
|
+
);
|
|
10910
|
+
process.exit(1);
|
|
10911
|
+
}
|
|
10912
|
+
async function isMarketplaceInstalled() {
|
|
10913
|
+
const result = await runClaudeCommand([
|
|
10914
|
+
"plugin",
|
|
10915
|
+
"marketplace",
|
|
10916
|
+
"list",
|
|
10917
|
+
"--json"
|
|
10918
|
+
]);
|
|
10919
|
+
if (!result.success) {
|
|
10920
|
+
return false;
|
|
10921
|
+
}
|
|
10922
|
+
try {
|
|
10923
|
+
const marketplaces = JSON.parse(result.output);
|
|
10924
|
+
return marketplaces.some((m) => m.name === MARKETPLACE_NAME);
|
|
10925
|
+
} catch {
|
|
10926
|
+
return false;
|
|
10927
|
+
}
|
|
10928
|
+
}
|
|
10929
|
+
async function addMarketplace() {
|
|
10930
|
+
const result = await runClaudeCommand([
|
|
10931
|
+
"plugin",
|
|
10932
|
+
"marketplace",
|
|
10933
|
+
"add",
|
|
10934
|
+
MARKETPLACE_REPO
|
|
10935
|
+
]);
|
|
10936
|
+
if (!result.success) {
|
|
10937
|
+
throw new Error(
|
|
10938
|
+
`Failed to add marketplace ${MARKETPLACE_REPO}: ${result.error ?? "unknown error"}`
|
|
10939
|
+
);
|
|
10940
|
+
}
|
|
10958
10941
|
}
|
|
10959
|
-
async function
|
|
10960
|
-
const
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10942
|
+
async function ensureMarketplace() {
|
|
10943
|
+
const installed = await isMarketplaceInstalled();
|
|
10944
|
+
if (!installed) {
|
|
10945
|
+
await addMarketplace();
|
|
10946
|
+
}
|
|
10947
|
+
}
|
|
10948
|
+
async function installVm0Plugin(scope = "user", cwd) {
|
|
10949
|
+
await ensureMarketplace();
|
|
10950
|
+
const args = ["plugin", "install", PLUGIN_ID, "--scope", scope];
|
|
10951
|
+
const result = await runClaudeCommand(args, cwd);
|
|
10952
|
+
if (!result.success) {
|
|
10953
|
+
throw new Error(
|
|
10954
|
+
`Failed to install plugin ${PLUGIN_ID}: ${result.error ?? "unknown error"}`
|
|
10955
|
+
);
|
|
10956
|
+
}
|
|
10964
10957
|
return {
|
|
10965
|
-
|
|
10966
|
-
|
|
10958
|
+
pluginId: PLUGIN_ID,
|
|
10959
|
+
scope
|
|
10967
10960
|
};
|
|
10968
10961
|
}
|
|
10969
10962
|
|
|
@@ -10977,34 +10970,34 @@ async function handleAuthentication(ctx) {
|
|
|
10977
10970
|
return;
|
|
10978
10971
|
}
|
|
10979
10972
|
if (!ctx.interactive) {
|
|
10980
|
-
console.error(
|
|
10973
|
+
console.error(chalk51.red("Error: Not authenticated"));
|
|
10981
10974
|
console.error("Run 'vm0 auth login' first or set VM0_TOKEN");
|
|
10982
10975
|
process.exit(1);
|
|
10983
10976
|
}
|
|
10984
|
-
console.log(
|
|
10977
|
+
console.log(chalk51.dim("Authentication required..."));
|
|
10985
10978
|
console.log();
|
|
10986
10979
|
await runAuthFlow({
|
|
10987
10980
|
onInitiating: () => {
|
|
10988
10981
|
console.log("Initiating authentication...");
|
|
10989
10982
|
},
|
|
10990
10983
|
onDeviceCodeReady: (url, code, expiresIn) => {
|
|
10991
|
-
console.log(
|
|
10992
|
-
console.log(
|
|
10984
|
+
console.log(chalk51.green("\nDevice code generated"));
|
|
10985
|
+
console.log(chalk51.cyan(`
|
|
10993
10986
|
To authenticate, visit: ${url}`));
|
|
10994
|
-
console.log(`And enter this code: ${
|
|
10987
|
+
console.log(`And enter this code: ${chalk51.bold(code)}`);
|
|
10995
10988
|
console.log(`
|
|
10996
10989
|
The code expires in ${expiresIn} minutes.`);
|
|
10997
10990
|
console.log("\nWaiting for authentication...");
|
|
10998
10991
|
},
|
|
10999
10992
|
onPolling: () => {
|
|
11000
|
-
process.stdout.write(
|
|
10993
|
+
process.stdout.write(chalk51.dim("."));
|
|
11001
10994
|
},
|
|
11002
10995
|
onSuccess: () => {
|
|
11003
|
-
console.log(
|
|
10996
|
+
console.log(chalk51.green("\nAuthentication successful!"));
|
|
11004
10997
|
console.log("Your credentials have been saved.");
|
|
11005
10998
|
},
|
|
11006
10999
|
onError: (error) => {
|
|
11007
|
-
console.error(
|
|
11000
|
+
console.error(chalk51.red(`
|
|
11008
11001
|
${error.message}`));
|
|
11009
11002
|
process.exit(1);
|
|
11010
11003
|
}
|
|
@@ -11019,11 +11012,11 @@ async function handleModelProvider(ctx) {
|
|
|
11019
11012
|
return;
|
|
11020
11013
|
}
|
|
11021
11014
|
if (!ctx.interactive) {
|
|
11022
|
-
console.error(
|
|
11015
|
+
console.error(chalk51.red("Error: No model provider configured"));
|
|
11023
11016
|
console.error("Run 'vm0 model-provider setup' first");
|
|
11024
11017
|
process.exit(1);
|
|
11025
11018
|
}
|
|
11026
|
-
console.log(
|
|
11019
|
+
console.log(chalk51.dim("Model provider setup required..."));
|
|
11027
11020
|
console.log();
|
|
11028
11021
|
const choices = getProviderChoices();
|
|
11029
11022
|
const providerType = await promptSelect(
|
|
@@ -11040,19 +11033,19 @@ async function handleModelProvider(ctx) {
|
|
|
11040
11033
|
const selectedChoice = choices.find((c20) => c20.type === providerType);
|
|
11041
11034
|
if (selectedChoice) {
|
|
11042
11035
|
console.log();
|
|
11043
|
-
console.log(
|
|
11036
|
+
console.log(chalk51.dim(selectedChoice.helpText));
|
|
11044
11037
|
console.log();
|
|
11045
11038
|
}
|
|
11046
11039
|
const credential = await promptPassword(
|
|
11047
11040
|
`Enter your ${selectedChoice?.credentialLabel ?? "credential"}:`
|
|
11048
11041
|
);
|
|
11049
11042
|
if (!credential) {
|
|
11050
|
-
console.log(
|
|
11043
|
+
console.log(chalk51.dim("Cancelled"));
|
|
11051
11044
|
process.exit(0);
|
|
11052
11045
|
}
|
|
11053
11046
|
const result = await setupModelProvider(providerType, credential);
|
|
11054
11047
|
console.log(
|
|
11055
|
-
|
|
11048
|
+
chalk51.green(
|
|
11056
11049
|
`
|
|
11057
11050
|
\u2713 Model provider "${providerType}" ${result.created ? "created" : "updated"}${result.isDefault ? ` (default for ${result.framework})` : ""}`
|
|
11058
11051
|
)
|
|
@@ -11080,52 +11073,63 @@ async function handleAgentCreation(ctx) {
|
|
|
11080
11073
|
}
|
|
11081
11074
|
if (!validateAgentName(agentName)) {
|
|
11082
11075
|
console.error(
|
|
11083
|
-
|
|
11076
|
+
chalk51.red(
|
|
11084
11077
|
"Invalid agent name: must be 3-64 chars, alphanumeric + hyphens"
|
|
11085
11078
|
)
|
|
11086
11079
|
);
|
|
11087
11080
|
process.exit(1);
|
|
11088
11081
|
}
|
|
11089
11082
|
if (existsSync10(agentName)) {
|
|
11090
|
-
console.error(
|
|
11083
|
+
console.error(chalk51.red(`
|
|
11091
11084
|
\u2717 ${agentName}/ already exists`));
|
|
11092
11085
|
console.log();
|
|
11093
11086
|
console.log("Remove it first or choose a different name:");
|
|
11094
|
-
console.log(
|
|
11087
|
+
console.log(chalk51.cyan(` rm -rf ${agentName}`));
|
|
11095
11088
|
process.exit(1);
|
|
11096
11089
|
}
|
|
11097
|
-
|
|
11098
|
-
|
|
11099
|
-
if (!confirmed) {
|
|
11100
|
-
console.log(chalk48.dim("Cancelled"));
|
|
11101
|
-
process.exit(0);
|
|
11102
|
-
}
|
|
11103
|
-
}
|
|
11104
|
-
await mkdir8(agentName, { recursive: true });
|
|
11105
|
-
console.log(chalk48.green(`\u2713 Created ${agentName}/`));
|
|
11090
|
+
await mkdir7(agentName, { recursive: true });
|
|
11091
|
+
console.log(chalk51.green(`\u2713 Created ${agentName}/`));
|
|
11106
11092
|
ctx.updateProgress(2, "completed");
|
|
11107
11093
|
return agentName;
|
|
11108
11094
|
}
|
|
11109
|
-
async function
|
|
11095
|
+
async function handlePluginInstallation(ctx, agentName) {
|
|
11110
11096
|
ctx.updateProgress(3, "in-progress");
|
|
11111
|
-
|
|
11112
|
-
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11097
|
+
let shouldInstall = true;
|
|
11098
|
+
if (!ctx.options.yes && ctx.interactive) {
|
|
11099
|
+
const confirmed = await promptConfirm(
|
|
11100
|
+
"Install VM0 Claude Plugin?",
|
|
11101
|
+
true
|
|
11102
|
+
// default: Yes
|
|
11103
|
+
);
|
|
11104
|
+
shouldInstall = confirmed ?? true;
|
|
11105
|
+
}
|
|
11106
|
+
if (!shouldInstall) {
|
|
11107
|
+
console.log(chalk51.dim("Skipped plugin installation"));
|
|
11108
|
+
ctx.updateProgress(3, "completed");
|
|
11109
|
+
return;
|
|
11110
|
+
}
|
|
11111
|
+
const scope = "project";
|
|
11112
|
+
try {
|
|
11113
|
+
const agentDir = path14.resolve(process.cwd(), agentName);
|
|
11114
|
+
const result = await installVm0Plugin(scope, agentDir);
|
|
11115
|
+
console.log(
|
|
11116
|
+
chalk51.green(`\u2713 Installed ${result.pluginId} (scope: ${result.scope})`)
|
|
11117
|
+
);
|
|
11118
|
+
} catch (error) {
|
|
11119
|
+
handlePluginError(error);
|
|
11120
|
+
}
|
|
11117
11121
|
ctx.updateProgress(3, "completed");
|
|
11118
11122
|
}
|
|
11119
11123
|
function printNextSteps(agentName) {
|
|
11120
11124
|
console.log();
|
|
11121
|
-
console.log(
|
|
11125
|
+
console.log(chalk51.bold("Next step:"));
|
|
11122
11126
|
console.log();
|
|
11123
11127
|
console.log(
|
|
11124
|
-
` ${
|
|
11128
|
+
` ${chalk51.cyan(`cd ${agentName} && claude "/${PRIMARY_SKILL_NAME} let's build a workflow"`)}`
|
|
11125
11129
|
);
|
|
11126
11130
|
console.log();
|
|
11127
11131
|
}
|
|
11128
|
-
var onboardCommand = new
|
|
11132
|
+
var onboardCommand = new Command48().name("onboard").description("Guided setup for new VM0 users").option("-y, --yes", "Skip confirmation prompts").option("--name <name>", `Agent name (default: ${DEFAULT_AGENT_NAME})`).action(async (options) => {
|
|
11129
11133
|
const interactive = isInteractive();
|
|
11130
11134
|
if (interactive) {
|
|
11131
11135
|
console.log();
|
|
@@ -11151,248 +11155,40 @@ var onboardCommand = new Command46().name("onboard").description("Guided setup f
|
|
|
11151
11155
|
await handleAuthentication(ctx);
|
|
11152
11156
|
await handleModelProvider(ctx);
|
|
11153
11157
|
const agentName = await handleAgentCreation(ctx);
|
|
11154
|
-
await
|
|
11158
|
+
await handlePluginInstallation(ctx, agentName);
|
|
11159
|
+
ctx.updateProgress(4, "completed");
|
|
11155
11160
|
printNextSteps(agentName);
|
|
11156
11161
|
});
|
|
11157
11162
|
|
|
11158
11163
|
// src/commands/setup-claude.ts
|
|
11159
|
-
import { Command as
|
|
11160
|
-
import
|
|
11161
|
-
|
|
11162
|
-
|
|
11163
|
-
|
|
11164
|
-
|
|
11165
|
-
|
|
11166
|
-
|
|
11167
|
-
|
|
11168
|
-
|
|
11169
|
-
|
|
11170
|
-
|
|
11171
|
-
|
|
11172
|
-
|
|
11173
|
-
## When to Use
|
|
11174
|
-
|
|
11175
|
-
- User wants to create a new VM0 agent from scratch
|
|
11176
|
-
- User wants to improve an existing agent's instructions
|
|
11177
|
-
- User needs help configuring vm0.yaml with skills
|
|
11178
|
-
- User is unsure how to structure their agent's workflow
|
|
11179
|
-
|
|
11180
|
-
## Workflow
|
|
11181
|
-
|
|
11182
|
-
### Step 1: Understand the Goal
|
|
11183
|
-
|
|
11184
|
-
Ask the user what they want their agent to accomplish:
|
|
11185
|
-
- What is the main task or problem to solve?
|
|
11186
|
-
- What inputs will the agent receive?
|
|
11187
|
-
- What outputs should the agent produce?
|
|
11188
|
-
- Are there any constraints or requirements?
|
|
11189
|
-
|
|
11190
|
-
### Step 2: Design the Workflow
|
|
11191
|
-
|
|
11192
|
-
Break down the task into clear, sequential steps:
|
|
11193
|
-
1. Each step should be a single, focused action
|
|
11194
|
-
2. Steps should build on each other logically
|
|
11195
|
-
3. Include error handling and edge cases
|
|
11196
|
-
4. Consider what tools/skills the agent will need
|
|
11197
|
-
|
|
11198
|
-
### Step 3: Write AGENTS.md
|
|
11199
|
-
|
|
11200
|
-
Create the agent instructions file with:
|
|
11201
|
-
|
|
11202
|
-
\`\`\`markdown
|
|
11203
|
-
# Agent Instructions
|
|
11204
|
-
|
|
11205
|
-
You are a [role description].
|
|
11206
|
-
|
|
11207
|
-
## Goal
|
|
11208
|
-
|
|
11209
|
-
[Clear statement of what the agent should accomplish]
|
|
11210
|
-
|
|
11211
|
-
## Workflow
|
|
11212
|
-
|
|
11213
|
-
1. [First step with specific instructions]
|
|
11214
|
-
2. [Second step with specific instructions]
|
|
11215
|
-
3. [Continue with remaining steps...]
|
|
11216
|
-
|
|
11217
|
-
## Output
|
|
11218
|
-
|
|
11219
|
-
[Describe the expected output format and location]
|
|
11220
|
-
|
|
11221
|
-
## Constraints
|
|
11222
|
-
|
|
11223
|
-
[Any limitations or rules the agent should follow]
|
|
11224
|
-
\`\`\`
|
|
11225
|
-
|
|
11226
|
-
### Step 4: Configure vm0.yaml
|
|
11227
|
-
|
|
11228
|
-
Update the vm0.yaml to include necessary skills:
|
|
11229
|
-
|
|
11230
|
-
\`\`\`yaml
|
|
11231
|
-
version: "1.0"
|
|
11232
|
-
|
|
11233
|
-
agents:
|
|
11234
|
-
agent-name:
|
|
11235
|
-
framework: claude-code
|
|
11236
|
-
instructions: AGENTS.md
|
|
11237
|
-
skills:
|
|
11238
|
-
- https://github.com/vm0-ai/vm0-skills/tree/main/skill-name
|
|
11239
|
-
environment:
|
|
11240
|
-
# Add any required environment variables
|
|
11241
|
-
API_KEY: "\${{ secrets.API_KEY }}"
|
|
11242
|
-
\`\`\`
|
|
11243
|
-
|
|
11244
|
-
### Step 5: Test the Agent
|
|
11245
|
-
|
|
11246
|
-
Guide the user to test their agent:
|
|
11247
|
-
|
|
11248
|
-
\`\`\`bash
|
|
11249
|
-
# Deploy the agent configuration
|
|
11250
|
-
vm0 compose vm0.yaml
|
|
11251
|
-
|
|
11252
|
-
# Run the agent with a test prompt
|
|
11253
|
-
vm0 cook "start working on the task"
|
|
11254
|
-
|
|
11255
|
-
# Check the logs if needed
|
|
11256
|
-
vm0 logs <run-id>
|
|
11257
|
-
\`\`\`
|
|
11258
|
-
|
|
11259
|
-
## Available Skills
|
|
11260
|
-
|
|
11261
|
-
Common skills from vm0-skills repository:
|
|
11262
|
-
|
|
11263
|
-
| Skill | Purpose |
|
|
11264
|
-
|-------|---------|
|
|
11265
|
-
| \`github\` | GitHub API operations (issues, PRs, repos) |
|
|
11266
|
-
| \`slack\` | Send messages to Slack channels |
|
|
11267
|
-
| \`notion\` | Read/write Notion pages and databases |
|
|
11268
|
-
| \`firecrawl\` | Web scraping and content extraction |
|
|
11269
|
-
| \`browserbase\` | Browser automation |
|
|
11270
|
-
| \`openai\` | OpenAI API for embeddings, completions |
|
|
11271
|
-
| \`supabase\` | Database operations with Supabase |
|
|
11272
|
-
|
|
11273
|
-
Browse all skills: https://github.com/vm0-ai/vm0-skills
|
|
11274
|
-
|
|
11275
|
-
## Example Agents
|
|
11276
|
-
|
|
11277
|
-
### Content Curator Agent
|
|
11278
|
-
|
|
11279
|
-
\`\`\`markdown
|
|
11280
|
-
# Agent Instructions
|
|
11281
|
-
|
|
11282
|
-
You are a content curator that monitors HackerNews for AI-related articles.
|
|
11283
|
-
|
|
11284
|
-
## Workflow
|
|
11285
|
-
|
|
11286
|
-
1. Go to HackerNews and read the top 30 stories
|
|
11287
|
-
2. Filter for AI, ML, and LLM related content
|
|
11288
|
-
3. For each relevant article, extract:
|
|
11289
|
-
- Title and URL
|
|
11290
|
-
- Key points (2-3 sentences)
|
|
11291
|
-
- Why it's interesting
|
|
11292
|
-
4. Write a summary to \`daily-digest.md\`
|
|
11293
|
-
|
|
11294
|
-
## Output
|
|
11295
|
-
|
|
11296
|
-
Create \`daily-digest.md\` with today's date as the header.
|
|
11297
|
-
\`\`\`
|
|
11298
|
-
|
|
11299
|
-
### GitHub Issue Tracker Agent
|
|
11300
|
-
|
|
11301
|
-
\`\`\`markdown
|
|
11302
|
-
# Agent Instructions
|
|
11303
|
-
|
|
11304
|
-
You are a GitHub issue tracker that summarizes open issues.
|
|
11305
|
-
|
|
11306
|
-
## Workflow
|
|
11307
|
-
|
|
11308
|
-
1. List all open issues in the repository
|
|
11309
|
-
2. Group issues by labels (bug, feature, docs)
|
|
11310
|
-
3. For each group, summarize:
|
|
11311
|
-
- Number of issues
|
|
11312
|
-
- Oldest issue age
|
|
11313
|
-
- Most discussed issues
|
|
11314
|
-
4. Create a report in \`issue-report.md\`
|
|
11315
|
-
|
|
11316
|
-
## Skills Required
|
|
11317
|
-
|
|
11318
|
-
- github (for API access)
|
|
11319
|
-
\`\`\`
|
|
11320
|
-
|
|
11321
|
-
### Data Pipeline Agent
|
|
11322
|
-
|
|
11323
|
-
\`\`\`markdown
|
|
11324
|
-
# Agent Instructions
|
|
11325
|
-
|
|
11326
|
-
You are a data pipeline agent that processes CSV files.
|
|
11327
|
-
|
|
11328
|
-
## Workflow
|
|
11329
|
-
|
|
11330
|
-
1. Read all CSV files from the input volume
|
|
11331
|
-
2. For each file:
|
|
11332
|
-
- Validate the schema
|
|
11333
|
-
- Clean missing values
|
|
11334
|
-
- Transform dates to ISO format
|
|
11335
|
-
3. Merge all files into \`combined.csv\`
|
|
11336
|
-
4. Generate a summary report
|
|
11337
|
-
|
|
11338
|
-
## Input
|
|
11339
|
-
|
|
11340
|
-
Files are provided via volume mount.
|
|
11341
|
-
|
|
11342
|
-
## Output
|
|
11343
|
-
|
|
11344
|
-
Write results to the artifact directory.
|
|
11345
|
-
\`\`\`
|
|
11346
|
-
|
|
11347
|
-
## Best Practices
|
|
11348
|
-
|
|
11349
|
-
1. **Be Specific**: Vague instructions lead to unpredictable results
|
|
11350
|
-
2. **One Task Per Step**: Keep workflow steps focused and atomic
|
|
11351
|
-
3. **Define Output Clearly**: Specify exact file names and formats
|
|
11352
|
-
4. **Handle Errors**: Include what to do when things go wrong
|
|
11353
|
-
5. **Test Incrementally**: Start with simple workflows, add complexity
|
|
11354
|
-
6. **Use Skills Wisely**: Only include skills the agent actually needs
|
|
11355
|
-
|
|
11356
|
-
## Troubleshooting
|
|
11357
|
-
|
|
11358
|
-
### Agent doesn't follow instructions
|
|
11359
|
-
- Make instructions more specific and explicit
|
|
11360
|
-
- Add examples of expected behavior
|
|
11361
|
-
- Break complex steps into smaller sub-steps
|
|
11362
|
-
|
|
11363
|
-
### Agent uses wrong tools
|
|
11364
|
-
- Specify which tools/skills to use for each step
|
|
11365
|
-
- Add constraints about what NOT to do
|
|
11366
|
-
|
|
11367
|
-
### Output format is wrong
|
|
11368
|
-
- Provide exact templates for output files
|
|
11369
|
-
- Include example output in the instructions
|
|
11370
|
-
`;
|
|
11371
|
-
var setupClaudeCommand = new Command47().name("setup-claude").description("Add/update Claude skill for agent building").option(
|
|
11372
|
-
"--agent-dir <dir>",
|
|
11373
|
-
"Agent directory (shown in next step instructions)"
|
|
11374
|
-
).action(async (options) => {
|
|
11375
|
-
console.log(chalk49.dim("Installing vm0-agent-builder skill..."));
|
|
11376
|
-
await mkdir9(SKILL_DIR2, { recursive: true });
|
|
11377
|
-
await writeFile8(path15.join(SKILL_DIR2, "SKILL.md"), SKILL_CONTENT);
|
|
11378
|
-
console.log(
|
|
11379
|
-
chalk49.green(`Done Installed vm0-agent-builder skill to ${SKILL_DIR2}`)
|
|
11380
|
-
);
|
|
11164
|
+
import { Command as Command49 } from "commander";
|
|
11165
|
+
import chalk52 from "chalk";
|
|
11166
|
+
var setupClaudeCommand = new Command49().name("setup-claude").description("Install VM0 Claude Plugin").option("--agent-dir <dir>", "Agent directory to run install in").option("--scope <scope>", "Installation scope (user or project)", "project").action(async (options) => {
|
|
11167
|
+
console.log(chalk52.dim("Installing VM0 Claude Plugin..."));
|
|
11168
|
+
const scope = options.scope === "user" ? "user" : "project";
|
|
11169
|
+
try {
|
|
11170
|
+
const result = await installVm0Plugin(scope, options.agentDir);
|
|
11171
|
+
console.log(
|
|
11172
|
+
chalk52.green(`\u2713 Installed ${result.pluginId} (scope: ${result.scope})`)
|
|
11173
|
+
);
|
|
11174
|
+
} catch (error) {
|
|
11175
|
+
handlePluginError(error);
|
|
11176
|
+
}
|
|
11381
11177
|
console.log();
|
|
11382
11178
|
console.log("Next step:");
|
|
11383
11179
|
const cdPrefix = options.agentDir ? `cd ${options.agentDir} && ` : "";
|
|
11384
11180
|
console.log(
|
|
11385
|
-
|
|
11386
|
-
` ${cdPrefix}claude "
|
|
11181
|
+
chalk52.cyan(
|
|
11182
|
+
` ${cdPrefix}claude "/${PRIMARY_SKILL_NAME} let's build a workflow"`
|
|
11387
11183
|
)
|
|
11388
11184
|
);
|
|
11389
11185
|
});
|
|
11390
11186
|
|
|
11391
11187
|
// src/index.ts
|
|
11392
|
-
var program = new
|
|
11393
|
-
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.
|
|
11188
|
+
var program = new Command50();
|
|
11189
|
+
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("9.4.0");
|
|
11394
11190
|
program.command("info").description("Display environment information").action(async () => {
|
|
11395
|
-
console.log(
|
|
11191
|
+
console.log(chalk53.bold("System Information:"));
|
|
11396
11192
|
console.log(`Node Version: ${process.version}`);
|
|
11397
11193
|
console.log(`Platform: ${process.platform}`);
|
|
11398
11194
|
console.log(`Architecture: ${process.arch}`);
|