@vm0/cli 7.1.0 → 8.0.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 +1032 -1592
- 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 Command45 } from "commander";
|
|
5
|
+
import chalk45 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/lib/api/auth.ts
|
|
8
8
|
import chalk from "chalk";
|
|
@@ -79,7 +79,7 @@ async function exchangeToken(apiUrl, deviceCode) {
|
|
|
79
79
|
return response.json();
|
|
80
80
|
}
|
|
81
81
|
function delay(ms) {
|
|
82
|
-
return new Promise((
|
|
82
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
83
83
|
}
|
|
84
84
|
async function authenticate(apiUrl) {
|
|
85
85
|
const targetApiUrl = apiUrl ?? await getApiUrl();
|
|
@@ -3024,10 +3024,10 @@ async function getRawHeaders() {
|
|
|
3024
3024
|
}
|
|
3025
3025
|
return headers;
|
|
3026
3026
|
}
|
|
3027
|
-
async function httpGet(
|
|
3027
|
+
async function httpGet(path14) {
|
|
3028
3028
|
const baseUrl = await getBaseUrl();
|
|
3029
3029
|
const headers = await getRawHeaders();
|
|
3030
|
-
return fetch(`${baseUrl}${
|
|
3030
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
3031
3031
|
method: "GET",
|
|
3032
3032
|
headers
|
|
3033
3033
|
});
|
|
@@ -3588,49 +3588,49 @@ var cliComposeSchema = z23.object({
|
|
|
3588
3588
|
function formatZodError(error) {
|
|
3589
3589
|
const issue = error.issues[0];
|
|
3590
3590
|
if (!issue) return "Validation failed";
|
|
3591
|
-
const
|
|
3591
|
+
const path14 = issue.path.join(".");
|
|
3592
3592
|
const message = issue.message;
|
|
3593
|
-
if (!
|
|
3593
|
+
if (!path14) return message;
|
|
3594
3594
|
if (issue.code === "invalid_type") {
|
|
3595
3595
|
const received = issue.received;
|
|
3596
3596
|
const isMissing = received === "undefined" || message.includes("received undefined") || message === "Required";
|
|
3597
|
-
if (
|
|
3597
|
+
if (path14 === "version" && isMissing) {
|
|
3598
3598
|
return "Missing config.version";
|
|
3599
3599
|
}
|
|
3600
|
-
if (
|
|
3600
|
+
if (path14 === "agents" && isMissing) {
|
|
3601
3601
|
return "Missing agents object in config";
|
|
3602
3602
|
}
|
|
3603
|
-
if (
|
|
3604
|
-
const volumeKey =
|
|
3603
|
+
if (path14.startsWith("volumes.") && path14.endsWith(".name")) {
|
|
3604
|
+
const volumeKey = path14.split(".")[1];
|
|
3605
3605
|
return `Volume "${volumeKey}" must have a 'name' field (string)`;
|
|
3606
3606
|
}
|
|
3607
|
-
if (
|
|
3608
|
-
const volumeKey =
|
|
3607
|
+
if (path14.startsWith("volumes.") && path14.endsWith(".version")) {
|
|
3608
|
+
const volumeKey = path14.split(".")[1];
|
|
3609
3609
|
return `Volume "${volumeKey}" must have a 'version' field (string)`;
|
|
3610
3610
|
}
|
|
3611
3611
|
if (issue.expected === "array") {
|
|
3612
|
-
const fieldName =
|
|
3612
|
+
const fieldName = path14.replace(/^agents\.[^.]+\./, "agent.");
|
|
3613
3613
|
return `${fieldName} must be an array`;
|
|
3614
3614
|
}
|
|
3615
3615
|
if (issue.expected === "string" && received === "number") {
|
|
3616
|
-
const fieldName =
|
|
3616
|
+
const fieldName = path14.replace(/^agents\.[^.]+\./, "agent.");
|
|
3617
3617
|
const match = fieldName.match(/^(agent\.[^.]+)\.\d+$/);
|
|
3618
3618
|
if (match) {
|
|
3619
3619
|
return `Each entry in ${match[1]?.replace("agent.", "")} must be a string`;
|
|
3620
3620
|
}
|
|
3621
3621
|
}
|
|
3622
3622
|
}
|
|
3623
|
-
if (issue.code === "invalid_key" &&
|
|
3623
|
+
if (issue.code === "invalid_key" && path14.startsWith("agents.")) {
|
|
3624
3624
|
return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
|
|
3625
3625
|
}
|
|
3626
|
-
if (message === "Invalid key in record" &&
|
|
3626
|
+
if (message === "Invalid key in record" && path14.startsWith("agents.")) {
|
|
3627
3627
|
return "Invalid agent name format. Must be 3-64 characters, letters, numbers, and hyphens only. Must start and end with letter or number.";
|
|
3628
3628
|
}
|
|
3629
3629
|
if (issue.code === "custom") {
|
|
3630
3630
|
return message;
|
|
3631
3631
|
}
|
|
3632
|
-
if (
|
|
3633
|
-
const cleanPath =
|
|
3632
|
+
if (path14.startsWith("agents.")) {
|
|
3633
|
+
const cleanPath = path14.replace(/^agents\.[^.]+\./, "agent.");
|
|
3634
3634
|
if (message.startsWith("Invalid input:")) {
|
|
3635
3635
|
const match = message.match(/expected (\w+), received (\w+)/);
|
|
3636
3636
|
if (match && match[1] === "string" && match[2] === "number") {
|
|
@@ -3642,7 +3642,7 @@ function formatZodError(error) {
|
|
|
3642
3642
|
}
|
|
3643
3643
|
return `${cleanPath}: ${message}`;
|
|
3644
3644
|
}
|
|
3645
|
-
return `${
|
|
3645
|
+
return `${path14}: ${message}`;
|
|
3646
3646
|
}
|
|
3647
3647
|
function validateAgentName(name) {
|
|
3648
3648
|
return cliAgentNameSchema.safeParse(name).success;
|
|
@@ -3815,7 +3815,7 @@ function excludeVm0Filter(filePath) {
|
|
|
3815
3815
|
return !shouldExclude;
|
|
3816
3816
|
}
|
|
3817
3817
|
function listTarFiles(tarPath) {
|
|
3818
|
-
return new Promise((
|
|
3818
|
+
return new Promise((resolve, reject) => {
|
|
3819
3819
|
const files = [];
|
|
3820
3820
|
tar.list({
|
|
3821
3821
|
file: tarPath,
|
|
@@ -3824,7 +3824,7 @@ function listTarFiles(tarPath) {
|
|
|
3824
3824
|
files.push(entry.path);
|
|
3825
3825
|
}
|
|
3826
3826
|
}
|
|
3827
|
-
}).then(() =>
|
|
3827
|
+
}).then(() => resolve(files)).catch(reject);
|
|
3828
3828
|
});
|
|
3829
3829
|
}
|
|
3830
3830
|
async function listLocalFiles(dir, excludeDirs = [".vm0"]) {
|
|
@@ -3886,11 +3886,11 @@ async function removeEmptyDirs(dir, excludeDirs = [".vm0"]) {
|
|
|
3886
3886
|
|
|
3887
3887
|
// src/lib/storage/direct-upload.ts
|
|
3888
3888
|
async function hashFileStream(filePath) {
|
|
3889
|
-
return new Promise((
|
|
3889
|
+
return new Promise((resolve, reject) => {
|
|
3890
3890
|
const hash = createHash("sha256");
|
|
3891
3891
|
const stream = fs3.createReadStream(filePath);
|
|
3892
3892
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
3893
|
-
stream.on("end", () =>
|
|
3893
|
+
stream.on("end", () => resolve(hash.digest("hex")));
|
|
3894
3894
|
stream.on("error", reject);
|
|
3895
3895
|
});
|
|
3896
3896
|
}
|
|
@@ -3975,7 +3975,7 @@ function createManifest(files) {
|
|
|
3975
3975
|
return Buffer.from(JSON.stringify(manifest, null, 2));
|
|
3976
3976
|
}
|
|
3977
3977
|
function sleep(ms) {
|
|
3978
|
-
return new Promise((
|
|
3978
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3979
3979
|
}
|
|
3980
3980
|
async function uploadToPresignedUrl(presignedUrl, data, contentType, maxRetries = 3) {
|
|
3981
3981
|
let lastError = null;
|
|
@@ -4549,7 +4549,6 @@ var EventRenderer = class {
|
|
|
4549
4549
|
// src/commands/run/shared.ts
|
|
4550
4550
|
import chalk5 from "chalk";
|
|
4551
4551
|
import * as fs5 from "fs";
|
|
4552
|
-
import * as path5 from "path";
|
|
4553
4552
|
import { config as dotenvConfig } from "dotenv";
|
|
4554
4553
|
|
|
4555
4554
|
// src/lib/events/claude-event-parser.ts
|
|
@@ -5783,7 +5782,7 @@ var ApiClient = class {
|
|
|
5783
5782
|
/**
|
|
5784
5783
|
* Generic GET request
|
|
5785
5784
|
*/
|
|
5786
|
-
async get(
|
|
5785
|
+
async get(path14) {
|
|
5787
5786
|
const baseUrl = await this.getBaseUrl();
|
|
5788
5787
|
const token = await getToken();
|
|
5789
5788
|
if (!token) {
|
|
@@ -5796,7 +5795,7 @@ var ApiClient = class {
|
|
|
5796
5795
|
if (bypassSecret) {
|
|
5797
5796
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
5798
5797
|
}
|
|
5799
|
-
return fetch(`${baseUrl}${
|
|
5798
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
5800
5799
|
method: "GET",
|
|
5801
5800
|
headers
|
|
5802
5801
|
});
|
|
@@ -5804,7 +5803,7 @@ var ApiClient = class {
|
|
|
5804
5803
|
/**
|
|
5805
5804
|
* Generic POST request
|
|
5806
5805
|
*/
|
|
5807
|
-
async post(
|
|
5806
|
+
async post(path14, options) {
|
|
5808
5807
|
const baseUrl = await this.getBaseUrl();
|
|
5809
5808
|
const token = await getToken();
|
|
5810
5809
|
if (!token) {
|
|
@@ -5820,7 +5819,7 @@ var ApiClient = class {
|
|
|
5820
5819
|
if (bypassSecret) {
|
|
5821
5820
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
5822
5821
|
}
|
|
5823
|
-
return fetch(`${baseUrl}${
|
|
5822
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
5824
5823
|
method: "POST",
|
|
5825
5824
|
headers,
|
|
5826
5825
|
body: options?.body
|
|
@@ -5829,7 +5828,7 @@ var ApiClient = class {
|
|
|
5829
5828
|
/**
|
|
5830
5829
|
* Generic DELETE request
|
|
5831
5830
|
*/
|
|
5832
|
-
async delete(
|
|
5831
|
+
async delete(path14) {
|
|
5833
5832
|
const baseUrl = await this.getBaseUrl();
|
|
5834
5833
|
const token = await getToken();
|
|
5835
5834
|
if (!token) {
|
|
@@ -5842,7 +5841,7 @@ var ApiClient = class {
|
|
|
5842
5841
|
if (bypassSecret) {
|
|
5843
5842
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
5844
5843
|
}
|
|
5845
|
-
return fetch(`${baseUrl}${
|
|
5844
|
+
return fetch(`${baseUrl}${path14}`, {
|
|
5846
5845
|
method: "DELETE",
|
|
5847
5846
|
headers
|
|
5848
5847
|
});
|
|
@@ -5887,7 +5886,7 @@ async function streamEvents(runId, options) {
|
|
|
5887
5886
|
const ablyClient = createRealtimeClient(async () => {
|
|
5888
5887
|
return apiClient.getRealtimeToken(runId);
|
|
5889
5888
|
});
|
|
5890
|
-
return new Promise((
|
|
5889
|
+
return new Promise((resolve, reject) => {
|
|
5891
5890
|
const channelName = getRunChannelName(runId);
|
|
5892
5891
|
const channel = ablyClient.channels.get(channelName, {
|
|
5893
5892
|
params: { rewind: "2m" }
|
|
@@ -5948,7 +5947,7 @@ async function streamEvents(runId, options) {
|
|
|
5948
5947
|
result = { succeeded: false, runId };
|
|
5949
5948
|
}
|
|
5950
5949
|
cleanup();
|
|
5951
|
-
|
|
5950
|
+
resolve(result);
|
|
5952
5951
|
}
|
|
5953
5952
|
}
|
|
5954
5953
|
channel.subscribe(handleMessage).catch((err) => {
|
|
@@ -5992,30 +5991,32 @@ function extractSecretNames(composeContent) {
|
|
|
5992
5991
|
const grouped = groupVariablesBySource(refs);
|
|
5993
5992
|
return grouped.secrets.map((r) => r.name);
|
|
5994
5993
|
}
|
|
5995
|
-
function loadValues(cliValues, configNames) {
|
|
5994
|
+
function loadValues(cliValues, configNames, envFilePath) {
|
|
5996
5995
|
const result = { ...cliValues };
|
|
5997
5996
|
const missingNames = configNames.filter((name) => !(name in result));
|
|
5998
5997
|
if (missingNames.length > 0) {
|
|
5999
|
-
const
|
|
6000
|
-
|
|
6001
|
-
|
|
5998
|
+
const envValues = {};
|
|
5999
|
+
for (const name of missingNames) {
|
|
6000
|
+
const envValue = process.env[name];
|
|
6001
|
+
if (envValue !== void 0) {
|
|
6002
|
+
envValues[name] = envValue;
|
|
6003
|
+
}
|
|
6004
|
+
}
|
|
6005
|
+
let fileValues = {};
|
|
6006
|
+
if (envFilePath) {
|
|
6007
|
+
if (!fs5.existsSync(envFilePath)) {
|
|
6008
|
+
throw new Error(`Environment file not found: ${envFilePath}`);
|
|
6009
|
+
}
|
|
6002
6010
|
const dotenvResult = dotenvConfig({ path: envFilePath, quiet: true });
|
|
6003
6011
|
if (dotenvResult.parsed) {
|
|
6004
|
-
|
|
6012
|
+
fileValues = Object.fromEntries(
|
|
6005
6013
|
Object.entries(dotenvResult.parsed).filter(
|
|
6006
6014
|
([key]) => missingNames.includes(key)
|
|
6007
6015
|
)
|
|
6008
6016
|
);
|
|
6009
6017
|
}
|
|
6010
6018
|
}
|
|
6011
|
-
|
|
6012
|
-
for (const name of missingNames) {
|
|
6013
|
-
const envValue = process.env[name];
|
|
6014
|
-
if (envValue !== void 0) {
|
|
6015
|
-
envValues[name] = envValue;
|
|
6016
|
-
}
|
|
6017
|
-
}
|
|
6018
|
-
Object.assign(result, dotenvValues, envValues);
|
|
6019
|
+
Object.assign(result, envValues, fileValues);
|
|
6019
6020
|
}
|
|
6020
6021
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
6021
6022
|
}
|
|
@@ -6130,7 +6131,7 @@ async function pollEvents(runId, options) {
|
|
|
6130
6131
|
result = { succeeded: false, runId };
|
|
6131
6132
|
}
|
|
6132
6133
|
if (!complete) {
|
|
6133
|
-
await new Promise((
|
|
6134
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
6134
6135
|
}
|
|
6135
6136
|
}
|
|
6136
6137
|
return result;
|
|
@@ -6173,13 +6174,16 @@ var mainRunCommand = new Command2().name("run").description("Run an agent").argu
|
|
|
6173
6174
|
"<agent-name>",
|
|
6174
6175
|
"Agent reference: [scope/]name[:version] (e.g., 'my-agent', 'lancy/my-agent:abc123', 'my-agent:latest')"
|
|
6175
6176
|
).argument("<prompt>", "Prompt for the agent").option(
|
|
6177
|
+
"--env-file <path>",
|
|
6178
|
+
"Load environment variables from file (priority: CLI flags > file > env vars)"
|
|
6179
|
+
).option(
|
|
6176
6180
|
"--vars <KEY=value>",
|
|
6177
|
-
"Variables for ${{ vars.xxx }} (repeatable, falls back to env
|
|
6181
|
+
"Variables for ${{ vars.xxx }} (repeatable, falls back to --env-file or env vars)",
|
|
6178
6182
|
collectKeyValue,
|
|
6179
6183
|
{}
|
|
6180
6184
|
).option(
|
|
6181
6185
|
"--secrets <KEY=value>",
|
|
6182
|
-
"Secrets for ${{ secrets.xxx }} (repeatable, falls back to env
|
|
6186
|
+
"Secrets for ${{ secrets.xxx }} (repeatable, falls back to --env-file or env vars)",
|
|
6183
6187
|
collectKeyValue,
|
|
6184
6188
|
{}
|
|
6185
6189
|
).option("--artifact-name <name>", "Artifact storage name (required for run)").option(
|
|
@@ -6256,9 +6260,13 @@ var mainRunCommand = new Command2().name("run").description("Run an agent").argu
|
|
|
6256
6260
|
}
|
|
6257
6261
|
}
|
|
6258
6262
|
const varNames = extractVarNames(composeContent);
|
|
6259
|
-
const vars = loadValues(options.vars, varNames);
|
|
6263
|
+
const vars = loadValues(options.vars, varNames, options.envFile);
|
|
6260
6264
|
const secretNames = extractSecretNames(composeContent);
|
|
6261
|
-
const secrets = loadValues(
|
|
6265
|
+
const secrets = loadValues(
|
|
6266
|
+
options.secrets,
|
|
6267
|
+
secretNames,
|
|
6268
|
+
options.envFile
|
|
6269
|
+
);
|
|
6262
6270
|
if (verbose && varNames.length > 0) {
|
|
6263
6271
|
console.log(chalk6.dim(` Required vars: ${varNames.join(", ")}`));
|
|
6264
6272
|
if (vars) {
|
|
@@ -6350,6 +6358,8 @@ var mainRunCommand = new Command2().name("run").description("Run an agent").argu
|
|
|
6350
6358
|
console.error(
|
|
6351
6359
|
chalk6.dim(" Make sure the version hash is correct.")
|
|
6352
6360
|
);
|
|
6361
|
+
} else if (error.message.startsWith("Environment file not found:")) {
|
|
6362
|
+
console.error(chalk6.red(`\u2717 ${error.message}`));
|
|
6353
6363
|
} else if (error.message.includes("not found")) {
|
|
6354
6364
|
console.error(chalk6.red(`\u2717 Agent not found: ${identifier}`));
|
|
6355
6365
|
console.error(
|
|
@@ -6373,13 +6383,16 @@ var mainRunCommand = new Command2().name("run").description("Run an agent").argu
|
|
|
6373
6383
|
import { Command as Command3, Option as Option2 } from "commander";
|
|
6374
6384
|
import chalk7 from "chalk";
|
|
6375
6385
|
var resumeCommand = new Command3().name("resume").description("Resume an agent run from a checkpoint (uses all snapshot data)").argument("<checkpointId>", "Checkpoint ID to resume from").argument("<prompt>", "Prompt for the resumed agent").option(
|
|
6386
|
+
"--env-file <path>",
|
|
6387
|
+
"Load environment variables from file (priority: CLI flags > file > env vars)"
|
|
6388
|
+
).option(
|
|
6376
6389
|
"--vars <KEY=value>",
|
|
6377
|
-
"Variables for ${{ vars.xxx }} (repeatable, falls back to env
|
|
6390
|
+
"Variables for ${{ vars.xxx }} (repeatable, falls back to --env-file or env vars)",
|
|
6378
6391
|
collectKeyValue,
|
|
6379
6392
|
{}
|
|
6380
6393
|
).option(
|
|
6381
6394
|
"--secrets <KEY=value>",
|
|
6382
|
-
"Secrets for ${{ secrets.xxx }} (repeatable,
|
|
6395
|
+
"Secrets for ${{ secrets.xxx }} (repeatable, falls back to --env-file or env vars)",
|
|
6383
6396
|
collectKeyValue,
|
|
6384
6397
|
{}
|
|
6385
6398
|
).option(
|
|
@@ -6411,7 +6424,8 @@ var resumeCommand = new Command3().name("resume").description("Resume an agent r
|
|
|
6411
6424
|
}
|
|
6412
6425
|
const checkpointInfo = await getCheckpoint(checkpointId);
|
|
6413
6426
|
const requiredSecretNames = checkpointInfo.agentComposeSnapshot.secretNames || [];
|
|
6414
|
-
const
|
|
6427
|
+
const envFile = options.envFile || allOpts.envFile;
|
|
6428
|
+
const loadedSecrets = loadValues(secrets, requiredSecretNames, envFile);
|
|
6415
6429
|
if (verbose) {
|
|
6416
6430
|
logVerbosePreFlight("Resuming agent run from checkpoint", [
|
|
6417
6431
|
{ label: "Checkpoint ID", value: checkpointId },
|
|
@@ -6474,6 +6488,8 @@ var resumeCommand = new Command3().name("resume").description("Resume an agent r
|
|
|
6474
6488
|
console.error(
|
|
6475
6489
|
chalk7.dim(" Try running without --experimental-realtime")
|
|
6476
6490
|
);
|
|
6491
|
+
} else if (error.message.startsWith("Environment file not found:")) {
|
|
6492
|
+
console.error(chalk7.red(`\u2717 ${error.message}`));
|
|
6477
6493
|
} else if (error.message.includes("not found")) {
|
|
6478
6494
|
console.error(chalk7.red(`\u2717 Checkpoint not found: ${checkpointId}`));
|
|
6479
6495
|
} else {
|
|
@@ -6494,13 +6510,16 @@ import chalk8 from "chalk";
|
|
|
6494
6510
|
var continueCommand = new Command4().name("continue").description(
|
|
6495
6511
|
"Continue an agent run from a session (uses latest artifact version)"
|
|
6496
6512
|
).argument("<agentSessionId>", "Agent session ID to continue from").argument("<prompt>", "Prompt for the continued agent").option(
|
|
6513
|
+
"--env-file <path>",
|
|
6514
|
+
"Load environment variables from file (priority: CLI flags > file > env vars)"
|
|
6515
|
+
).option(
|
|
6497
6516
|
"--vars <KEY=value>",
|
|
6498
|
-
"Variables for ${{ vars.xxx }} (repeatable, falls back to env
|
|
6517
|
+
"Variables for ${{ vars.xxx }} (repeatable, falls back to --env-file or env vars)",
|
|
6499
6518
|
collectKeyValue,
|
|
6500
6519
|
{}
|
|
6501
6520
|
).option(
|
|
6502
6521
|
"--secrets <KEY=value>",
|
|
6503
|
-
"Secrets for ${{ secrets.xxx }} (repeatable,
|
|
6522
|
+
"Secrets for ${{ secrets.xxx }} (repeatable, falls back to --env-file or env vars)",
|
|
6504
6523
|
collectKeyValue,
|
|
6505
6524
|
{}
|
|
6506
6525
|
).option(
|
|
@@ -6532,7 +6551,8 @@ var continueCommand = new Command4().name("continue").description(
|
|
|
6532
6551
|
}
|
|
6533
6552
|
const sessionInfo = await getSession(agentSessionId);
|
|
6534
6553
|
const requiredSecretNames = sessionInfo.secretNames || [];
|
|
6535
|
-
const
|
|
6554
|
+
const envFile = options.envFile || allOpts.envFile;
|
|
6555
|
+
const loadedSecrets = loadValues(secrets, requiredSecretNames, envFile);
|
|
6536
6556
|
if (verbose) {
|
|
6537
6557
|
logVerbosePreFlight("Continuing agent run from session", [
|
|
6538
6558
|
{ label: "Session ID", value: agentSessionId },
|
|
@@ -6596,6 +6616,8 @@ var continueCommand = new Command4().name("continue").description(
|
|
|
6596
6616
|
console.error(
|
|
6597
6617
|
chalk8.dim(" Try running without --experimental-realtime")
|
|
6598
6618
|
);
|
|
6619
|
+
} else if (error.message.startsWith("Environment file not found:")) {
|
|
6620
|
+
console.error(chalk8.red(`\u2717 ${error.message}`));
|
|
6599
6621
|
} else if (error.message.includes("not found")) {
|
|
6600
6622
|
console.error(
|
|
6601
6623
|
chalk8.red(`\u2717 Agent session not found: ${agentSessionId}`)
|
|
@@ -6623,13 +6645,13 @@ import { Command as Command11 } from "commander";
|
|
|
6623
6645
|
// src/commands/volume/init.ts
|
|
6624
6646
|
import { Command as Command5 } from "commander";
|
|
6625
6647
|
import chalk9 from "chalk";
|
|
6626
|
-
import
|
|
6648
|
+
import path6 from "path";
|
|
6627
6649
|
|
|
6628
6650
|
// src/lib/storage/storage-utils.ts
|
|
6629
6651
|
import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
6630
6652
|
import { existsSync as existsSync5 } from "fs";
|
|
6631
6653
|
import { parse as parseYaml3, stringify as stringifyYaml } from "yaml";
|
|
6632
|
-
import
|
|
6654
|
+
import path5 from "path";
|
|
6633
6655
|
var CONFIG_DIR2 = ".vm0";
|
|
6634
6656
|
var CONFIG_FILE2 = "storage.yaml";
|
|
6635
6657
|
function isValidStorageName(name) {
|
|
@@ -6640,8 +6662,8 @@ function isValidStorageName(name) {
|
|
|
6640
6662
|
return pattern.test(name) && !name.includes("--");
|
|
6641
6663
|
}
|
|
6642
6664
|
async function readStorageConfig(basePath = process.cwd()) {
|
|
6643
|
-
const configPath =
|
|
6644
|
-
const legacyConfigPath =
|
|
6665
|
+
const configPath = path5.join(basePath, CONFIG_DIR2, CONFIG_FILE2);
|
|
6666
|
+
const legacyConfigPath = path5.join(basePath, CONFIG_DIR2, "volume.yaml");
|
|
6645
6667
|
let actualPath = null;
|
|
6646
6668
|
if (existsSync5(configPath)) {
|
|
6647
6669
|
actualPath = configPath;
|
|
@@ -6659,8 +6681,8 @@ async function readStorageConfig(basePath = process.cwd()) {
|
|
|
6659
6681
|
return config;
|
|
6660
6682
|
}
|
|
6661
6683
|
async function writeStorageConfig(storageName, basePath = process.cwd(), type = "volume") {
|
|
6662
|
-
const configDir =
|
|
6663
|
-
const configPath =
|
|
6684
|
+
const configDir = path5.join(basePath, CONFIG_DIR2);
|
|
6685
|
+
const configPath = path5.join(configDir, CONFIG_FILE2);
|
|
6664
6686
|
if (!existsSync5(configDir)) {
|
|
6665
6687
|
await mkdir4(configDir, { recursive: true });
|
|
6666
6688
|
}
|
|
@@ -6741,14 +6763,14 @@ async function promptSelect(message, choices, initial) {
|
|
|
6741
6763
|
var initCommand = new Command5().name("init").description("Initialize a volume in the current directory").option("-n, --name <name>", "Volume name (required in non-interactive mode)").action(async (options) => {
|
|
6742
6764
|
try {
|
|
6743
6765
|
const cwd = process.cwd();
|
|
6744
|
-
const dirName =
|
|
6766
|
+
const dirName = path6.basename(cwd);
|
|
6745
6767
|
const existingConfig = await readStorageConfig(cwd);
|
|
6746
6768
|
if (existingConfig) {
|
|
6747
6769
|
console.log(
|
|
6748
6770
|
chalk9.yellow(`Volume already initialized: ${existingConfig.name}`)
|
|
6749
6771
|
);
|
|
6750
6772
|
console.log(
|
|
6751
|
-
chalk9.dim(`Config file: ${
|
|
6773
|
+
chalk9.dim(`Config file: ${path6.join(cwd, ".vm0", "storage.yaml")}`)
|
|
6752
6774
|
);
|
|
6753
6775
|
return;
|
|
6754
6776
|
}
|
|
@@ -6797,7 +6819,7 @@ var initCommand = new Command5().name("init").description("Initialize a volume i
|
|
|
6797
6819
|
console.log(chalk9.green(`\u2713 Initialized volume: ${volumeName}`));
|
|
6798
6820
|
console.log(
|
|
6799
6821
|
chalk9.dim(
|
|
6800
|
-
`\u2713 Config saved to ${
|
|
6822
|
+
`\u2713 Config saved to ${path6.join(cwd, ".vm0", "storage.yaml")}`
|
|
6801
6823
|
)
|
|
6802
6824
|
);
|
|
6803
6825
|
} catch (error) {
|
|
@@ -6865,7 +6887,7 @@ var pushCommand = new Command6().name("push").description("Push local files to c
|
|
|
6865
6887
|
// src/commands/volume/pull.ts
|
|
6866
6888
|
import { Command as Command7 } from "commander";
|
|
6867
6889
|
import chalk12 from "chalk";
|
|
6868
|
-
import
|
|
6890
|
+
import path7 from "path";
|
|
6869
6891
|
import * as fs6 from "fs";
|
|
6870
6892
|
import * as os4 from "os";
|
|
6871
6893
|
import * as tar3 from "tar";
|
|
@@ -6926,8 +6948,8 @@ var pullCommand = new Command7().name("pull").description("Pull cloud files to l
|
|
|
6926
6948
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
6927
6949
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
6928
6950
|
console.log(chalk12.green(`\u2713 Downloaded ${formatBytes3(tarBuffer.length)}`));
|
|
6929
|
-
const tmpDir = fs6.mkdtempSync(
|
|
6930
|
-
const tarPath =
|
|
6951
|
+
const tmpDir = fs6.mkdtempSync(path7.join(os4.tmpdir(), "vm0-"));
|
|
6952
|
+
const tarPath = path7.join(tmpDir, "volume.tar.gz");
|
|
6931
6953
|
await fs6.promises.writeFile(tarPath, tarBuffer);
|
|
6932
6954
|
console.log(chalk12.dim("Syncing local files..."));
|
|
6933
6955
|
const remoteFiles = await listTarFiles(tarPath);
|
|
@@ -7080,7 +7102,7 @@ import chalk16 from "chalk";
|
|
|
7080
7102
|
|
|
7081
7103
|
// src/lib/storage/clone-utils.ts
|
|
7082
7104
|
import chalk15 from "chalk";
|
|
7083
|
-
import
|
|
7105
|
+
import path8 from "path";
|
|
7084
7106
|
import * as fs7 from "fs";
|
|
7085
7107
|
import * as os5 from "os";
|
|
7086
7108
|
import * as tar4 from "tar";
|
|
@@ -7121,8 +7143,8 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
7121
7143
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
7122
7144
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
7123
7145
|
console.log(chalk15.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
|
|
7124
|
-
const tmpDir = fs7.mkdtempSync(
|
|
7125
|
-
const tarPath =
|
|
7146
|
+
const tmpDir = fs7.mkdtempSync(path8.join(os5.tmpdir(), "vm0-clone-"));
|
|
7147
|
+
const tarPath = path8.join(tmpDir, "archive.tar.gz");
|
|
7126
7148
|
await fs7.promises.writeFile(tarPath, tarBuffer);
|
|
7127
7149
|
const files = await listTarFiles(tarPath);
|
|
7128
7150
|
console.log(chalk15.dim("Extracting files..."));
|
|
@@ -7176,14 +7198,14 @@ import { Command as Command18 } from "commander";
|
|
|
7176
7198
|
// src/commands/artifact/init.ts
|
|
7177
7199
|
import { Command as Command12 } from "commander";
|
|
7178
7200
|
import chalk17 from "chalk";
|
|
7179
|
-
import
|
|
7201
|
+
import path9 from "path";
|
|
7180
7202
|
var initCommand2 = new Command12().name("init").description("Initialize an artifact in the current directory").option(
|
|
7181
7203
|
"-n, --name <name>",
|
|
7182
7204
|
"Artifact name (required in non-interactive mode)"
|
|
7183
7205
|
).action(async (options) => {
|
|
7184
7206
|
try {
|
|
7185
7207
|
const cwd = process.cwd();
|
|
7186
|
-
const dirName =
|
|
7208
|
+
const dirName = path9.basename(cwd);
|
|
7187
7209
|
const existingConfig = await readStorageConfig(cwd);
|
|
7188
7210
|
if (existingConfig) {
|
|
7189
7211
|
if (existingConfig.type === "artifact") {
|
|
@@ -7205,7 +7227,7 @@ var initCommand2 = new Command12().name("init").description("Initialize an artif
|
|
|
7205
7227
|
);
|
|
7206
7228
|
}
|
|
7207
7229
|
console.log(
|
|
7208
|
-
chalk17.dim(`Config file: ${
|
|
7230
|
+
chalk17.dim(`Config file: ${path9.join(cwd, ".vm0", "storage.yaml")}`)
|
|
7209
7231
|
);
|
|
7210
7232
|
return;
|
|
7211
7233
|
}
|
|
@@ -7254,7 +7276,7 @@ var initCommand2 = new Command12().name("init").description("Initialize an artif
|
|
|
7254
7276
|
console.log(chalk17.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
7255
7277
|
console.log(
|
|
7256
7278
|
chalk17.dim(
|
|
7257
|
-
`\u2713 Config saved to ${
|
|
7279
|
+
`\u2713 Config saved to ${path9.join(cwd, ".vm0", "storage.yaml")}`
|
|
7258
7280
|
)
|
|
7259
7281
|
);
|
|
7260
7282
|
} catch (error) {
|
|
@@ -7327,7 +7349,7 @@ var pushCommand2 = new Command13().name("push").description("Push local files to
|
|
|
7327
7349
|
// src/commands/artifact/pull.ts
|
|
7328
7350
|
import { Command as Command14 } from "commander";
|
|
7329
7351
|
import chalk19 from "chalk";
|
|
7330
|
-
import
|
|
7352
|
+
import path10 from "path";
|
|
7331
7353
|
import * as fs8 from "fs";
|
|
7332
7354
|
import * as os6 from "os";
|
|
7333
7355
|
import * as tar5 from "tar";
|
|
@@ -7383,8 +7405,8 @@ var pullCommand2 = new Command14().name("pull").description("Pull cloud artifact
|
|
|
7383
7405
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
7384
7406
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
7385
7407
|
console.log(chalk19.green(`\u2713 Downloaded ${formatBytes6(tarBuffer.length)}`));
|
|
7386
|
-
const tmpDir = fs8.mkdtempSync(
|
|
7387
|
-
const tarPath =
|
|
7408
|
+
const tmpDir = fs8.mkdtempSync(path10.join(os6.tmpdir(), "vm0-"));
|
|
7409
|
+
const tarPath = path10.join(tmpDir, "artifact.tar.gz");
|
|
7388
7410
|
await fs8.promises.writeFile(tarPath, tarBuffer);
|
|
7389
7411
|
console.log(chalk19.dim("Syncing local files..."));
|
|
7390
7412
|
const remoteFiles = await listTarFiles(tarPath);
|
|
@@ -7556,9 +7578,9 @@ var artifactCommand = new Command18().name("artifact").description("Manage artif
|
|
|
7556
7578
|
// src/commands/cook.ts
|
|
7557
7579
|
import { Command as Command19, Option as Option4 } from "commander";
|
|
7558
7580
|
import chalk24 from "chalk";
|
|
7559
|
-
import { readFile as readFile7, mkdir as mkdir6
|
|
7560
|
-
import { existsSync as existsSync8
|
|
7561
|
-
import
|
|
7581
|
+
import { readFile as readFile7, mkdir as mkdir6 } from "fs/promises";
|
|
7582
|
+
import { existsSync as existsSync8 } from "fs";
|
|
7583
|
+
import path11 from "path";
|
|
7562
7584
|
import { spawn as spawn2 } from "child_process";
|
|
7563
7585
|
import { parse as parseYaml4 } from "yaml";
|
|
7564
7586
|
import { config as dotenvConfig2 } from "dotenv";
|
|
@@ -7630,7 +7652,7 @@ async function getLatestVersion() {
|
|
|
7630
7652
|
}
|
|
7631
7653
|
}
|
|
7632
7654
|
function performUpgrade(packageManager) {
|
|
7633
|
-
return new Promise((
|
|
7655
|
+
return new Promise((resolve) => {
|
|
7634
7656
|
const isWindows = process.platform === "win32";
|
|
7635
7657
|
const command = isWindows ? `${packageManager}.cmd` : packageManager;
|
|
7636
7658
|
const args = packageManager === "pnpm" ? ["add", "-g", `${PACKAGE_NAME}@latest`] : ["install", "-g", `${PACKAGE_NAME}@latest`];
|
|
@@ -7639,10 +7661,10 @@ function performUpgrade(packageManager) {
|
|
|
7639
7661
|
shell: isWindows
|
|
7640
7662
|
});
|
|
7641
7663
|
child.on("close", (code) => {
|
|
7642
|
-
|
|
7664
|
+
resolve(code === 0);
|
|
7643
7665
|
});
|
|
7644
7666
|
child.on("error", () => {
|
|
7645
|
-
|
|
7667
|
+
resolve(false);
|
|
7646
7668
|
});
|
|
7647
7669
|
});
|
|
7648
7670
|
}
|
|
@@ -7774,7 +7796,7 @@ function printCommand(cmd) {
|
|
|
7774
7796
|
console.log(chalk24.dim(`> ${cmd}`));
|
|
7775
7797
|
}
|
|
7776
7798
|
function execVm0Command(args, options = {}) {
|
|
7777
|
-
return new Promise((
|
|
7799
|
+
return new Promise((resolve, reject) => {
|
|
7778
7800
|
const stdio = options.silent ? "pipe" : "inherit";
|
|
7779
7801
|
const proc = spawn2("vm0", args, {
|
|
7780
7802
|
cwd: options.cwd,
|
|
@@ -7793,7 +7815,7 @@ function execVm0Command(args, options = {}) {
|
|
|
7793
7815
|
}
|
|
7794
7816
|
proc.on("close", (code) => {
|
|
7795
7817
|
if (code === 0) {
|
|
7796
|
-
|
|
7818
|
+
resolve(stdout);
|
|
7797
7819
|
} else {
|
|
7798
7820
|
reject(new Error(stderr || `Command failed with exit code ${code}`));
|
|
7799
7821
|
}
|
|
@@ -7804,7 +7826,7 @@ function execVm0Command(args, options = {}) {
|
|
|
7804
7826
|
});
|
|
7805
7827
|
}
|
|
7806
7828
|
function execVm0RunWithCapture(args, options = {}) {
|
|
7807
|
-
return new Promise((
|
|
7829
|
+
return new Promise((resolve, reject) => {
|
|
7808
7830
|
const proc = spawn2("vm0", args, {
|
|
7809
7831
|
cwd: options.cwd,
|
|
7810
7832
|
stdio: ["inherit", "pipe", "pipe"],
|
|
@@ -7824,7 +7846,7 @@ function execVm0RunWithCapture(args, options = {}) {
|
|
|
7824
7846
|
});
|
|
7825
7847
|
proc.on("close", (code) => {
|
|
7826
7848
|
if (code === 0) {
|
|
7827
|
-
|
|
7849
|
+
resolve(stdout);
|
|
7828
7850
|
} else {
|
|
7829
7851
|
reject(new Error(stderr || `Command failed with exit code ${code}`));
|
|
7830
7852
|
}
|
|
@@ -7871,36 +7893,26 @@ function extractRequiredVarNames(config) {
|
|
|
7871
7893
|
return [.../* @__PURE__ */ new Set([...varNames, ...secretNames])];
|
|
7872
7894
|
}
|
|
7873
7895
|
function checkMissingVariables(varNames, envFilePath) {
|
|
7874
|
-
let
|
|
7875
|
-
if (
|
|
7896
|
+
let fileValues = {};
|
|
7897
|
+
if (envFilePath) {
|
|
7898
|
+
if (!existsSync8(envFilePath)) {
|
|
7899
|
+
throw new Error(`Environment file not found: ${envFilePath}`);
|
|
7900
|
+
}
|
|
7876
7901
|
const result = dotenvConfig2({ path: envFilePath, quiet: true });
|
|
7877
7902
|
if (result.parsed) {
|
|
7878
|
-
|
|
7903
|
+
fileValues = result.parsed;
|
|
7879
7904
|
}
|
|
7880
7905
|
}
|
|
7881
7906
|
const missing = [];
|
|
7882
7907
|
for (const name of varNames) {
|
|
7883
7908
|
const inEnv = process.env[name] !== void 0;
|
|
7884
|
-
const
|
|
7885
|
-
if (!inEnv && !
|
|
7909
|
+
const inFile = fileValues[name] !== void 0;
|
|
7910
|
+
if (!inEnv && !inFile) {
|
|
7886
7911
|
missing.push(name);
|
|
7887
7912
|
}
|
|
7888
7913
|
}
|
|
7889
7914
|
return missing;
|
|
7890
7915
|
}
|
|
7891
|
-
async function generateEnvPlaceholders(missingVars, envFilePath) {
|
|
7892
|
-
const placeholders = missingVars.map((name) => `${name}=`).join("\n");
|
|
7893
|
-
if (existsSync8(envFilePath)) {
|
|
7894
|
-
const existingContent = readFileSync(envFilePath, "utf8");
|
|
7895
|
-
const needsNewline = existingContent.length > 0 && !existingContent.endsWith("\n");
|
|
7896
|
-
const prefix = needsNewline ? "\n" : "";
|
|
7897
|
-
await appendFile(envFilePath, `${prefix}${placeholders}
|
|
7898
|
-
`);
|
|
7899
|
-
} else {
|
|
7900
|
-
await writeFile6(envFilePath, `${placeholders}
|
|
7901
|
-
`);
|
|
7902
|
-
}
|
|
7903
|
-
}
|
|
7904
7916
|
async function autoPullArtifact(runOutput, artifactDir) {
|
|
7905
7917
|
const serverVersion = parseArtifactVersionFromCompletion(
|
|
7906
7918
|
runOutput,
|
|
@@ -7926,11 +7938,14 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
7926
7938
|
}
|
|
7927
7939
|
}
|
|
7928
7940
|
var cookCmd = new Command19().name("cook").description("Quick start: prepare, compose and run agent from vm0.yaml");
|
|
7929
|
-
cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
7941
|
+
cookCmd.argument("[prompt]", "Prompt for the agent").option(
|
|
7942
|
+
"--env-file <path>",
|
|
7943
|
+
"Load environment variables from file (priority: CLI flags > file > env vars)"
|
|
7944
|
+
).option("-y, --yes", "Skip confirmation prompts").addOption(new Option4("--debug-no-mock-claude").hideHelp()).addOption(new Option4("--no-auto-update").hideHelp()).action(
|
|
7930
7945
|
// eslint-disable-next-line complexity -- TODO: refactor complex function
|
|
7931
7946
|
async (prompt, options) => {
|
|
7932
7947
|
if (!options.noAutoUpdate) {
|
|
7933
|
-
const shouldExit = await checkAndUpgrade("
|
|
7948
|
+
const shouldExit = await checkAndUpgrade("8.0.0", prompt);
|
|
7934
7949
|
if (shouldExit) {
|
|
7935
7950
|
process.exit(0);
|
|
7936
7951
|
}
|
|
@@ -7965,21 +7980,27 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
|
|
|
7965
7980
|
);
|
|
7966
7981
|
const requiredVarNames = extractRequiredVarNames(config);
|
|
7967
7982
|
if (requiredVarNames.length > 0) {
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
);
|
|
7973
|
-
if (missingVars.length > 0) {
|
|
7974
|
-
await generateEnvPlaceholders(missingVars, envFilePath);
|
|
7975
|
-
console.log();
|
|
7976
|
-
console.log(
|
|
7977
|
-
chalk24.yellow(
|
|
7978
|
-
`\u26A0 Missing environment variables. Please fill in values in .env file:`
|
|
7979
|
-
)
|
|
7983
|
+
try {
|
|
7984
|
+
const missingVars = checkMissingVariables(
|
|
7985
|
+
requiredVarNames,
|
|
7986
|
+
options.envFile
|
|
7980
7987
|
);
|
|
7981
|
-
|
|
7982
|
-
console.log(
|
|
7988
|
+
if (missingVars.length > 0) {
|
|
7989
|
+
console.log();
|
|
7990
|
+
console.error(chalk24.red("\u2717 Missing required variables:"));
|
|
7991
|
+
for (const varName of missingVars) {
|
|
7992
|
+
console.error(chalk24.red(` ${varName}`));
|
|
7993
|
+
}
|
|
7994
|
+
console.error(
|
|
7995
|
+
chalk24.dim(
|
|
7996
|
+
"\n Provide via --env-file, or set as environment variables"
|
|
7997
|
+
)
|
|
7998
|
+
);
|
|
7999
|
+
process.exit(1);
|
|
8000
|
+
}
|
|
8001
|
+
} catch (error) {
|
|
8002
|
+
if (error instanceof Error) {
|
|
8003
|
+
console.error(chalk24.red(`\u2717 ${error.message}`));
|
|
7983
8004
|
}
|
|
7984
8005
|
process.exit(1);
|
|
7985
8006
|
}
|
|
@@ -7988,7 +8009,7 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
|
|
|
7988
8009
|
console.log();
|
|
7989
8010
|
console.log(chalk24.bold("Processing volumes:"));
|
|
7990
8011
|
for (const volumeConfig of Object.values(config.volumes)) {
|
|
7991
|
-
const volumeDir =
|
|
8012
|
+
const volumeDir = path11.join(cwd, volumeConfig.name);
|
|
7992
8013
|
if (!existsSync8(volumeDir)) {
|
|
7993
8014
|
console.error(
|
|
7994
8015
|
chalk24.red(
|
|
@@ -8027,7 +8048,7 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
|
|
|
8027
8048
|
}
|
|
8028
8049
|
console.log();
|
|
8029
8050
|
console.log(chalk24.bold("Processing artifact:"));
|
|
8030
|
-
const artifactDir =
|
|
8051
|
+
const artifactDir = path11.join(cwd, ARTIFACT_DIR);
|
|
8031
8052
|
try {
|
|
8032
8053
|
if (!existsSync8(artifactDir)) {
|
|
8033
8054
|
printCommand(`mkdir ${ARTIFACT_DIR}`);
|
|
@@ -8156,80 +8177,98 @@ cookCmd.command("logs").description("View logs from the last cook run").option("
|
|
|
8156
8177
|
);
|
|
8157
8178
|
cookCmd.command("continue").description(
|
|
8158
8179
|
"Continue from the last session (latest conversation and artifact)"
|
|
8159
|
-
).argument("<prompt>", "Prompt for the continued agent").
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
"continue",
|
|
8176
|
-
state.lastSessionId,
|
|
8177
|
-
...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
|
|
8178
|
-
prompt
|
|
8179
|
-
],
|
|
8180
|
-
{ cwd }
|
|
8180
|
+
).argument("<prompt>", "Prompt for the continued agent").option(
|
|
8181
|
+
"--env-file <path>",
|
|
8182
|
+
"Load environment variables from file (priority: CLI flags > file > env vars)"
|
|
8183
|
+
).addOption(new Option4("--debug-no-mock-claude").hideHelp()).action(
|
|
8184
|
+
async (prompt, options) => {
|
|
8185
|
+
const state = await loadCookState();
|
|
8186
|
+
if (!state.lastSessionId) {
|
|
8187
|
+
console.error(chalk24.red("\u2717 No previous session found"));
|
|
8188
|
+
console.error(chalk24.dim(" Run 'vm0 cook <prompt>' first"));
|
|
8189
|
+
process.exit(1);
|
|
8190
|
+
}
|
|
8191
|
+
const cwd = process.cwd();
|
|
8192
|
+
const artifactDir = path11.join(cwd, ARTIFACT_DIR);
|
|
8193
|
+
const envFileArg = options.envFile ? ` --env-file ${options.envFile}` : "";
|
|
8194
|
+
printCommand(
|
|
8195
|
+
`vm0 run continue${envFileArg} ${state.lastSessionId} "${prompt}"`
|
|
8181
8196
|
);
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8191
|
-
|
|
8197
|
+
console.log();
|
|
8198
|
+
let runOutput;
|
|
8199
|
+
try {
|
|
8200
|
+
runOutput = await execVm0RunWithCapture(
|
|
8201
|
+
[
|
|
8202
|
+
"run",
|
|
8203
|
+
"continue",
|
|
8204
|
+
...options.envFile ? ["--env-file", options.envFile] : [],
|
|
8205
|
+
state.lastSessionId,
|
|
8206
|
+
...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
|
|
8207
|
+
prompt
|
|
8208
|
+
],
|
|
8209
|
+
{ cwd }
|
|
8210
|
+
);
|
|
8211
|
+
} catch {
|
|
8212
|
+
process.exit(1);
|
|
8213
|
+
}
|
|
8214
|
+
const newIds = parseRunIdsFromOutput(runOutput);
|
|
8215
|
+
if (newIds.runId || newIds.sessionId || newIds.checkpointId) {
|
|
8216
|
+
await saveCookState({
|
|
8217
|
+
lastRunId: newIds.runId,
|
|
8218
|
+
lastSessionId: newIds.sessionId,
|
|
8219
|
+
lastCheckpointId: newIds.checkpointId
|
|
8220
|
+
});
|
|
8221
|
+
}
|
|
8222
|
+
await autoPullArtifact(runOutput, artifactDir);
|
|
8192
8223
|
}
|
|
8193
|
-
|
|
8194
|
-
});
|
|
8224
|
+
);
|
|
8195
8225
|
cookCmd.command("resume").description(
|
|
8196
8226
|
"Resume from the last checkpoint (snapshotted conversation and artifact)"
|
|
8197
|
-
).argument("<prompt>", "Prompt for the resumed agent").
|
|
8198
|
-
|
|
8199
|
-
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
|
|
8213
|
-
"resume",
|
|
8214
|
-
state.lastCheckpointId,
|
|
8215
|
-
...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
|
|
8216
|
-
prompt
|
|
8217
|
-
],
|
|
8218
|
-
{ cwd }
|
|
8227
|
+
).argument("<prompt>", "Prompt for the resumed agent").option(
|
|
8228
|
+
"--env-file <path>",
|
|
8229
|
+
"Load environment variables from file (priority: CLI flags > file > env vars)"
|
|
8230
|
+
).addOption(new Option4("--debug-no-mock-claude").hideHelp()).action(
|
|
8231
|
+
async (prompt, options) => {
|
|
8232
|
+
const state = await loadCookState();
|
|
8233
|
+
if (!state.lastCheckpointId) {
|
|
8234
|
+
console.error(chalk24.red("\u2717 No previous checkpoint found"));
|
|
8235
|
+
console.error(chalk24.dim(" Run 'vm0 cook <prompt>' first"));
|
|
8236
|
+
process.exit(1);
|
|
8237
|
+
}
|
|
8238
|
+
const cwd = process.cwd();
|
|
8239
|
+
const artifactDir = path11.join(cwd, ARTIFACT_DIR);
|
|
8240
|
+
const envFileArg = options.envFile ? ` --env-file ${options.envFile}` : "";
|
|
8241
|
+
printCommand(
|
|
8242
|
+
`vm0 run resume${envFileArg} ${state.lastCheckpointId} "${prompt}"`
|
|
8219
8243
|
);
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8244
|
+
console.log();
|
|
8245
|
+
let runOutput;
|
|
8246
|
+
try {
|
|
8247
|
+
runOutput = await execVm0RunWithCapture(
|
|
8248
|
+
[
|
|
8249
|
+
"run",
|
|
8250
|
+
"resume",
|
|
8251
|
+
...options.envFile ? ["--env-file", options.envFile] : [],
|
|
8252
|
+
state.lastCheckpointId,
|
|
8253
|
+
...options.debugNoMockClaude ? ["--debug-no-mock-claude"] : [],
|
|
8254
|
+
prompt
|
|
8255
|
+
],
|
|
8256
|
+
{ cwd }
|
|
8257
|
+
);
|
|
8258
|
+
} catch {
|
|
8259
|
+
process.exit(1);
|
|
8260
|
+
}
|
|
8261
|
+
const newIds = parseRunIdsFromOutput(runOutput);
|
|
8262
|
+
if (newIds.runId || newIds.sessionId || newIds.checkpointId) {
|
|
8263
|
+
await saveCookState({
|
|
8264
|
+
lastRunId: newIds.runId,
|
|
8265
|
+
lastSessionId: newIds.sessionId,
|
|
8266
|
+
lastCheckpointId: newIds.checkpointId
|
|
8267
|
+
});
|
|
8268
|
+
}
|
|
8269
|
+
await autoPullArtifact(runOutput, artifactDir);
|
|
8230
8270
|
}
|
|
8231
|
-
|
|
8232
|
-
});
|
|
8271
|
+
);
|
|
8233
8272
|
var cookCommand = cookCmd;
|
|
8234
8273
|
|
|
8235
8274
|
// src/commands/logs/index.ts
|
|
@@ -8659,13 +8698,13 @@ var listCommand3 = new Command24().name("list").alias("ls").description("List al
|
|
|
8659
8698
|
}
|
|
8660
8699
|
});
|
|
8661
8700
|
|
|
8662
|
-
// src/commands/agent/
|
|
8701
|
+
// src/commands/agent/status.ts
|
|
8663
8702
|
import { Command as Command25 } from "commander";
|
|
8664
8703
|
import chalk29 from "chalk";
|
|
8665
8704
|
|
|
8666
8705
|
// src/lib/domain/source-derivation.ts
|
|
8667
8706
|
import * as fs9 from "fs/promises";
|
|
8668
|
-
import * as
|
|
8707
|
+
import * as path12 from "path";
|
|
8669
8708
|
import * as os7 from "os";
|
|
8670
8709
|
function extractVariableReferences2(environment) {
|
|
8671
8710
|
const secrets = [];
|
|
@@ -8715,7 +8754,7 @@ async function deriveAgentVariableSources(agent, options) {
|
|
|
8715
8754
|
};
|
|
8716
8755
|
}
|
|
8717
8756
|
const tempDir = await fs9.mkdtemp(
|
|
8718
|
-
|
|
8757
|
+
path12.join(os7.tmpdir(), "vm0-source-derivation-")
|
|
8719
8758
|
);
|
|
8720
8759
|
try {
|
|
8721
8760
|
const skillResults = await Promise.all(
|
|
@@ -8769,67 +8808,72 @@ async function deriveComposeVariableSources(content, options) {
|
|
|
8769
8808
|
return results;
|
|
8770
8809
|
}
|
|
8771
8810
|
|
|
8772
|
-
// src/commands/agent/
|
|
8811
|
+
// src/commands/agent/status.ts
|
|
8812
|
+
function formatListSection(label, items) {
|
|
8813
|
+
if (items.length === 0) return;
|
|
8814
|
+
console.log(` ${label}:`);
|
|
8815
|
+
for (const item of items) {
|
|
8816
|
+
console.log(` - ${item}`);
|
|
8817
|
+
}
|
|
8818
|
+
}
|
|
8819
|
+
function formatVolumes(volumes, volumeConfigs) {
|
|
8820
|
+
if (volumes.length === 0) return;
|
|
8821
|
+
console.log(` Volumes:`);
|
|
8822
|
+
for (const vol of volumes) {
|
|
8823
|
+
const volumeDef = volumeConfigs?.[vol];
|
|
8824
|
+
if (volumeDef) {
|
|
8825
|
+
console.log(` - ${vol}:${volumeDef.version.slice(0, 8)}`);
|
|
8826
|
+
} else {
|
|
8827
|
+
console.log(` - ${vol}`);
|
|
8828
|
+
}
|
|
8829
|
+
}
|
|
8830
|
+
}
|
|
8831
|
+
function formatVariableSources(sources) {
|
|
8832
|
+
if (sources.secrets.length > 0) {
|
|
8833
|
+
console.log(` Secrets:`);
|
|
8834
|
+
for (const secret of sources.secrets) {
|
|
8835
|
+
const sourceInfo = chalk29.dim(`(${secret.source})`);
|
|
8836
|
+
console.log(` - ${secret.name.padEnd(20)} ${sourceInfo}`);
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
if (sources.vars.length > 0) {
|
|
8840
|
+
console.log(` Vars:`);
|
|
8841
|
+
for (const v of sources.vars) {
|
|
8842
|
+
const sourceInfo = chalk29.dim(`(${v.source})`);
|
|
8843
|
+
console.log(` - ${v.name.padEnd(20)} ${sourceInfo}`);
|
|
8844
|
+
}
|
|
8845
|
+
}
|
|
8846
|
+
}
|
|
8847
|
+
function formatAgentDetails(agentName, agent, agentSources, volumeConfigs) {
|
|
8848
|
+
console.log(` ${chalk29.cyan(agentName)}:`);
|
|
8849
|
+
console.log(` Framework: ${agent.framework}`);
|
|
8850
|
+
if (agent.image) {
|
|
8851
|
+
console.log(` Image: ${agent.image}`);
|
|
8852
|
+
}
|
|
8853
|
+
formatListSection("Apps", agent.apps ?? []);
|
|
8854
|
+
if (agent.working_dir) {
|
|
8855
|
+
console.log(` Working Dir: ${agent.working_dir}`);
|
|
8856
|
+
}
|
|
8857
|
+
formatVolumes(agent.volumes ?? [], volumeConfigs);
|
|
8858
|
+
formatListSection("Skills", agent.skills ?? []);
|
|
8859
|
+
if (agentSources) {
|
|
8860
|
+
formatVariableSources(agentSources);
|
|
8861
|
+
}
|
|
8862
|
+
if (agent.experimental_runner) {
|
|
8863
|
+
console.log(` Runner: ${agent.experimental_runner.group}`);
|
|
8864
|
+
}
|
|
8865
|
+
}
|
|
8773
8866
|
function formatComposeOutput(name, versionId, content, variableSources) {
|
|
8774
8867
|
console.log(chalk29.bold("Name:") + ` ${name}`);
|
|
8775
8868
|
console.log(chalk29.bold("Version:") + ` ${versionId}`);
|
|
8776
8869
|
console.log();
|
|
8777
8870
|
console.log(chalk29.bold("Agents:"));
|
|
8778
8871
|
for (const [agentName, agent] of Object.entries(content.agents)) {
|
|
8779
|
-
console.log(` ${chalk29.cyan(agentName)}:`);
|
|
8780
|
-
console.log(` Framework: ${agent.framework}`);
|
|
8781
|
-
if (agent.image) {
|
|
8782
|
-
console.log(` Image: ${agent.image}`);
|
|
8783
|
-
}
|
|
8784
|
-
if (agent.apps && agent.apps.length > 0) {
|
|
8785
|
-
console.log(` Apps:`);
|
|
8786
|
-
for (const app of agent.apps) {
|
|
8787
|
-
console.log(` - ${app}`);
|
|
8788
|
-
}
|
|
8789
|
-
}
|
|
8790
|
-
if (agent.working_dir) {
|
|
8791
|
-
console.log(` Working Dir: ${agent.working_dir}`);
|
|
8792
|
-
}
|
|
8793
|
-
if (agent.volumes && agent.volumes.length > 0) {
|
|
8794
|
-
console.log(` Volumes:`);
|
|
8795
|
-
for (const vol of agent.volumes) {
|
|
8796
|
-
const volumeDef = content.volumes?.[vol];
|
|
8797
|
-
if (volumeDef) {
|
|
8798
|
-
console.log(` - ${vol}:${volumeDef.version.slice(0, 8)}`);
|
|
8799
|
-
} else {
|
|
8800
|
-
console.log(` - ${vol}`);
|
|
8801
|
-
}
|
|
8802
|
-
}
|
|
8803
|
-
}
|
|
8804
|
-
if (agent.skills && agent.skills.length > 0) {
|
|
8805
|
-
console.log(` Skills:`);
|
|
8806
|
-
for (const skill of agent.skills) {
|
|
8807
|
-
console.log(` - ${skill}`);
|
|
8808
|
-
}
|
|
8809
|
-
}
|
|
8810
8872
|
const agentSources = variableSources?.get(agentName);
|
|
8811
|
-
|
|
8812
|
-
if (agentSources.secrets.length > 0) {
|
|
8813
|
-
console.log(` Secrets:`);
|
|
8814
|
-
for (const secret of agentSources.secrets) {
|
|
8815
|
-
const sourceInfo = chalk29.dim(`(${secret.source})`);
|
|
8816
|
-
console.log(` - ${secret.name.padEnd(20)} ${sourceInfo}`);
|
|
8817
|
-
}
|
|
8818
|
-
}
|
|
8819
|
-
if (agentSources.vars.length > 0) {
|
|
8820
|
-
console.log(` Vars:`);
|
|
8821
|
-
for (const v of agentSources.vars) {
|
|
8822
|
-
const sourceInfo = chalk29.dim(`(${v.source})`);
|
|
8823
|
-
console.log(` - ${v.name.padEnd(20)} ${sourceInfo}`);
|
|
8824
|
-
}
|
|
8825
|
-
}
|
|
8826
|
-
}
|
|
8827
|
-
if (agent.experimental_runner) {
|
|
8828
|
-
console.log(` Runner: ${agent.experimental_runner.group}`);
|
|
8829
|
-
}
|
|
8873
|
+
formatAgentDetails(agentName, agent, agentSources, content.volumes);
|
|
8830
8874
|
}
|
|
8831
8875
|
}
|
|
8832
|
-
var
|
|
8876
|
+
var statusCommand4 = new Command25().name("status").description("Show status of agent compose").argument(
|
|
8833
8877
|
"<name[:version]>",
|
|
8834
8878
|
"Agent name with optional version (e.g., my-agent:latest or my-agent:a1b2c3d4)"
|
|
8835
8879
|
).option("-s, --scope <scope>", "Scope to look up the compose from").option("--no-sources", "Skip fetching skills to determine variable sources").action(
|
|
@@ -8897,7 +8941,7 @@ var inspectCommand = new Command25().name("inspect").description("Inspect an age
|
|
|
8897
8941
|
variableSources
|
|
8898
8942
|
);
|
|
8899
8943
|
} catch (error) {
|
|
8900
|
-
console.error(chalk29.red("\u2717 Failed to
|
|
8944
|
+
console.error(chalk29.red("\u2717 Failed to get agent compose status"));
|
|
8901
8945
|
if (error instanceof Error) {
|
|
8902
8946
|
if (error.message.includes("Not authenticated")) {
|
|
8903
8947
|
console.error(chalk29.dim(" Run: vm0 auth login"));
|
|
@@ -8911,14 +8955,14 @@ var inspectCommand = new Command25().name("inspect").description("Inspect an age
|
|
|
8911
8955
|
);
|
|
8912
8956
|
|
|
8913
8957
|
// src/commands/agent/index.ts
|
|
8914
|
-
var agentCommand = new Command26().name("agent").description("Manage agent composes").addCommand(listCommand3).addCommand(
|
|
8958
|
+
var agentCommand = new Command26().name("agent").description("Manage agent composes").addCommand(listCommand3).addCommand(statusCommand4);
|
|
8915
8959
|
|
|
8916
8960
|
// src/commands/init.ts
|
|
8917
8961
|
import { Command as Command27 } from "commander";
|
|
8918
8962
|
import chalk30 from "chalk";
|
|
8919
|
-
import
|
|
8963
|
+
import path13 from "path";
|
|
8920
8964
|
import { existsSync as existsSync9 } from "fs";
|
|
8921
|
-
import { writeFile as
|
|
8965
|
+
import { writeFile as writeFile6 } from "fs/promises";
|
|
8922
8966
|
var VM0_YAML_FILE = "vm0.yaml";
|
|
8923
8967
|
var AGENTS_MD_FILE = "AGENTS.md";
|
|
8924
8968
|
function generateVm0Yaml(agentName) {
|
|
@@ -8973,7 +9017,7 @@ var initCommand3 = new Command27().name("init").description("Initialize a new VM
|
|
|
8973
9017
|
console.error(chalk30.dim(" Usage: vm0 init --name <agent-name>"));
|
|
8974
9018
|
process.exit(1);
|
|
8975
9019
|
} else {
|
|
8976
|
-
const dirName =
|
|
9020
|
+
const dirName = path13.basename(process.cwd());
|
|
8977
9021
|
const defaultName = validateAgentName(dirName) ? dirName : void 0;
|
|
8978
9022
|
const name = await promptText(
|
|
8979
9023
|
"Enter agent name",
|
|
@@ -8999,10 +9043,10 @@ var initCommand3 = new Command27().name("init").description("Initialize a new VM
|
|
|
8999
9043
|
console.log(chalk30.dim(" Must start and end with letter or number"));
|
|
9000
9044
|
process.exit(1);
|
|
9001
9045
|
}
|
|
9002
|
-
await
|
|
9046
|
+
await writeFile6(VM0_YAML_FILE, generateVm0Yaml(agentName));
|
|
9003
9047
|
const vm0Status = existingFiles.includes(VM0_YAML_FILE) ? " (overwritten)" : "";
|
|
9004
9048
|
console.log(chalk30.green(`\u2713 Created ${VM0_YAML_FILE}${vm0Status}`));
|
|
9005
|
-
await
|
|
9049
|
+
await writeFile6(AGENTS_MD_FILE, generateAgentsMd());
|
|
9006
9050
|
const agentsStatus = existingFiles.includes(AGENTS_MD_FILE) ? " (overwritten)" : "";
|
|
9007
9051
|
console.log(chalk30.green(`\u2713 Created ${AGENTS_MD_FILE}${agentsStatus}`));
|
|
9008
9052
|
console.log();
|
|
@@ -9018,644 +9062,100 @@ var initCommand3 = new Command27().name("init").description("Initialize a new VM
|
|
|
9018
9062
|
);
|
|
9019
9063
|
});
|
|
9020
9064
|
|
|
9021
|
-
// src/commands/
|
|
9065
|
+
// src/commands/schedule/index.ts
|
|
9066
|
+
import { Command as Command34 } from "commander";
|
|
9067
|
+
|
|
9068
|
+
// src/commands/schedule/setup.ts
|
|
9022
9069
|
import { Command as Command28 } from "commander";
|
|
9023
9070
|
import chalk31 from "chalk";
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
import { execSync, spawnSync } from "child_process";
|
|
9027
|
-
import path15 from "path";
|
|
9071
|
+
|
|
9072
|
+
// src/lib/domain/schedule-utils.ts
|
|
9028
9073
|
import { parse as parseYaml5 } from "yaml";
|
|
9029
|
-
function
|
|
9030
|
-
|
|
9031
|
-
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9074
|
+
function formatRelativeTime2(dateStr) {
|
|
9075
|
+
if (!dateStr) return "-";
|
|
9076
|
+
const date = new Date(dateStr);
|
|
9077
|
+
const now = /* @__PURE__ */ new Date();
|
|
9078
|
+
const diffMs = date.getTime() - now.getTime();
|
|
9079
|
+
const diffAbs = Math.abs(diffMs);
|
|
9080
|
+
const minutes = Math.floor(diffAbs / (1e3 * 60));
|
|
9081
|
+
const hours = Math.floor(diffAbs / (1e3 * 60 * 60));
|
|
9082
|
+
const days = Math.floor(diffAbs / (1e3 * 60 * 60 * 24));
|
|
9083
|
+
const isPast = diffMs < 0;
|
|
9084
|
+
if (days > 0) {
|
|
9085
|
+
return isPast ? `${days}d ago` : `in ${days}d`;
|
|
9086
|
+
} else if (hours > 0) {
|
|
9087
|
+
return isPast ? `${hours}h ago` : `in ${hours}h`;
|
|
9088
|
+
} else if (minutes > 0) {
|
|
9089
|
+
return isPast ? `${minutes}m ago` : `in ${minutes}m`;
|
|
9090
|
+
} else {
|
|
9091
|
+
return isPast ? "just now" : "soon";
|
|
9035
9092
|
}
|
|
9036
9093
|
}
|
|
9037
|
-
function
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
|
|
9094
|
+
function formatDateTime(dateStr) {
|
|
9095
|
+
if (!dateStr) return "-";
|
|
9096
|
+
const date = new Date(dateStr);
|
|
9097
|
+
const year = date.getFullYear();
|
|
9098
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
9099
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
9100
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
9101
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
9102
|
+
const formatted = `${year}-${month}-${day} ${hours}:${minutes}`;
|
|
9103
|
+
const relative2 = formatRelativeTime2(dateStr);
|
|
9104
|
+
return `${formatted} (${relative2})`;
|
|
9044
9105
|
}
|
|
9045
|
-
function
|
|
9046
|
-
|
|
9047
|
-
|
|
9048
|
-
|
|
9049
|
-
|
|
9050
|
-
|
|
9051
|
-
|
|
9106
|
+
function generateCronExpression(frequency, time, day) {
|
|
9107
|
+
const [hourStr, minuteStr] = time.split(":");
|
|
9108
|
+
const hour = parseInt(hourStr ?? "0", 10);
|
|
9109
|
+
const minute = parseInt(minuteStr ?? "0", 10);
|
|
9110
|
+
switch (frequency) {
|
|
9111
|
+
case "daily":
|
|
9112
|
+
return `${minute} ${hour} * * *`;
|
|
9113
|
+
case "weekly":
|
|
9114
|
+
return `${minute} ${hour} * * ${day ?? 1}`;
|
|
9115
|
+
case "monthly":
|
|
9116
|
+
return `${minute} ${hour} ${day ?? 1} * *`;
|
|
9052
9117
|
}
|
|
9053
9118
|
}
|
|
9054
|
-
function
|
|
9055
|
-
|
|
9056
|
-
if (cwd === gitRoot) {
|
|
9057
|
-
return null;
|
|
9058
|
-
}
|
|
9059
|
-
const relativePath = path15.relative(gitRoot, cwd);
|
|
9060
|
-
return relativePath.replace(/\\/g, "/");
|
|
9119
|
+
function detectTimezone() {
|
|
9120
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
9061
9121
|
}
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9066
|
-
console.log(chalk31.red("\u2717 Not in a git repository"));
|
|
9067
|
-
console.log();
|
|
9068
|
-
console.log("This command must be run from within a git repository.");
|
|
9069
|
-
console.log();
|
|
9070
|
-
console.log("To initialize a git repository, run:");
|
|
9071
|
-
console.log(` ${chalk31.cyan("git init")}`);
|
|
9072
|
-
process.exit(1);
|
|
9122
|
+
function validateTimeFormat(time) {
|
|
9123
|
+
const match = time.match(/^(\d{1,2}):(\d{2})$/);
|
|
9124
|
+
if (!match) {
|
|
9125
|
+
return "Invalid format. Use HH:MM (e.g., 09:00)";
|
|
9073
9126
|
}
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
console.log("GitHub CLI is required for this command.");
|
|
9079
|
-
console.log();
|
|
9080
|
-
console.log(` macOS: ${chalk31.cyan("brew install gh")}`);
|
|
9081
|
-
console.log(` Other: ${chalk31.cyan("https://cli.github.com/")}`);
|
|
9082
|
-
console.log();
|
|
9083
|
-
console.log("After installation, run:");
|
|
9084
|
-
console.log(` ${chalk31.cyan("gh auth login")}`);
|
|
9085
|
-
console.log();
|
|
9086
|
-
console.log("Then try again:");
|
|
9087
|
-
console.log(` ${chalk31.cyan("vm0 setup-github")}`);
|
|
9088
|
-
process.exit(1);
|
|
9127
|
+
const hour = parseInt(match[1], 10);
|
|
9128
|
+
const minute = parseInt(match[2], 10);
|
|
9129
|
+
if (hour < 0 || hour > 23) {
|
|
9130
|
+
return "Hour must be 0-23";
|
|
9089
9131
|
}
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
console.log(chalk31.red("\u2717 GitHub CLI is not authenticated"));
|
|
9093
|
-
console.log();
|
|
9094
|
-
console.log("Please authenticate GitHub CLI first:");
|
|
9095
|
-
console.log(` ${chalk31.cyan("gh auth login")}`);
|
|
9096
|
-
console.log();
|
|
9097
|
-
console.log("Then try again:");
|
|
9098
|
-
console.log(` ${chalk31.cyan("vm0 setup-github")}`);
|
|
9099
|
-
process.exit(1);
|
|
9132
|
+
if (minute < 0 || minute > 59) {
|
|
9133
|
+
return "Minute must be 0-59";
|
|
9100
9134
|
}
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
console.log(` ${chalk31.cyan("vm0 auth login")}`);
|
|
9108
|
-
console.log();
|
|
9109
|
-
console.log("Then try again:");
|
|
9110
|
-
console.log(` ${chalk31.cyan("vm0 setup-github")}`);
|
|
9111
|
-
process.exit(1);
|
|
9135
|
+
return true;
|
|
9136
|
+
}
|
|
9137
|
+
function validateDateFormat(date) {
|
|
9138
|
+
const match = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
9139
|
+
if (!match) {
|
|
9140
|
+
return "Invalid format. Use YYYY-MM-DD (e.g., 2025-01-15)";
|
|
9112
9141
|
}
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
console.log();
|
|
9119
|
-
console.log("To create one, run:");
|
|
9120
|
-
console.log(` ${chalk31.cyan("vm0 init")}`);
|
|
9121
|
-
console.log();
|
|
9122
|
-
console.log("Then try again:");
|
|
9123
|
-
console.log(` ${chalk31.cyan("vm0 setup-github")}`);
|
|
9124
|
-
process.exit(1);
|
|
9142
|
+
const year = parseInt(match[1], 10);
|
|
9143
|
+
const month = parseInt(match[2], 10);
|
|
9144
|
+
const day = parseInt(match[3], 10);
|
|
9145
|
+
if (year < 2e3 || year > 2100) {
|
|
9146
|
+
return "Year must be between 2000 and 2100";
|
|
9125
9147
|
}
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
}
|
|
9129
|
-
function generatePublishYaml(workingDir) {
|
|
9130
|
-
const pathPrefix = workingDir ? `${workingDir}/` : "";
|
|
9131
|
-
const workingDirYaml = workingDir ? ` working-directory: ${workingDir}
|
|
9132
|
-
` : "";
|
|
9133
|
-
return `name: Publish Agent
|
|
9134
|
-
|
|
9135
|
-
on:
|
|
9136
|
-
push:
|
|
9137
|
-
branches: [main]
|
|
9138
|
-
paths:
|
|
9139
|
-
- '${pathPrefix}vm0.yaml'
|
|
9140
|
-
- '${pathPrefix}AGENTS.md'
|
|
9141
|
-
|
|
9142
|
-
jobs:
|
|
9143
|
-
publish:
|
|
9144
|
-
runs-on: ubuntu-latest
|
|
9145
|
-
steps:
|
|
9146
|
-
- uses: actions/checkout@v4
|
|
9147
|
-
|
|
9148
|
-
- name: Publish Agent
|
|
9149
|
-
uses: vm0-ai/compose-action@v1
|
|
9150
|
-
id: compose
|
|
9151
|
-
with:
|
|
9152
|
-
vm0-token: \${{ secrets.VM0_TOKEN }}
|
|
9153
|
-
${workingDirYaml}
|
|
9154
|
-
- name: Show Results
|
|
9155
|
-
run: |
|
|
9156
|
-
echo "Agent: \${{ steps.compose.outputs.name }}"
|
|
9157
|
-
echo "Compose ID: \${{ steps.compose.outputs.compose-id }}"
|
|
9158
|
-
echo "Version: \${{ steps.compose.outputs.version-id }}"
|
|
9159
|
-
echo "Action: \${{ steps.compose.outputs.action }}"
|
|
9160
|
-
`;
|
|
9161
|
-
}
|
|
9162
|
-
function generateRunYaml(agentName, secrets, vars) {
|
|
9163
|
-
const otherSecrets = secrets.filter((s) => s !== "VM0_TOKEN");
|
|
9164
|
-
const secretsLines = otherSecrets.map((s) => ` ${s}=\${{ secrets.${s} }}`).join("\n");
|
|
9165
|
-
const varsLines = vars.map((v) => ` ${v}=\${{ vars.${v} }}`).join("\n");
|
|
9166
|
-
let yaml = `name: Run Agent
|
|
9167
|
-
|
|
9168
|
-
on:
|
|
9169
|
-
# Uncomment to enable scheduled runs:
|
|
9170
|
-
# schedule:
|
|
9171
|
-
# - cron: '0 1 * * *' # Daily at 9:00 AM UTC+8
|
|
9172
|
-
workflow_dispatch:
|
|
9173
|
-
inputs:
|
|
9174
|
-
prompt:
|
|
9175
|
-
description: 'Prompt for the agent'
|
|
9176
|
-
required: false
|
|
9177
|
-
default: 'do the job'
|
|
9178
|
-
|
|
9179
|
-
jobs:
|
|
9180
|
-
run:
|
|
9181
|
-
runs-on: ubuntu-latest
|
|
9182
|
-
steps:
|
|
9183
|
-
- name: Run Agent
|
|
9184
|
-
uses: vm0-ai/run-action@v1
|
|
9185
|
-
with:
|
|
9186
|
-
agent: ${agentName}
|
|
9187
|
-
prompt: \${{ github.event.inputs.prompt || 'do the job' }}
|
|
9188
|
-
silent: true
|
|
9189
|
-
vm0-token: \${{ secrets.VM0_TOKEN }}`;
|
|
9190
|
-
if (secretsLines) {
|
|
9191
|
-
yaml += `
|
|
9192
|
-
secrets: |
|
|
9193
|
-
${secretsLines}`;
|
|
9194
|
-
}
|
|
9195
|
-
if (varsLines) {
|
|
9196
|
-
yaml += `
|
|
9197
|
-
vars: |
|
|
9198
|
-
${varsLines}`;
|
|
9199
|
-
}
|
|
9200
|
-
yaml += "\n";
|
|
9201
|
-
return yaml;
|
|
9202
|
-
}
|
|
9203
|
-
function extractSecretsAndVars(config) {
|
|
9204
|
-
const secrets = /* @__PURE__ */ new Set();
|
|
9205
|
-
const vars = /* @__PURE__ */ new Set();
|
|
9206
|
-
const refs = extractVariableReferences(config);
|
|
9207
|
-
const grouped = groupVariablesBySource(refs);
|
|
9208
|
-
for (const ref of grouped.secrets) {
|
|
9209
|
-
secrets.add(ref.name);
|
|
9148
|
+
if (month < 1 || month > 12) {
|
|
9149
|
+
return "Month must be 1-12";
|
|
9210
9150
|
}
|
|
9211
|
-
|
|
9212
|
-
|
|
9151
|
+
if (day < 1 || day > 31) {
|
|
9152
|
+
return "Day must be 1-31";
|
|
9213
9153
|
}
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
}
|
|
9220
|
-
async function promptYesNo(question, defaultYes) {
|
|
9221
|
-
const result = await promptConfirm(question, defaultYes);
|
|
9222
|
-
return result ?? false;
|
|
9223
|
-
}
|
|
9224
|
-
function setGitHubSecret(name, value) {
|
|
9225
|
-
const result = spawnSync("gh", ["secret", "set", name], {
|
|
9226
|
-
input: value,
|
|
9227
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
9228
|
-
});
|
|
9229
|
-
return result.status === 0;
|
|
9230
|
-
}
|
|
9231
|
-
function setGitHubVariable(name, value) {
|
|
9232
|
-
const result = spawnSync("gh", ["variable", "set", name, "--body", value], {
|
|
9233
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
9234
|
-
});
|
|
9235
|
-
return result.status === 0;
|
|
9236
|
-
}
|
|
9237
|
-
async function detectSecretValues(secrets, vars, vm0Token) {
|
|
9238
|
-
const secretStatuses = secrets.map((name) => {
|
|
9239
|
-
if (name === "VM0_TOKEN") {
|
|
9240
|
-
return { name, found: true, source: "vm0 auth", value: vm0Token };
|
|
9241
|
-
}
|
|
9242
|
-
const envValue = process.env[name];
|
|
9243
|
-
if (envValue) {
|
|
9244
|
-
return { name, found: true, source: "environment", value: envValue };
|
|
9245
|
-
}
|
|
9246
|
-
return { name, found: false };
|
|
9247
|
-
});
|
|
9248
|
-
const varStatuses = vars.map((name) => {
|
|
9249
|
-
const envValue = process.env[name];
|
|
9250
|
-
if (envValue) {
|
|
9251
|
-
return { name, found: true, source: "environment", value: envValue };
|
|
9252
|
-
}
|
|
9253
|
-
return { name, found: false };
|
|
9254
|
-
});
|
|
9255
|
-
return { secretStatuses, varStatuses };
|
|
9256
|
-
}
|
|
9257
|
-
function displaySecretsTable(secretStatuses, varStatuses) {
|
|
9258
|
-
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
9259
|
-
console.log("\u2502 Detected secrets and variables: \u2502");
|
|
9260
|
-
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
9261
|
-
if (secretStatuses.length > 0) {
|
|
9262
|
-
console.log("\u2502 Secrets: \u2502");
|
|
9263
|
-
for (const s of secretStatuses) {
|
|
9264
|
-
const status = s.found ? chalk31.green("\u2713") : chalk31.red("\u2717");
|
|
9265
|
-
const source = s.found ? `(from ${s.source})` : "not found";
|
|
9266
|
-
const paddedName = (s.name + " ").padEnd(23, ".");
|
|
9267
|
-
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
9268
|
-
}
|
|
9269
|
-
}
|
|
9270
|
-
if (varStatuses.length > 0) {
|
|
9271
|
-
console.log("\u2502 Variables: \u2502");
|
|
9272
|
-
for (const v of varStatuses) {
|
|
9273
|
-
const status = v.found ? chalk31.green("\u2713") : chalk31.red("\u2717");
|
|
9274
|
-
const source = v.found ? `(from ${v.source})` : "not found";
|
|
9275
|
-
const paddedName = (v.name + " ").padEnd(23, ".");
|
|
9276
|
-
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
9277
|
-
}
|
|
9278
|
-
}
|
|
9279
|
-
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
9280
|
-
}
|
|
9281
|
-
function showManualSetupInstructions(secrets, vars) {
|
|
9282
|
-
console.log("Skipped automatic setup. Configure secrets manually:");
|
|
9283
|
-
console.log();
|
|
9284
|
-
console.log(" Step 1: Get your VM0 token");
|
|
9285
|
-
console.log(` ${chalk31.cyan("vm0 auth setup-token")}`);
|
|
9286
|
-
console.log();
|
|
9287
|
-
console.log(" Step 2: Set GitHub secrets");
|
|
9288
|
-
for (const s of secrets) {
|
|
9289
|
-
console.log(` ${chalk31.cyan(`gh secret set ${s}`)}`);
|
|
9290
|
-
}
|
|
9291
|
-
if (vars.length > 0) {
|
|
9292
|
-
console.log();
|
|
9293
|
-
console.log(" Step 3: Set GitHub variables");
|
|
9294
|
-
for (const v of vars) {
|
|
9295
|
-
console.log(` ${chalk31.cyan(`gh variable set ${v}`)}`);
|
|
9296
|
-
}
|
|
9297
|
-
}
|
|
9298
|
-
}
|
|
9299
|
-
function showSuccessMessage() {
|
|
9300
|
-
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
9301
|
-
console.log("\u2502 \u2713 GitHub Actions setup complete! \u2502");
|
|
9302
|
-
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
9303
|
-
console.log("\u2502 Workflows created: \u2502");
|
|
9304
|
-
console.log("\u2502 \u2022 .github/workflows/publish.yml \u2502");
|
|
9305
|
-
console.log("\u2502 \u2022 .github/workflows/run.yml \u2502");
|
|
9306
|
-
console.log("\u2502 \u2502");
|
|
9307
|
-
console.log("\u2502 Next steps: \u2502");
|
|
9308
|
-
console.log("\u2502 1. Commit and push the workflow files \u2502");
|
|
9309
|
-
console.log("\u2502 2. Push to main branch to trigger publish \u2502");
|
|
9310
|
-
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
9311
|
-
}
|
|
9312
|
-
function showPartialSuccessMessage(missingSecrets, missingVars) {
|
|
9313
|
-
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
9314
|
-
console.log("\u2502 \u26A0 Setup partially complete \u2502");
|
|
9315
|
-
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
9316
|
-
console.log("\u2502 Missing secrets - set them manually: \u2502");
|
|
9317
|
-
for (const s of missingSecrets) {
|
|
9318
|
-
console.log(`\u2502 gh secret set ${s.padEnd(40)}\u2502`);
|
|
9319
|
-
}
|
|
9320
|
-
for (const v of missingVars) {
|
|
9321
|
-
console.log(`\u2502 gh variable set ${v.padEnd(38)}\u2502`);
|
|
9322
|
-
}
|
|
9323
|
-
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
9324
|
-
}
|
|
9325
|
-
function showWorkflowsCreatedMessage() {
|
|
9326
|
-
console.log("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510");
|
|
9327
|
-
console.log("\u2502 \u2713 Workflow files created! \u2502");
|
|
9328
|
-
console.log("\u251C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524");
|
|
9329
|
-
console.log("\u2502 \u2022 .github/workflows/publish.yml \u2502");
|
|
9330
|
-
console.log("\u2502 \u2022 .github/workflows/run.yml \u2502");
|
|
9331
|
-
console.log("\u2502 \u2502");
|
|
9332
|
-
console.log("\u2502 Next steps: \u2502");
|
|
9333
|
-
console.log("\u2502 1. Set GitHub secrets (see commands above) \u2502");
|
|
9334
|
-
console.log("\u2502 2. Commit and push the workflow files \u2502");
|
|
9335
|
-
console.log("\u2502 3. Push to main branch to trigger publish \u2502");
|
|
9336
|
-
console.log("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
9337
|
-
}
|
|
9338
|
-
var setupGithubCommand = new Command28().name("setup-github").description("Initialize GitHub Actions workflows for agent deployment").option("-f, --force", "Overwrite existing workflow files").option("-y, --yes", "Auto-confirm all prompts").option("--skip-secrets", "Skip automatic secrets/variables setup").action(
|
|
9339
|
-
// eslint-disable-next-line complexity -- TODO: refactor complex function
|
|
9340
|
-
async (options) => {
|
|
9341
|
-
const prereqs = await checkPrerequisites();
|
|
9342
|
-
if (!prereqs) {
|
|
9343
|
-
process.exit(1);
|
|
9344
|
-
}
|
|
9345
|
-
const { token: vm0Token, gitRoot } = prereqs;
|
|
9346
|
-
const workingDir = getRelativeWorkingDir(gitRoot);
|
|
9347
|
-
console.log();
|
|
9348
|
-
console.log("Analyzing vm0.yaml...");
|
|
9349
|
-
const content = await readFile8("vm0.yaml", "utf8");
|
|
9350
|
-
const config = parseYaml5(content);
|
|
9351
|
-
const agents = config.agents;
|
|
9352
|
-
const agentName = Object.keys(agents)[0];
|
|
9353
|
-
console.log(chalk31.green(`\u2713 Agent: ${agentName}`));
|
|
9354
|
-
const { secrets, vars } = extractSecretsAndVars(config);
|
|
9355
|
-
console.log(
|
|
9356
|
-
chalk31.green(
|
|
9357
|
-
`\u2713 Found ${secrets.length} secrets, ${vars.length} variables`
|
|
9358
|
-
)
|
|
9359
|
-
);
|
|
9360
|
-
console.log();
|
|
9361
|
-
const publishPath = path15.join(gitRoot, ".github/workflows/publish.yml");
|
|
9362
|
-
const runPath = path15.join(gitRoot, ".github/workflows/run.yml");
|
|
9363
|
-
const displayPublishPath = ".github/workflows/publish.yml";
|
|
9364
|
-
const displayRunPath = ".github/workflows/run.yml";
|
|
9365
|
-
const existingFiles = [];
|
|
9366
|
-
if (existsSync10(publishPath)) existingFiles.push(displayPublishPath);
|
|
9367
|
-
if (existsSync10(runPath)) existingFiles.push(displayRunPath);
|
|
9368
|
-
if (existingFiles.length > 0 && !options.force) {
|
|
9369
|
-
console.log(chalk31.yellow("\u26A0 Existing workflow files detected:"));
|
|
9370
|
-
for (const file of existingFiles) {
|
|
9371
|
-
console.log(` \u2022 ${file}`);
|
|
9372
|
-
}
|
|
9373
|
-
console.log();
|
|
9374
|
-
if (!options.yes) {
|
|
9375
|
-
const overwrite = await promptYesNo(
|
|
9376
|
-
"Overwrite existing files?",
|
|
9377
|
-
false
|
|
9378
|
-
);
|
|
9379
|
-
if (!overwrite) {
|
|
9380
|
-
console.log();
|
|
9381
|
-
console.log("Aborted. To force overwrite, run:");
|
|
9382
|
-
console.log(` ${chalk31.cyan("vm0 setup-github --force")}`);
|
|
9383
|
-
process.exit(0);
|
|
9384
|
-
}
|
|
9385
|
-
}
|
|
9386
|
-
console.log();
|
|
9387
|
-
}
|
|
9388
|
-
console.log("Creating workflow files...");
|
|
9389
|
-
await mkdir7(path15.join(gitRoot, ".github/workflows"), { recursive: true });
|
|
9390
|
-
await writeFile8(publishPath, generatePublishYaml(workingDir));
|
|
9391
|
-
const publishStatus = existingFiles.includes(displayPublishPath) ? "Overwrote" : "Created";
|
|
9392
|
-
console.log(chalk31.green(`\u2713 ${publishStatus} ${displayPublishPath}`));
|
|
9393
|
-
await writeFile8(runPath, generateRunYaml(agentName, secrets, vars));
|
|
9394
|
-
const runStatus = existingFiles.includes(displayRunPath) ? "Overwrote" : "Created";
|
|
9395
|
-
console.log(chalk31.green(`\u2713 ${runStatus} ${displayRunPath}`));
|
|
9396
|
-
console.log();
|
|
9397
|
-
if (options.skipSecrets) {
|
|
9398
|
-
console.log(chalk31.green("\u2713 Done (secrets setup skipped)"));
|
|
9399
|
-
return;
|
|
9400
|
-
}
|
|
9401
|
-
const { secretStatuses, varStatuses } = await detectSecretValues(
|
|
9402
|
-
secrets,
|
|
9403
|
-
vars,
|
|
9404
|
-
vm0Token
|
|
9405
|
-
);
|
|
9406
|
-
displaySecretsTable(secretStatuses, varStatuses);
|
|
9407
|
-
console.log();
|
|
9408
|
-
const hasFoundValues = secretStatuses.some((s) => s.found) || varStatuses.some((v) => v.found);
|
|
9409
|
-
if (!hasFoundValues) {
|
|
9410
|
-
console.log("No secret/variable values found in environment.");
|
|
9411
|
-
console.log();
|
|
9412
|
-
showManualSetupInstructions(secrets, vars);
|
|
9413
|
-
console.log();
|
|
9414
|
-
showWorkflowsCreatedMessage();
|
|
9415
|
-
return;
|
|
9416
|
-
}
|
|
9417
|
-
let shouldSetup = options.yes;
|
|
9418
|
-
if (!shouldSetup) {
|
|
9419
|
-
shouldSetup = await promptYesNo(
|
|
9420
|
-
"Set up GitHub secrets/variables automatically?",
|
|
9421
|
-
true
|
|
9422
|
-
);
|
|
9423
|
-
}
|
|
9424
|
-
if (!shouldSetup) {
|
|
9425
|
-
console.log();
|
|
9426
|
-
showManualSetupInstructions(secrets, vars);
|
|
9427
|
-
console.log();
|
|
9428
|
-
showWorkflowsCreatedMessage();
|
|
9429
|
-
return;
|
|
9430
|
-
}
|
|
9431
|
-
console.log();
|
|
9432
|
-
console.log("Setting secrets...");
|
|
9433
|
-
const failedSecrets = [];
|
|
9434
|
-
for (const s of secretStatuses) {
|
|
9435
|
-
if (s.found && s.value) {
|
|
9436
|
-
const success = setGitHubSecret(s.name, s.value);
|
|
9437
|
-
if (success) {
|
|
9438
|
-
console.log(` ${chalk31.green("\u2713")} ${s.name}`);
|
|
9439
|
-
} else {
|
|
9440
|
-
console.log(` ${chalk31.red("\u2717")} ${s.name} (failed)`);
|
|
9441
|
-
failedSecrets.push(s.name);
|
|
9442
|
-
}
|
|
9443
|
-
} else {
|
|
9444
|
-
console.log(
|
|
9445
|
-
` ${chalk31.yellow("\u26A0")} ${s.name} (skipped - not found)`
|
|
9446
|
-
);
|
|
9447
|
-
}
|
|
9448
|
-
}
|
|
9449
|
-
const failedVars = [];
|
|
9450
|
-
if (varStatuses.length > 0) {
|
|
9451
|
-
console.log();
|
|
9452
|
-
console.log("Setting variables...");
|
|
9453
|
-
for (const v of varStatuses) {
|
|
9454
|
-
if (v.found && v.value) {
|
|
9455
|
-
const success = setGitHubVariable(v.name, v.value);
|
|
9456
|
-
if (success) {
|
|
9457
|
-
console.log(` ${chalk31.green("\u2713")} ${v.name}`);
|
|
9458
|
-
} else {
|
|
9459
|
-
console.log(` ${chalk31.red("\u2717")} ${v.name} (failed)`);
|
|
9460
|
-
failedVars.push(v.name);
|
|
9461
|
-
}
|
|
9462
|
-
} else {
|
|
9463
|
-
console.log(
|
|
9464
|
-
` ${chalk31.yellow("\u26A0")} ${v.name} (skipped - not found)`
|
|
9465
|
-
);
|
|
9466
|
-
}
|
|
9467
|
-
}
|
|
9468
|
-
}
|
|
9469
|
-
console.log();
|
|
9470
|
-
const missingSecrets = [
|
|
9471
|
-
...secretStatuses.filter((s) => !s.found).map((s) => s.name),
|
|
9472
|
-
...failedSecrets
|
|
9473
|
-
];
|
|
9474
|
-
const missingVars = [
|
|
9475
|
-
...varStatuses.filter((v) => !v.found).map((v) => v.name),
|
|
9476
|
-
...failedVars
|
|
9477
|
-
];
|
|
9478
|
-
if (missingSecrets.length === 0 && missingVars.length === 0) {
|
|
9479
|
-
showSuccessMessage();
|
|
9480
|
-
} else {
|
|
9481
|
-
showPartialSuccessMessage(missingSecrets, missingVars);
|
|
9482
|
-
}
|
|
9483
|
-
}
|
|
9484
|
-
);
|
|
9485
|
-
|
|
9486
|
-
// src/commands/schedule/index.ts
|
|
9487
|
-
import { Command as Command36 } from "commander";
|
|
9488
|
-
|
|
9489
|
-
// src/commands/schedule/init.ts
|
|
9490
|
-
import { Command as Command29 } from "commander";
|
|
9491
|
-
import chalk32 from "chalk";
|
|
9492
|
-
import { existsSync as existsSync12, writeFileSync } from "fs";
|
|
9493
|
-
import { stringify as stringifyYaml2 } from "yaml";
|
|
9494
|
-
|
|
9495
|
-
// src/lib/domain/schedule-utils.ts
|
|
9496
|
-
import { existsSync as existsSync11, readFileSync as readFileSync2 } from "fs";
|
|
9497
|
-
import { parse as parseYaml6 } from "yaml";
|
|
9498
|
-
var CONFIG_FILE4 = "vm0.yaml";
|
|
9499
|
-
var SCHEDULE_FILE = "schedule.yaml";
|
|
9500
|
-
function loadAgentName() {
|
|
9501
|
-
if (!existsSync11(CONFIG_FILE4)) {
|
|
9502
|
-
return { agentName: null };
|
|
9503
|
-
}
|
|
9504
|
-
try {
|
|
9505
|
-
const content = readFileSync2(CONFIG_FILE4, "utf8");
|
|
9506
|
-
const config = parseYaml6(content);
|
|
9507
|
-
const agentNames = Object.keys(config.agents || {});
|
|
9508
|
-
return { agentName: agentNames[0] || null };
|
|
9509
|
-
} catch (err) {
|
|
9510
|
-
return {
|
|
9511
|
-
agentName: null,
|
|
9512
|
-
error: err instanceof Error ? err.message : "Failed to parse vm0.yaml"
|
|
9513
|
-
};
|
|
9514
|
-
}
|
|
9515
|
-
}
|
|
9516
|
-
function loadScheduleName() {
|
|
9517
|
-
if (!existsSync11(SCHEDULE_FILE)) {
|
|
9518
|
-
return { scheduleName: null };
|
|
9519
|
-
}
|
|
9520
|
-
try {
|
|
9521
|
-
const content = readFileSync2(SCHEDULE_FILE, "utf8");
|
|
9522
|
-
const parsed = parseYaml6(content);
|
|
9523
|
-
if (!parsed?.schedules) {
|
|
9524
|
-
return {
|
|
9525
|
-
scheduleName: null,
|
|
9526
|
-
error: "No schedules defined in schedule.yaml"
|
|
9527
|
-
};
|
|
9528
|
-
}
|
|
9529
|
-
const scheduleNames = Object.keys(parsed.schedules);
|
|
9530
|
-
return { scheduleName: scheduleNames[0] || null };
|
|
9531
|
-
} catch (err) {
|
|
9532
|
-
return {
|
|
9533
|
-
scheduleName: null,
|
|
9534
|
-
error: err instanceof Error ? err.message : "Failed to parse schedule.yaml"
|
|
9535
|
-
};
|
|
9536
|
-
}
|
|
9537
|
-
}
|
|
9538
|
-
function formatRelativeTime2(dateStr) {
|
|
9539
|
-
if (!dateStr) return "-";
|
|
9540
|
-
const date = new Date(dateStr);
|
|
9541
|
-
const now = /* @__PURE__ */ new Date();
|
|
9542
|
-
const diffMs = date.getTime() - now.getTime();
|
|
9543
|
-
const diffAbs = Math.abs(diffMs);
|
|
9544
|
-
const minutes = Math.floor(diffAbs / (1e3 * 60));
|
|
9545
|
-
const hours = Math.floor(diffAbs / (1e3 * 60 * 60));
|
|
9546
|
-
const days = Math.floor(diffAbs / (1e3 * 60 * 60 * 24));
|
|
9547
|
-
const isPast = diffMs < 0;
|
|
9548
|
-
if (days > 0) {
|
|
9549
|
-
return isPast ? `${days}d ago` : `in ${days}d`;
|
|
9550
|
-
} else if (hours > 0) {
|
|
9551
|
-
return isPast ? `${hours}h ago` : `in ${hours}h`;
|
|
9552
|
-
} else if (minutes > 0) {
|
|
9553
|
-
return isPast ? `${minutes}m ago` : `in ${minutes}m`;
|
|
9554
|
-
} else {
|
|
9555
|
-
return isPast ? "just now" : "soon";
|
|
9556
|
-
}
|
|
9557
|
-
}
|
|
9558
|
-
function formatDateTime(dateStr) {
|
|
9559
|
-
if (!dateStr) return "-";
|
|
9560
|
-
const date = new Date(dateStr);
|
|
9561
|
-
const year = date.getFullYear();
|
|
9562
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
9563
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
9564
|
-
const hours = String(date.getHours()).padStart(2, "0");
|
|
9565
|
-
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
9566
|
-
const formatted = `${year}-${month}-${day} ${hours}:${minutes}`;
|
|
9567
|
-
const relative2 = formatRelativeTime2(dateStr);
|
|
9568
|
-
return `${formatted} (${relative2})`;
|
|
9569
|
-
}
|
|
9570
|
-
function generateCronExpression(frequency, time, day) {
|
|
9571
|
-
const [hourStr, minuteStr] = time.split(":");
|
|
9572
|
-
const hour = parseInt(hourStr ?? "0", 10);
|
|
9573
|
-
const minute = parseInt(minuteStr ?? "0", 10);
|
|
9574
|
-
switch (frequency) {
|
|
9575
|
-
case "daily":
|
|
9576
|
-
return `${minute} ${hour} * * *`;
|
|
9577
|
-
case "weekly":
|
|
9578
|
-
return `${minute} ${hour} * * ${day ?? 1}`;
|
|
9579
|
-
case "monthly":
|
|
9580
|
-
return `${minute} ${hour} ${day ?? 1} * *`;
|
|
9581
|
-
}
|
|
9582
|
-
}
|
|
9583
|
-
function detectTimezone() {
|
|
9584
|
-
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
9585
|
-
}
|
|
9586
|
-
function extractVarsAndSecrets() {
|
|
9587
|
-
const result = { vars: [], secrets: [] };
|
|
9588
|
-
if (!existsSync11(CONFIG_FILE4)) {
|
|
9589
|
-
return result;
|
|
9590
|
-
}
|
|
9591
|
-
try {
|
|
9592
|
-
const content = readFileSync2(CONFIG_FILE4, "utf8");
|
|
9593
|
-
const config = parseYaml6(content);
|
|
9594
|
-
const agents = Object.values(config.agents || {});
|
|
9595
|
-
const agent = agents[0];
|
|
9596
|
-
if (!agent) {
|
|
9597
|
-
return result;
|
|
9598
|
-
}
|
|
9599
|
-
if (agent.environment) {
|
|
9600
|
-
for (const value of Object.values(agent.environment)) {
|
|
9601
|
-
const varsMatches = value.matchAll(/\$\{\{\s*vars\.(\w+)\s*\}\}/g);
|
|
9602
|
-
for (const match of varsMatches) {
|
|
9603
|
-
if (match[1] && !result.vars.includes(match[1])) {
|
|
9604
|
-
result.vars.push(match[1]);
|
|
9605
|
-
}
|
|
9606
|
-
}
|
|
9607
|
-
const secretsMatches = value.matchAll(
|
|
9608
|
-
/\$\{\{\s*secrets\.(\w+)\s*\}\}/g
|
|
9609
|
-
);
|
|
9610
|
-
for (const match of secretsMatches) {
|
|
9611
|
-
if (match[1] && !result.secrets.includes(match[1])) {
|
|
9612
|
-
result.secrets.push(match[1]);
|
|
9613
|
-
}
|
|
9614
|
-
}
|
|
9615
|
-
}
|
|
9616
|
-
}
|
|
9617
|
-
return result;
|
|
9618
|
-
} catch {
|
|
9619
|
-
return result;
|
|
9620
|
-
}
|
|
9621
|
-
}
|
|
9622
|
-
function validateTimeFormat(time) {
|
|
9623
|
-
const match = time.match(/^(\d{1,2}):(\d{2})$/);
|
|
9624
|
-
if (!match) {
|
|
9625
|
-
return "Invalid format. Use HH:MM (e.g., 09:00)";
|
|
9626
|
-
}
|
|
9627
|
-
const hour = parseInt(match[1], 10);
|
|
9628
|
-
const minute = parseInt(match[2], 10);
|
|
9629
|
-
if (hour < 0 || hour > 23) {
|
|
9630
|
-
return "Hour must be 0-23";
|
|
9631
|
-
}
|
|
9632
|
-
if (minute < 0 || minute > 59) {
|
|
9633
|
-
return "Minute must be 0-59";
|
|
9634
|
-
}
|
|
9635
|
-
return true;
|
|
9636
|
-
}
|
|
9637
|
-
function validateDateFormat(date) {
|
|
9638
|
-
const match = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
9639
|
-
if (!match) {
|
|
9640
|
-
return "Invalid format. Use YYYY-MM-DD (e.g., 2025-01-15)";
|
|
9641
|
-
}
|
|
9642
|
-
const year = parseInt(match[1], 10);
|
|
9643
|
-
const month = parseInt(match[2], 10);
|
|
9644
|
-
const day = parseInt(match[3], 10);
|
|
9645
|
-
if (year < 2e3 || year > 2100) {
|
|
9646
|
-
return "Year must be between 2000 and 2100";
|
|
9647
|
-
}
|
|
9648
|
-
if (month < 1 || month > 12) {
|
|
9649
|
-
return "Month must be 1-12";
|
|
9650
|
-
}
|
|
9651
|
-
if (day < 1 || day > 31) {
|
|
9652
|
-
return "Day must be 1-31";
|
|
9653
|
-
}
|
|
9654
|
-
const testDate = new Date(year, month - 1, day);
|
|
9655
|
-
if (testDate.getFullYear() !== year || testDate.getMonth() !== month - 1 || testDate.getDate() !== day) {
|
|
9656
|
-
return "Invalid date";
|
|
9657
|
-
}
|
|
9658
|
-
return true;
|
|
9154
|
+
const testDate = new Date(year, month - 1, day);
|
|
9155
|
+
if (testDate.getFullYear() !== year || testDate.getMonth() !== month - 1 || testDate.getDate() !== day) {
|
|
9156
|
+
return "Invalid date";
|
|
9157
|
+
}
|
|
9158
|
+
return true;
|
|
9659
9159
|
}
|
|
9660
9160
|
function getTomorrowDateLocal() {
|
|
9661
9161
|
const tomorrow = /* @__PURE__ */ new Date();
|
|
@@ -9679,11 +9179,11 @@ function toISODateTime(dateTimeStr) {
|
|
|
9679
9179
|
const date = new Date(isoStr);
|
|
9680
9180
|
return date.toISOString();
|
|
9681
9181
|
}
|
|
9682
|
-
async function
|
|
9182
|
+
async function resolveScheduleByAgent(agentName) {
|
|
9683
9183
|
const { schedules } = await listSchedules();
|
|
9684
|
-
const schedule = schedules.find((s) => s.
|
|
9184
|
+
const schedule = schedules.find((s) => s.composeName === agentName);
|
|
9685
9185
|
if (!schedule) {
|
|
9686
|
-
throw new Error(`
|
|
9186
|
+
throw new Error(`No schedule found for agent "${agentName}"`);
|
|
9687
9187
|
}
|
|
9688
9188
|
return {
|
|
9689
9189
|
name: schedule.name,
|
|
@@ -9692,8 +9192,7 @@ async function resolveScheduleByName(name) {
|
|
|
9692
9192
|
};
|
|
9693
9193
|
}
|
|
9694
9194
|
|
|
9695
|
-
// src/commands/schedule/
|
|
9696
|
-
var SCHEDULE_FILE2 = "schedule.yaml";
|
|
9195
|
+
// src/commands/schedule/setup.ts
|
|
9697
9196
|
var FREQUENCY_CHOICES = [
|
|
9698
9197
|
{ title: "Daily", value: "daily", description: "Run every day" },
|
|
9699
9198
|
{
|
|
@@ -9741,281 +9240,12 @@ function parseDayOption(day, frequency) {
|
|
|
9741
9240
|
}
|
|
9742
9241
|
return void 0;
|
|
9743
9242
|
}
|
|
9744
|
-
var initCommand4 = new Command29().name("init").description("Create a schedule.yaml interactively").option("-n, --name <name>", "Schedule name").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("--no-vars", "Don't include vars from vm0.yaml").option("--force", "Overwrite existing schedule.yaml").action(
|
|
9745
|
-
// eslint-disable-next-line complexity -- TODO: refactor complex function
|
|
9746
|
-
async (options) => {
|
|
9747
|
-
try {
|
|
9748
|
-
const { agentName, error } = loadAgentName();
|
|
9749
|
-
if (error) {
|
|
9750
|
-
console.error(chalk32.red(`\u2717 Invalid vm0.yaml: ${error}`));
|
|
9751
|
-
process.exit(1);
|
|
9752
|
-
}
|
|
9753
|
-
if (!agentName) {
|
|
9754
|
-
console.error(chalk32.red("\u2717 No vm0.yaml found"));
|
|
9755
|
-
console.error(
|
|
9756
|
-
chalk32.dim(" Run this command from an agent directory")
|
|
9757
|
-
);
|
|
9758
|
-
process.exit(1);
|
|
9759
|
-
}
|
|
9760
|
-
if (existsSync12(SCHEDULE_FILE2) && !options.force) {
|
|
9761
|
-
if (!isInteractive()) {
|
|
9762
|
-
console.error(chalk32.red("\u2717 schedule.yaml already exists"));
|
|
9763
|
-
console.error(chalk32.dim(" Use --force to overwrite"));
|
|
9764
|
-
process.exit(1);
|
|
9765
|
-
}
|
|
9766
|
-
const overwrite = await promptConfirm(
|
|
9767
|
-
"schedule.yaml exists. Overwrite?",
|
|
9768
|
-
false
|
|
9769
|
-
);
|
|
9770
|
-
if (!overwrite) {
|
|
9771
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9772
|
-
return;
|
|
9773
|
-
}
|
|
9774
|
-
}
|
|
9775
|
-
let scheduleName = options.name;
|
|
9776
|
-
if (!scheduleName) {
|
|
9777
|
-
if (!isInteractive()) {
|
|
9778
|
-
console.error(
|
|
9779
|
-
chalk32.red("\u2717 --name is required in non-interactive mode")
|
|
9780
|
-
);
|
|
9781
|
-
process.exit(1);
|
|
9782
|
-
}
|
|
9783
|
-
scheduleName = await promptText(
|
|
9784
|
-
"Schedule name",
|
|
9785
|
-
`${agentName}-schedule`
|
|
9786
|
-
);
|
|
9787
|
-
if (!scheduleName) {
|
|
9788
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9789
|
-
return;
|
|
9790
|
-
}
|
|
9791
|
-
}
|
|
9792
|
-
let frequency = options.frequency;
|
|
9793
|
-
if (!frequency || !["daily", "weekly", "monthly", "once"].includes(frequency)) {
|
|
9794
|
-
if (!isInteractive()) {
|
|
9795
|
-
console.error(
|
|
9796
|
-
chalk32.red(
|
|
9797
|
-
"\u2717 --frequency is required (daily|weekly|monthly|once)"
|
|
9798
|
-
)
|
|
9799
|
-
);
|
|
9800
|
-
process.exit(1);
|
|
9801
|
-
}
|
|
9802
|
-
frequency = await promptSelect(
|
|
9803
|
-
"Schedule frequency",
|
|
9804
|
-
FREQUENCY_CHOICES,
|
|
9805
|
-
0
|
|
9806
|
-
);
|
|
9807
|
-
if (!frequency) {
|
|
9808
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9809
|
-
return;
|
|
9810
|
-
}
|
|
9811
|
-
}
|
|
9812
|
-
let day;
|
|
9813
|
-
if (frequency === "weekly" || frequency === "monthly") {
|
|
9814
|
-
if (options.day) {
|
|
9815
|
-
day = parseDayOption(options.day, frequency);
|
|
9816
|
-
if (day === void 0) {
|
|
9817
|
-
console.error(
|
|
9818
|
-
chalk32.red(
|
|
9819
|
-
`\u2717 Invalid day: ${options.day}. Use mon-sun for weekly or 1-31 for monthly.`
|
|
9820
|
-
)
|
|
9821
|
-
);
|
|
9822
|
-
process.exit(1);
|
|
9823
|
-
}
|
|
9824
|
-
} else if (isInteractive()) {
|
|
9825
|
-
if (frequency === "weekly") {
|
|
9826
|
-
day = await promptSelect("Day of week", DAY_OF_WEEK_CHOICES, 0);
|
|
9827
|
-
if (day === void 0) {
|
|
9828
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9829
|
-
return;
|
|
9830
|
-
}
|
|
9831
|
-
} else {
|
|
9832
|
-
const dayStr = await promptText("Day of month (1-31)", "1");
|
|
9833
|
-
if (!dayStr) {
|
|
9834
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9835
|
-
return;
|
|
9836
|
-
}
|
|
9837
|
-
day = parseInt(dayStr, 10);
|
|
9838
|
-
if (isNaN(day) || day < 1 || day > 31) {
|
|
9839
|
-
console.error(chalk32.red("\u2717 Day must be between 1 and 31"));
|
|
9840
|
-
process.exit(1);
|
|
9841
|
-
}
|
|
9842
|
-
}
|
|
9843
|
-
} else {
|
|
9844
|
-
console.error(chalk32.red("\u2717 --day is required for weekly/monthly"));
|
|
9845
|
-
process.exit(1);
|
|
9846
|
-
}
|
|
9847
|
-
}
|
|
9848
|
-
let time = options.time;
|
|
9849
|
-
let atTime;
|
|
9850
|
-
if (frequency === "once") {
|
|
9851
|
-
if (!isInteractive()) {
|
|
9852
|
-
console.error(
|
|
9853
|
-
chalk32.red("\u2717 One-time schedules require interactive mode")
|
|
9854
|
-
);
|
|
9855
|
-
console.error(
|
|
9856
|
-
chalk32.dim(" Use cron frequency for non-interactive mode")
|
|
9857
|
-
);
|
|
9858
|
-
process.exit(1);
|
|
9859
|
-
}
|
|
9860
|
-
const tomorrowDate = getTomorrowDateLocal();
|
|
9861
|
-
const date = await promptText(
|
|
9862
|
-
"Date (YYYY-MM-DD, default tomorrow)",
|
|
9863
|
-
tomorrowDate,
|
|
9864
|
-
validateDateFormat
|
|
9865
|
-
);
|
|
9866
|
-
if (!date) {
|
|
9867
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9868
|
-
return;
|
|
9869
|
-
}
|
|
9870
|
-
const currentTime = getCurrentTimeLocal();
|
|
9871
|
-
time = await promptText(
|
|
9872
|
-
"Time (HH:MM)",
|
|
9873
|
-
currentTime,
|
|
9874
|
-
validateTimeFormat
|
|
9875
|
-
);
|
|
9876
|
-
if (!time) {
|
|
9877
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9878
|
-
return;
|
|
9879
|
-
}
|
|
9880
|
-
const dateStr = `${date} ${time}`;
|
|
9881
|
-
atTime = dateStr;
|
|
9882
|
-
} else {
|
|
9883
|
-
if (!time) {
|
|
9884
|
-
if (!isInteractive()) {
|
|
9885
|
-
console.error(chalk32.red("\u2717 --time is required (HH:MM format)"));
|
|
9886
|
-
process.exit(1);
|
|
9887
|
-
}
|
|
9888
|
-
time = await promptText(
|
|
9889
|
-
"Time (HH:MM)",
|
|
9890
|
-
"09:00",
|
|
9891
|
-
validateTimeFormat
|
|
9892
|
-
);
|
|
9893
|
-
if (!time) {
|
|
9894
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9895
|
-
return;
|
|
9896
|
-
}
|
|
9897
|
-
} else {
|
|
9898
|
-
const validation = validateTimeFormat(time);
|
|
9899
|
-
if (validation !== true) {
|
|
9900
|
-
console.error(chalk32.red(`\u2717 Invalid time: ${validation}`));
|
|
9901
|
-
process.exit(1);
|
|
9902
|
-
}
|
|
9903
|
-
}
|
|
9904
|
-
}
|
|
9905
|
-
const detectedTimezone = detectTimezone();
|
|
9906
|
-
let timezone = options.timezone;
|
|
9907
|
-
if (!timezone) {
|
|
9908
|
-
if (isInteractive()) {
|
|
9909
|
-
timezone = await promptText("Timezone", detectedTimezone);
|
|
9910
|
-
if (!timezone) {
|
|
9911
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9912
|
-
return;
|
|
9913
|
-
}
|
|
9914
|
-
} else {
|
|
9915
|
-
timezone = detectedTimezone;
|
|
9916
|
-
}
|
|
9917
|
-
}
|
|
9918
|
-
let promptText_ = options.prompt;
|
|
9919
|
-
if (!promptText_) {
|
|
9920
|
-
if (!isInteractive()) {
|
|
9921
|
-
console.error(chalk32.red("\u2717 --prompt is required"));
|
|
9922
|
-
process.exit(1);
|
|
9923
|
-
}
|
|
9924
|
-
promptText_ = await promptText(
|
|
9925
|
-
"Prompt to run",
|
|
9926
|
-
"let's start working."
|
|
9927
|
-
);
|
|
9928
|
-
if (!promptText_) {
|
|
9929
|
-
console.log(chalk32.dim("Cancelled"));
|
|
9930
|
-
return;
|
|
9931
|
-
}
|
|
9932
|
-
}
|
|
9933
|
-
let vars;
|
|
9934
|
-
let secrets;
|
|
9935
|
-
if (options.vars) {
|
|
9936
|
-
const extracted = extractVarsAndSecrets();
|
|
9937
|
-
if (extracted.vars.length > 0 || extracted.secrets.length > 0) {
|
|
9938
|
-
let includeVars = true;
|
|
9939
|
-
if (isInteractive()) {
|
|
9940
|
-
const varCount = extracted.vars.length;
|
|
9941
|
-
const secretCount = extracted.secrets.length;
|
|
9942
|
-
const parts = [];
|
|
9943
|
-
if (varCount > 0) parts.push(`${varCount} variable(s)`);
|
|
9944
|
-
if (secretCount > 0) parts.push(`${secretCount} secret(s)`);
|
|
9945
|
-
const itemList = [
|
|
9946
|
-
...extracted.vars.map((v) => `vars.${v}`),
|
|
9947
|
-
...extracted.secrets.map((s) => `secrets.${s}`)
|
|
9948
|
-
];
|
|
9949
|
-
includeVars = await promptConfirm(
|
|
9950
|
-
`Include ${parts.join(" and ")} from vm0.yaml? (${itemList.join(", ")})`,
|
|
9951
|
-
true
|
|
9952
|
-
) ?? true;
|
|
9953
|
-
}
|
|
9954
|
-
if (includeVars) {
|
|
9955
|
-
if (extracted.vars.length > 0) {
|
|
9956
|
-
vars = {};
|
|
9957
|
-
for (const v of extracted.vars) {
|
|
9958
|
-
vars[v] = `\${${v}}`;
|
|
9959
|
-
}
|
|
9960
|
-
}
|
|
9961
|
-
if (extracted.secrets.length > 0) {
|
|
9962
|
-
secrets = {};
|
|
9963
|
-
for (const s of extracted.secrets) {
|
|
9964
|
-
secrets[s] = `\${${s}}`;
|
|
9965
|
-
}
|
|
9966
|
-
}
|
|
9967
|
-
}
|
|
9968
|
-
}
|
|
9969
|
-
}
|
|
9970
|
-
const scheduleYaml = {
|
|
9971
|
-
version: "1.0",
|
|
9972
|
-
schedules: {
|
|
9973
|
-
[scheduleName]: {
|
|
9974
|
-
on: {
|
|
9975
|
-
timezone
|
|
9976
|
-
},
|
|
9977
|
-
run: {
|
|
9978
|
-
agent: agentName,
|
|
9979
|
-
prompt: promptText_
|
|
9980
|
-
}
|
|
9981
|
-
}
|
|
9982
|
-
}
|
|
9983
|
-
};
|
|
9984
|
-
if (atTime) {
|
|
9985
|
-
scheduleYaml.schedules[scheduleName].on.at = atTime;
|
|
9986
|
-
} else if (time && frequency !== "once") {
|
|
9987
|
-
scheduleYaml.schedules[scheduleName].on.cron = generateCronExpression(frequency, time, day);
|
|
9988
|
-
}
|
|
9989
|
-
if (vars && Object.keys(vars).length > 0) {
|
|
9990
|
-
scheduleYaml.schedules[scheduleName].run.vars = vars;
|
|
9991
|
-
}
|
|
9992
|
-
if (secrets && Object.keys(secrets).length > 0) {
|
|
9993
|
-
scheduleYaml.schedules[scheduleName].run.secrets = secrets;
|
|
9994
|
-
}
|
|
9995
|
-
writeFileSync(SCHEDULE_FILE2, stringifyYaml2(scheduleYaml));
|
|
9996
|
-
console.log(chalk32.green(`\u2713 Created ${SCHEDULE_FILE2}`));
|
|
9997
|
-
console.log(chalk32.dim(" Deploy with: vm0 schedule deploy"));
|
|
9998
|
-
} catch (error) {
|
|
9999
|
-
console.error(chalk32.red("\u2717 Failed to create schedule.yaml"));
|
|
10000
|
-
if (error instanceof Error) {
|
|
10001
|
-
console.error(chalk32.dim(` ${error.message}`));
|
|
10002
|
-
}
|
|
10003
|
-
process.exit(1);
|
|
10004
|
-
}
|
|
10005
|
-
}
|
|
10006
|
-
);
|
|
10007
|
-
|
|
10008
|
-
// src/commands/schedule/deploy.ts
|
|
10009
|
-
import { Command as Command30 } from "commander";
|
|
10010
|
-
import chalk33 from "chalk";
|
|
10011
|
-
import { existsSync as existsSync13, readFileSync as readFileSync3 } from "fs";
|
|
10012
|
-
import { parse as parseYaml7 } from "yaml";
|
|
10013
9243
|
function expandEnvVars(value) {
|
|
10014
9244
|
return value.replace(/\$\{([^}]+)\}/g, (match, varName) => {
|
|
10015
9245
|
const envValue = process.env[varName];
|
|
10016
9246
|
if (envValue === void 0) {
|
|
10017
9247
|
console.warn(
|
|
10018
|
-
|
|
9248
|
+
chalk31.yellow(` Warning: Environment variable ${varName} not set`)
|
|
10019
9249
|
);
|
|
10020
9250
|
return match;
|
|
10021
9251
|
}
|
|
@@ -10044,134 +9274,407 @@ function formatInTimezone(isoDate, timezone) {
|
|
|
10044
9274
|
const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
|
|
10045
9275
|
return `${get("year")}-${get("month")}-${get("day")} ${get("hour")}:${get("minute")}`;
|
|
10046
9276
|
}
|
|
10047
|
-
|
|
9277
|
+
function parseFrequencyFromCron(cron) {
|
|
9278
|
+
const parts = cron.split(" ");
|
|
9279
|
+
if (parts.length !== 5) return null;
|
|
9280
|
+
const [minute, hour, dayOfMonth, , dayOfWeek] = parts;
|
|
9281
|
+
const time = `${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`;
|
|
9282
|
+
if (dayOfMonth === "*" && dayOfWeek === "*") {
|
|
9283
|
+
return { frequency: "daily", time };
|
|
9284
|
+
} else if (dayOfMonth === "*" && dayOfWeek !== "*") {
|
|
9285
|
+
return { frequency: "weekly", day: parseInt(dayOfWeek, 10), time };
|
|
9286
|
+
} else if (dayOfMonth !== "*" && dayOfWeek === "*") {
|
|
9287
|
+
return { frequency: "monthly", day: parseInt(dayOfMonth, 10), time };
|
|
9288
|
+
}
|
|
9289
|
+
return null;
|
|
9290
|
+
}
|
|
9291
|
+
function collect(value, previous) {
|
|
9292
|
+
return previous.concat([value]);
|
|
9293
|
+
}
|
|
9294
|
+
function parseKeyValuePairs(pairs) {
|
|
9295
|
+
const result = {};
|
|
9296
|
+
for (const pair of pairs) {
|
|
9297
|
+
const eqIndex = pair.indexOf("=");
|
|
9298
|
+
if (eqIndex > 0) {
|
|
9299
|
+
const key = pair.slice(0, eqIndex);
|
|
9300
|
+
const value = pair.slice(eqIndex + 1);
|
|
9301
|
+
result[key] = value;
|
|
9302
|
+
}
|
|
9303
|
+
}
|
|
9304
|
+
return result;
|
|
9305
|
+
}
|
|
9306
|
+
function getExistingDefaults(existingSchedule) {
|
|
9307
|
+
const defaults = {};
|
|
9308
|
+
if (existingSchedule?.cronExpression) {
|
|
9309
|
+
const parsed = parseFrequencyFromCron(existingSchedule.cronExpression);
|
|
9310
|
+
if (parsed) {
|
|
9311
|
+
defaults.frequency = parsed.frequency;
|
|
9312
|
+
defaults.day = parsed.day;
|
|
9313
|
+
defaults.time = parsed.time;
|
|
9314
|
+
}
|
|
9315
|
+
} else if (existingSchedule?.atTime) {
|
|
9316
|
+
defaults.frequency = "once";
|
|
9317
|
+
}
|
|
9318
|
+
return defaults;
|
|
9319
|
+
}
|
|
9320
|
+
async function gatherFrequency(optionFrequency, existingFrequency) {
|
|
9321
|
+
let frequency = optionFrequency;
|
|
9322
|
+
if (frequency && ["daily", "weekly", "monthly", "once"].includes(frequency)) {
|
|
9323
|
+
return frequency;
|
|
9324
|
+
}
|
|
9325
|
+
if (!isInteractive()) {
|
|
9326
|
+
console.error(
|
|
9327
|
+
chalk31.red("\u2717 --frequency is required (daily|weekly|monthly|once)")
|
|
9328
|
+
);
|
|
9329
|
+
process.exit(1);
|
|
9330
|
+
}
|
|
9331
|
+
const defaultIndex = existingFrequency ? FREQUENCY_CHOICES.findIndex((c19) => c19.value === existingFrequency) : 0;
|
|
9332
|
+
frequency = await promptSelect(
|
|
9333
|
+
"Schedule frequency",
|
|
9334
|
+
FREQUENCY_CHOICES,
|
|
9335
|
+
defaultIndex >= 0 ? defaultIndex : 0
|
|
9336
|
+
);
|
|
9337
|
+
return frequency || null;
|
|
9338
|
+
}
|
|
9339
|
+
async function gatherDay(frequency, optionDay, existingDay) {
|
|
9340
|
+
if (frequency !== "weekly" && frequency !== "monthly") {
|
|
9341
|
+
return null;
|
|
9342
|
+
}
|
|
9343
|
+
if (optionDay) {
|
|
9344
|
+
const day2 = parseDayOption(optionDay, frequency);
|
|
9345
|
+
if (day2 === void 0) {
|
|
9346
|
+
console.error(
|
|
9347
|
+
chalk31.red(
|
|
9348
|
+
`\u2717 Invalid day: ${optionDay}. Use mon-sun for weekly or 1-31 for monthly.`
|
|
9349
|
+
)
|
|
9350
|
+
);
|
|
9351
|
+
process.exit(1);
|
|
9352
|
+
}
|
|
9353
|
+
return day2;
|
|
9354
|
+
}
|
|
9355
|
+
if (!isInteractive()) {
|
|
9356
|
+
console.error(chalk31.red("\u2717 --day is required for weekly/monthly"));
|
|
9357
|
+
process.exit(1);
|
|
9358
|
+
}
|
|
9359
|
+
if (frequency === "weekly") {
|
|
9360
|
+
const defaultDayIndex = existingDay !== void 0 ? DAY_OF_WEEK_CHOICES.findIndex((c19) => c19.value === existingDay) : 0;
|
|
9361
|
+
const day2 = await promptSelect(
|
|
9362
|
+
"Day of week",
|
|
9363
|
+
DAY_OF_WEEK_CHOICES,
|
|
9364
|
+
defaultDayIndex >= 0 ? defaultDayIndex : 0
|
|
9365
|
+
);
|
|
9366
|
+
return day2 ?? null;
|
|
9367
|
+
}
|
|
9368
|
+
const dayStr = await promptText(
|
|
9369
|
+
"Day of month (1-31)",
|
|
9370
|
+
existingDay?.toString() || "1"
|
|
9371
|
+
);
|
|
9372
|
+
if (!dayStr) return null;
|
|
9373
|
+
const day = parseInt(dayStr, 10);
|
|
9374
|
+
if (isNaN(day) || day < 1 || day > 31) {
|
|
9375
|
+
console.error(chalk31.red("\u2717 Day must be between 1 and 31"));
|
|
9376
|
+
process.exit(1);
|
|
9377
|
+
}
|
|
9378
|
+
return day;
|
|
9379
|
+
}
|
|
9380
|
+
async function gatherRecurringTime(optionTime, existingTime) {
|
|
9381
|
+
if (optionTime) {
|
|
9382
|
+
const validation = validateTimeFormat(optionTime);
|
|
9383
|
+
if (validation !== true) {
|
|
9384
|
+
console.error(chalk31.red(`\u2717 Invalid time: ${validation}`));
|
|
9385
|
+
process.exit(1);
|
|
9386
|
+
}
|
|
9387
|
+
return optionTime;
|
|
9388
|
+
}
|
|
9389
|
+
if (!isInteractive()) {
|
|
9390
|
+
console.error(chalk31.red("\u2717 --time is required (HH:MM format)"));
|
|
9391
|
+
process.exit(1);
|
|
9392
|
+
}
|
|
9393
|
+
return await promptText(
|
|
9394
|
+
"Time (HH:MM)",
|
|
9395
|
+
existingTime || "09:00",
|
|
9396
|
+
validateTimeFormat
|
|
9397
|
+
);
|
|
9398
|
+
}
|
|
9399
|
+
async function gatherOneTimeSchedule(optionDay, optionTime, existingTime) {
|
|
9400
|
+
if (optionDay && optionTime) {
|
|
9401
|
+
if (!validateDateFormat(optionDay)) {
|
|
9402
|
+
console.error(
|
|
9403
|
+
chalk31.red(
|
|
9404
|
+
`\u2717 Invalid date format: ${optionDay}. Use YYYY-MM-DD format.`
|
|
9405
|
+
)
|
|
9406
|
+
);
|
|
9407
|
+
process.exit(1);
|
|
9408
|
+
}
|
|
9409
|
+
if (!validateTimeFormat(optionTime)) {
|
|
9410
|
+
console.error(
|
|
9411
|
+
chalk31.red(`\u2717 Invalid time format: ${optionTime}. Use HH:MM format.`)
|
|
9412
|
+
);
|
|
9413
|
+
process.exit(1);
|
|
9414
|
+
}
|
|
9415
|
+
return `${optionDay} ${optionTime}`;
|
|
9416
|
+
}
|
|
9417
|
+
if (!isInteractive()) {
|
|
9418
|
+
console.error(chalk31.red("\u2717 One-time schedules require interactive mode"));
|
|
9419
|
+
console.error(
|
|
9420
|
+
chalk31.dim(" Or provide --day (YYYY-MM-DD) and --time (HH:MM) flags")
|
|
9421
|
+
);
|
|
9422
|
+
process.exit(1);
|
|
9423
|
+
}
|
|
9424
|
+
const tomorrowDate = getTomorrowDateLocal();
|
|
9425
|
+
const date = await promptText(
|
|
9426
|
+
"Date (YYYY-MM-DD, default tomorrow)",
|
|
9427
|
+
tomorrowDate,
|
|
9428
|
+
validateDateFormat
|
|
9429
|
+
);
|
|
9430
|
+
if (!date) return null;
|
|
9431
|
+
const currentTime = getCurrentTimeLocal();
|
|
9432
|
+
const time = await promptText(
|
|
9433
|
+
"Time (HH:MM)",
|
|
9434
|
+
existingTime || currentTime,
|
|
9435
|
+
validateTimeFormat
|
|
9436
|
+
);
|
|
9437
|
+
if (!time) return null;
|
|
9438
|
+
return `${date} ${time}`;
|
|
9439
|
+
}
|
|
9440
|
+
async function gatherTimezone(optionTimezone, existingTimezone) {
|
|
9441
|
+
if (optionTimezone) return optionTimezone;
|
|
9442
|
+
const detectedTimezone = detectTimezone();
|
|
9443
|
+
if (!isInteractive()) {
|
|
9444
|
+
return detectedTimezone;
|
|
9445
|
+
}
|
|
9446
|
+
return await promptText("Timezone", existingTimezone || detectedTimezone);
|
|
9447
|
+
}
|
|
9448
|
+
async function gatherPromptText(optionPrompt, existingPrompt) {
|
|
9449
|
+
if (optionPrompt) return optionPrompt;
|
|
9450
|
+
if (!isInteractive()) {
|
|
9451
|
+
console.error(chalk31.red("\u2717 --prompt is required"));
|
|
9452
|
+
process.exit(1);
|
|
9453
|
+
}
|
|
9454
|
+
return await promptText(
|
|
9455
|
+
"Prompt to run",
|
|
9456
|
+
existingPrompt || "let's start working."
|
|
9457
|
+
);
|
|
9458
|
+
}
|
|
9459
|
+
async function gatherVars(optionVars, existingVars) {
|
|
9460
|
+
if (optionVars.length > 0) {
|
|
9461
|
+
return parseKeyValuePairs(optionVars);
|
|
9462
|
+
}
|
|
9463
|
+
if (isInteractive() && existingVars) {
|
|
9464
|
+
const keepVars = await promptConfirm(
|
|
9465
|
+
`Keep existing variables? (${Object.keys(existingVars).join(", ")})`,
|
|
9466
|
+
true
|
|
9467
|
+
);
|
|
9468
|
+
if (keepVars) {
|
|
9469
|
+
return existingVars;
|
|
9470
|
+
}
|
|
9471
|
+
}
|
|
9472
|
+
return void 0;
|
|
9473
|
+
}
|
|
9474
|
+
async function gatherSecrets(optionSecrets, existingSecretNames) {
|
|
9475
|
+
if (optionSecrets.length > 0) {
|
|
9476
|
+
return parseKeyValuePairs(optionSecrets);
|
|
9477
|
+
}
|
|
9478
|
+
if (isInteractive() && existingSecretNames && existingSecretNames.length > 0) {
|
|
9479
|
+
const keepSecrets = await promptConfirm(
|
|
9480
|
+
`Keep existing secrets? (${existingSecretNames.join(", ")})`,
|
|
9481
|
+
true
|
|
9482
|
+
);
|
|
9483
|
+
if (!keepSecrets) {
|
|
9484
|
+
console.log(
|
|
9485
|
+
chalk31.dim(" Note: You'll need to provide new secret values")
|
|
9486
|
+
);
|
|
9487
|
+
}
|
|
9488
|
+
}
|
|
9489
|
+
return void 0;
|
|
9490
|
+
}
|
|
9491
|
+
async function resolveAgent(agentName) {
|
|
9492
|
+
const compose = await getComposeByName(agentName);
|
|
9493
|
+
if (!compose) {
|
|
9494
|
+
console.error(chalk31.red(`\u2717 Agent not found: ${agentName}`));
|
|
9495
|
+
console.error(chalk31.dim(" Make sure the agent is composed first"));
|
|
9496
|
+
process.exit(1);
|
|
9497
|
+
}
|
|
9498
|
+
return {
|
|
9499
|
+
composeId: compose.id,
|
|
9500
|
+
scheduleName: `${agentName}-schedule`
|
|
9501
|
+
};
|
|
9502
|
+
}
|
|
9503
|
+
async function findExistingSchedule(agentName) {
|
|
9504
|
+
const { schedules } = await listSchedules();
|
|
9505
|
+
return schedules.find((s) => s.composeName === agentName);
|
|
9506
|
+
}
|
|
9507
|
+
async function buildAndDeploy(params) {
|
|
9508
|
+
let cronExpression;
|
|
9509
|
+
let atTimeISO;
|
|
9510
|
+
if (params.atTime) {
|
|
9511
|
+
atTimeISO = toISODateTime(params.atTime);
|
|
9512
|
+
} else if (params.time && params.frequency !== "once") {
|
|
9513
|
+
cronExpression = generateCronExpression(
|
|
9514
|
+
params.frequency,
|
|
9515
|
+
params.time,
|
|
9516
|
+
params.day
|
|
9517
|
+
);
|
|
9518
|
+
}
|
|
9519
|
+
const expandedVars = expandEnvVarsInObject(params.vars);
|
|
9520
|
+
const expandedSecrets = expandEnvVarsInObject(params.secrets);
|
|
9521
|
+
console.log(
|
|
9522
|
+
`
|
|
9523
|
+
Deploying schedule for agent ${chalk31.cyan(params.agentName)}...`
|
|
9524
|
+
);
|
|
9525
|
+
const deployResult = await deploySchedule({
|
|
9526
|
+
name: params.scheduleName,
|
|
9527
|
+
composeId: params.composeId,
|
|
9528
|
+
cronExpression,
|
|
9529
|
+
atTime: atTimeISO,
|
|
9530
|
+
timezone: params.timezone,
|
|
9531
|
+
prompt: params.prompt,
|
|
9532
|
+
vars: expandedVars,
|
|
9533
|
+
secrets: expandedSecrets,
|
|
9534
|
+
artifactName: params.artifactName
|
|
9535
|
+
});
|
|
9536
|
+
displayDeployResult(params.agentName, deployResult);
|
|
9537
|
+
}
|
|
9538
|
+
function handleSetupError(error) {
|
|
9539
|
+
console.error(chalk31.red("\u2717 Failed to setup schedule"));
|
|
9540
|
+
if (error instanceof Error) {
|
|
9541
|
+
if (error.message.includes("Not authenticated")) {
|
|
9542
|
+
console.error(chalk31.dim(" Run: vm0 auth login"));
|
|
9543
|
+
} else {
|
|
9544
|
+
console.error(chalk31.dim(` ${error.message}`));
|
|
9545
|
+
}
|
|
9546
|
+
}
|
|
9547
|
+
process.exit(1);
|
|
9548
|
+
}
|
|
9549
|
+
function displayDeployResult(agentName, deployResult) {
|
|
9550
|
+
if (deployResult.created) {
|
|
9551
|
+
console.log(
|
|
9552
|
+
chalk31.green(`\u2713 Created schedule for agent ${chalk31.cyan(agentName)}`)
|
|
9553
|
+
);
|
|
9554
|
+
} else {
|
|
9555
|
+
console.log(
|
|
9556
|
+
chalk31.green(`\u2713 Updated schedule for agent ${chalk31.cyan(agentName)}`)
|
|
9557
|
+
);
|
|
9558
|
+
}
|
|
9559
|
+
console.log(chalk31.dim(` Timezone: ${deployResult.schedule.timezone}`));
|
|
9560
|
+
if (deployResult.schedule.cronExpression) {
|
|
9561
|
+
console.log(chalk31.dim(` Cron: ${deployResult.schedule.cronExpression}`));
|
|
9562
|
+
if (deployResult.schedule.nextRunAt) {
|
|
9563
|
+
const nextRun = formatInTimezone(
|
|
9564
|
+
deployResult.schedule.nextRunAt,
|
|
9565
|
+
deployResult.schedule.timezone
|
|
9566
|
+
);
|
|
9567
|
+
console.log(chalk31.dim(` Next run: ${nextRun}`));
|
|
9568
|
+
}
|
|
9569
|
+
} else if (deployResult.schedule.atTime) {
|
|
9570
|
+
const atTimeFormatted = formatInTimezone(
|
|
9571
|
+
deployResult.schedule.atTime,
|
|
9572
|
+
deployResult.schedule.timezone
|
|
9573
|
+
);
|
|
9574
|
+
console.log(chalk31.dim(` At: ${atTimeFormatted}`));
|
|
9575
|
+
}
|
|
9576
|
+
}
|
|
9577
|
+
var setupCommand = new Command28().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").action(async (agentName, options) => {
|
|
10048
9578
|
try {
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
9579
|
+
const { composeId, scheduleName } = await resolveAgent(agentName);
|
|
9580
|
+
const existingSchedule = await findExistingSchedule(agentName);
|
|
9581
|
+
console.log(
|
|
9582
|
+
chalk31.dim(
|
|
9583
|
+
existingSchedule ? `Editing existing schedule for agent ${agentName}` : `Creating new schedule for agent ${agentName}`
|
|
9584
|
+
)
|
|
9585
|
+
);
|
|
9586
|
+
const defaults = getExistingDefaults(existingSchedule);
|
|
9587
|
+
const frequency = await gatherFrequency(
|
|
9588
|
+
options.frequency,
|
|
9589
|
+
defaults.frequency
|
|
9590
|
+
);
|
|
9591
|
+
if (!frequency) {
|
|
9592
|
+
console.log(chalk31.dim("Cancelled"));
|
|
9593
|
+
return;
|
|
10053
9594
|
}
|
|
10054
|
-
|
|
10055
|
-
let
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
|
|
10060
|
-
|
|
10061
|
-
|
|
9595
|
+
let day;
|
|
9596
|
+
let time;
|
|
9597
|
+
let atTime;
|
|
9598
|
+
if (frequency === "once") {
|
|
9599
|
+
const result = await gatherOneTimeSchedule(
|
|
9600
|
+
options.day,
|
|
9601
|
+
options.time,
|
|
9602
|
+
defaults.time
|
|
9603
|
+
);
|
|
9604
|
+
if (!result) {
|
|
9605
|
+
console.log(chalk31.dim("Cancelled"));
|
|
9606
|
+
return;
|
|
10062
9607
|
}
|
|
10063
|
-
|
|
10064
|
-
}
|
|
10065
|
-
|
|
10066
|
-
|
|
10067
|
-
|
|
10068
|
-
|
|
10069
|
-
console.error(
|
|
10070
|
-
chalk33.dim(` ${issue.path.join(".")}: ${issue.message}`)
|
|
10071
|
-
);
|
|
9608
|
+
atTime = result;
|
|
9609
|
+
} else {
|
|
9610
|
+
day = await gatherDay(frequency, options.day, defaults.day) ?? void 0;
|
|
9611
|
+
if (day === null && (frequency === "weekly" || frequency === "monthly")) {
|
|
9612
|
+
console.log(chalk31.dim("Cancelled"));
|
|
9613
|
+
return;
|
|
10072
9614
|
}
|
|
10073
|
-
|
|
10074
|
-
|
|
10075
|
-
|
|
10076
|
-
const scheduleEntries = Object.entries(scheduleYaml.schedules);
|
|
10077
|
-
if (scheduleEntries.length === 0) {
|
|
10078
|
-
console.error(chalk33.red("\u2717 No schedules defined in file"));
|
|
10079
|
-
process.exit(1);
|
|
10080
|
-
}
|
|
10081
|
-
if (scheduleEntries.length > 1) {
|
|
10082
|
-
console.error(
|
|
10083
|
-
chalk33.red("\u2717 Multiple schedules per file not supported yet")
|
|
9615
|
+
const timeResult = await gatherRecurringTime(
|
|
9616
|
+
options.time,
|
|
9617
|
+
defaults.time
|
|
10084
9618
|
);
|
|
10085
|
-
|
|
10086
|
-
|
|
9619
|
+
if (!timeResult) {
|
|
9620
|
+
console.log(chalk31.dim("Cancelled"));
|
|
9621
|
+
return;
|
|
9622
|
+
}
|
|
9623
|
+
time = timeResult;
|
|
10087
9624
|
}
|
|
10088
|
-
const
|
|
10089
|
-
|
|
10090
|
-
|
|
10091
|
-
|
|
10092
|
-
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
10096
|
-
|
|
10097
|
-
|
|
9625
|
+
const timezone = await gatherTimezone(
|
|
9626
|
+
options.timezone,
|
|
9627
|
+
existingSchedule?.timezone
|
|
9628
|
+
);
|
|
9629
|
+
if (!timezone) {
|
|
9630
|
+
console.log(chalk31.dim("Cancelled"));
|
|
9631
|
+
return;
|
|
9632
|
+
}
|
|
9633
|
+
const promptText_ = await gatherPromptText(
|
|
9634
|
+
options.prompt,
|
|
9635
|
+
existingSchedule?.prompt
|
|
9636
|
+
);
|
|
9637
|
+
if (!promptText_) {
|
|
9638
|
+
console.log(chalk31.dim("Cancelled"));
|
|
9639
|
+
return;
|
|
10098
9640
|
}
|
|
10099
|
-
const
|
|
10100
|
-
const
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
|
|
9641
|
+
const vars = await gatherVars(options.var || [], existingSchedule?.vars);
|
|
9642
|
+
const secrets = await gatherSecrets(
|
|
9643
|
+
options.secret || [],
|
|
9644
|
+
existingSchedule?.secretNames
|
|
9645
|
+
);
|
|
9646
|
+
await buildAndDeploy({
|
|
9647
|
+
scheduleName,
|
|
10105
9648
|
composeId,
|
|
10106
|
-
|
|
9649
|
+
agentName,
|
|
9650
|
+
frequency,
|
|
9651
|
+
time,
|
|
9652
|
+
day,
|
|
10107
9653
|
atTime,
|
|
10108
|
-
timezone
|
|
10109
|
-
prompt:
|
|
10110
|
-
vars
|
|
10111
|
-
secrets
|
|
10112
|
-
artifactName:
|
|
10113
|
-
|
|
10114
|
-
volumeVersions: schedule.run.volumeVersions
|
|
10115
|
-
};
|
|
10116
|
-
const deployResult = await deploySchedule(body);
|
|
10117
|
-
if (deployResult.created) {
|
|
10118
|
-
console.log(
|
|
10119
|
-
chalk33.green(`\u2713 Created schedule ${chalk33.cyan(scheduleName)}`)
|
|
10120
|
-
);
|
|
10121
|
-
} else {
|
|
10122
|
-
console.log(
|
|
10123
|
-
chalk33.green(`\u2713 Updated schedule ${chalk33.cyan(scheduleName)}`)
|
|
10124
|
-
);
|
|
10125
|
-
}
|
|
10126
|
-
console.log(chalk33.dim(` Timezone: ${deployResult.schedule.timezone}`));
|
|
10127
|
-
if (deployResult.schedule.cronExpression) {
|
|
10128
|
-
console.log(
|
|
10129
|
-
chalk33.dim(` Cron: ${deployResult.schedule.cronExpression}`)
|
|
10130
|
-
);
|
|
10131
|
-
if (deployResult.schedule.nextRunAt) {
|
|
10132
|
-
const nextRun = formatInTimezone(
|
|
10133
|
-
deployResult.schedule.nextRunAt,
|
|
10134
|
-
deployResult.schedule.timezone
|
|
10135
|
-
);
|
|
10136
|
-
console.log(chalk33.dim(` Next run: ${nextRun}`));
|
|
10137
|
-
}
|
|
10138
|
-
} else if (deployResult.schedule.atTime) {
|
|
10139
|
-
const atTime2 = formatInTimezone(
|
|
10140
|
-
deployResult.schedule.atTime,
|
|
10141
|
-
deployResult.schedule.timezone
|
|
10142
|
-
);
|
|
10143
|
-
console.log(chalk33.dim(` At: ${atTime2}`));
|
|
10144
|
-
}
|
|
9654
|
+
timezone,
|
|
9655
|
+
prompt: promptText_,
|
|
9656
|
+
vars,
|
|
9657
|
+
secrets,
|
|
9658
|
+
artifactName: options.artifactName
|
|
9659
|
+
});
|
|
10145
9660
|
} catch (error) {
|
|
10146
|
-
|
|
10147
|
-
if (error instanceof Error) {
|
|
10148
|
-
if (error.message.includes("Not authenticated")) {
|
|
10149
|
-
console.error(chalk33.dim(" Run: vm0 auth login"));
|
|
10150
|
-
} else {
|
|
10151
|
-
console.error(chalk33.dim(` ${error.message}`));
|
|
10152
|
-
}
|
|
10153
|
-
}
|
|
10154
|
-
process.exit(1);
|
|
9661
|
+
handleSetupError(error);
|
|
10155
9662
|
}
|
|
10156
9663
|
});
|
|
10157
9664
|
|
|
10158
9665
|
// src/commands/schedule/list.ts
|
|
10159
|
-
import { Command as
|
|
10160
|
-
import
|
|
10161
|
-
var listCommand4 = new
|
|
9666
|
+
import { Command as Command29 } from "commander";
|
|
9667
|
+
import chalk32 from "chalk";
|
|
9668
|
+
var listCommand4 = new Command29().name("list").alias("ls").description("List all schedules").action(async () => {
|
|
10162
9669
|
try {
|
|
10163
9670
|
const result = await listSchedules();
|
|
10164
9671
|
if (result.schedules.length === 0) {
|
|
10165
|
-
console.log(
|
|
9672
|
+
console.log(chalk32.dim("No schedules found"));
|
|
10166
9673
|
console.log(
|
|
10167
|
-
|
|
9674
|
+
chalk32.dim(" Create one with: vm0 schedule setup <agent-name>")
|
|
10168
9675
|
);
|
|
10169
9676
|
return;
|
|
10170
9677
|
}
|
|
10171
|
-
const nameWidth = Math.max(
|
|
10172
|
-
4,
|
|
10173
|
-
...result.schedules.map((s) => s.name.length)
|
|
10174
|
-
);
|
|
10175
9678
|
const agentWidth = Math.max(
|
|
10176
9679
|
5,
|
|
10177
9680
|
...result.schedules.map((s) => s.composeName.length)
|
|
@@ -10183,19 +9686,17 @@ var listCommand4 = new Command31().name("list").alias("ls").description("List al
|
|
|
10183
9686
|
)
|
|
10184
9687
|
);
|
|
10185
9688
|
const header = [
|
|
10186
|
-
"NAME".padEnd(nameWidth),
|
|
10187
9689
|
"AGENT".padEnd(agentWidth),
|
|
10188
9690
|
"TRIGGER".padEnd(triggerWidth),
|
|
10189
9691
|
"STATUS".padEnd(8),
|
|
10190
9692
|
"NEXT RUN"
|
|
10191
9693
|
].join(" ");
|
|
10192
|
-
console.log(
|
|
9694
|
+
console.log(chalk32.dim(header));
|
|
10193
9695
|
for (const schedule of result.schedules) {
|
|
10194
9696
|
const trigger = schedule.cronExpression ? `${schedule.cronExpression} (${schedule.timezone})` : schedule.atTime || "-";
|
|
10195
|
-
const status = schedule.enabled ?
|
|
9697
|
+
const status = schedule.enabled ? chalk32.green("enabled") : chalk32.yellow("disabled");
|
|
10196
9698
|
const nextRun = schedule.enabled ? formatRelativeTime2(schedule.nextRunAt) : "-";
|
|
10197
9699
|
const row = [
|
|
10198
|
-
schedule.name.padEnd(nameWidth),
|
|
10199
9700
|
schedule.composeName.padEnd(agentWidth),
|
|
10200
9701
|
trigger.padEnd(triggerWidth),
|
|
10201
9702
|
status.padEnd(8 + (schedule.enabled ? 0 : 2)),
|
|
@@ -10205,12 +9706,12 @@ var listCommand4 = new Command31().name("list").alias("ls").description("List al
|
|
|
10205
9706
|
console.log(row);
|
|
10206
9707
|
}
|
|
10207
9708
|
} catch (error) {
|
|
10208
|
-
console.error(
|
|
9709
|
+
console.error(chalk32.red("\u2717 Failed to list schedules"));
|
|
10209
9710
|
if (error instanceof Error) {
|
|
10210
9711
|
if (error.message.includes("Not authenticated")) {
|
|
10211
|
-
console.error(
|
|
9712
|
+
console.error(chalk32.dim(" Run: vm0 auth login"));
|
|
10212
9713
|
} else {
|
|
10213
|
-
console.error(
|
|
9714
|
+
console.error(chalk32.dim(` ${error.message}`));
|
|
10214
9715
|
}
|
|
10215
9716
|
}
|
|
10216
9717
|
process.exit(1);
|
|
@@ -10218,213 +9719,181 @@ var listCommand4 = new Command31().name("list").alias("ls").description("List al
|
|
|
10218
9719
|
});
|
|
10219
9720
|
|
|
10220
9721
|
// src/commands/schedule/status.ts
|
|
10221
|
-
import { Command as
|
|
10222
|
-
import
|
|
9722
|
+
import { Command as Command30 } from "commander";
|
|
9723
|
+
import chalk33 from "chalk";
|
|
10223
9724
|
function formatDateTimeStyled(dateStr) {
|
|
10224
|
-
if (!dateStr) return
|
|
9725
|
+
if (!dateStr) return chalk33.dim("-");
|
|
10225
9726
|
const formatted = formatDateTime(dateStr);
|
|
10226
|
-
return formatted.replace(/\(([^)]+)\)$/,
|
|
9727
|
+
return formatted.replace(/\(([^)]+)\)$/, chalk33.dim("($1)"));
|
|
10227
9728
|
}
|
|
10228
9729
|
function formatTrigger(schedule) {
|
|
10229
9730
|
if (schedule.cronExpression) {
|
|
10230
9731
|
return schedule.cronExpression;
|
|
10231
9732
|
}
|
|
10232
9733
|
if (schedule.atTime) {
|
|
10233
|
-
return `${schedule.atTime} ${
|
|
9734
|
+
return `${schedule.atTime} ${chalk33.dim("(one-time)")}`;
|
|
10234
9735
|
}
|
|
10235
|
-
return
|
|
9736
|
+
return chalk33.dim("-");
|
|
10236
9737
|
}
|
|
10237
9738
|
function formatRunStatus(status) {
|
|
10238
9739
|
switch (status) {
|
|
10239
9740
|
case "completed":
|
|
10240
|
-
return
|
|
9741
|
+
return chalk33.green(status);
|
|
10241
9742
|
case "failed":
|
|
10242
9743
|
case "timeout":
|
|
10243
|
-
return
|
|
9744
|
+
return chalk33.red(status);
|
|
10244
9745
|
case "running":
|
|
10245
|
-
return
|
|
9746
|
+
return chalk33.blue(status);
|
|
10246
9747
|
case "pending":
|
|
10247
|
-
return
|
|
9748
|
+
return chalk33.yellow(status);
|
|
10248
9749
|
default:
|
|
10249
9750
|
return status;
|
|
10250
9751
|
}
|
|
10251
9752
|
}
|
|
10252
|
-
|
|
10253
|
-
"
|
|
10254
|
-
"
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10258
|
-
"
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
let name = nameArg;
|
|
10262
|
-
if (!name) {
|
|
10263
|
-
const scheduleResult = loadScheduleName();
|
|
10264
|
-
if (scheduleResult.error) {
|
|
10265
|
-
console.error(chalk35.red(`\u2717 ${scheduleResult.error}`));
|
|
10266
|
-
process.exit(1);
|
|
10267
|
-
}
|
|
10268
|
-
if (!scheduleResult.scheduleName) {
|
|
10269
|
-
console.error(chalk35.red("\u2717 Schedule name required"));
|
|
10270
|
-
console.error(
|
|
10271
|
-
chalk35.dim(
|
|
10272
|
-
" Provide name or run from directory with schedule.yaml"
|
|
10273
|
-
)
|
|
10274
|
-
);
|
|
10275
|
-
process.exit(1);
|
|
10276
|
-
}
|
|
10277
|
-
name = scheduleResult.scheduleName;
|
|
10278
|
-
}
|
|
10279
|
-
const resolved = await resolveScheduleByName(name);
|
|
10280
|
-
const composeId = resolved.composeId;
|
|
10281
|
-
const schedule = await getScheduleByName({ name, composeId });
|
|
10282
|
-
console.log();
|
|
10283
|
-
console.log(`Schedule: ${chalk35.cyan(schedule.name)}`);
|
|
10284
|
-
console.log(chalk35.dim("\u2501".repeat(50)));
|
|
10285
|
-
const statusText = schedule.enabled ? chalk35.green("enabled") : chalk35.yellow("disabled");
|
|
10286
|
-
console.log(`${"Status:".padEnd(16)}${statusText}`);
|
|
9753
|
+
function printRunConfiguration(schedule) {
|
|
9754
|
+
const statusText = schedule.enabled ? chalk33.green("enabled") : chalk33.yellow("disabled");
|
|
9755
|
+
console.log(`${"Status:".padEnd(16)}${statusText}`);
|
|
9756
|
+
console.log(
|
|
9757
|
+
`${"Agent:".padEnd(16)}${schedule.composeName} ${chalk33.dim(`(${schedule.scopeSlug})`)}`
|
|
9758
|
+
);
|
|
9759
|
+
const promptPreview = schedule.prompt.length > 60 ? schedule.prompt.slice(0, 57) + "..." : schedule.prompt;
|
|
9760
|
+
console.log(`${"Prompt:".padEnd(16)}${chalk33.dim(promptPreview)}`);
|
|
9761
|
+
if (schedule.vars && Object.keys(schedule.vars).length > 0) {
|
|
10287
9762
|
console.log(
|
|
10288
|
-
`${"
|
|
9763
|
+
`${"Variables:".padEnd(16)}${Object.keys(schedule.vars).join(", ")}`
|
|
10289
9764
|
);
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10294
|
-
|
|
10295
|
-
|
|
10296
|
-
}
|
|
10297
|
-
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
)
|
|
10301
|
-
|
|
10302
|
-
|
|
10303
|
-
|
|
10304
|
-
|
|
10305
|
-
|
|
10306
|
-
|
|
9765
|
+
}
|
|
9766
|
+
if (schedule.secretNames && schedule.secretNames.length > 0) {
|
|
9767
|
+
console.log(`${"Secrets:".padEnd(16)}${schedule.secretNames.join(", ")}`);
|
|
9768
|
+
}
|
|
9769
|
+
if (schedule.artifactName) {
|
|
9770
|
+
const artifactInfo = schedule.artifactVersion ? `${schedule.artifactName}:${schedule.artifactVersion}` : schedule.artifactName;
|
|
9771
|
+
console.log(`${"Artifact:".padEnd(16)}${artifactInfo}`);
|
|
9772
|
+
}
|
|
9773
|
+
if (schedule.volumeVersions && Object.keys(schedule.volumeVersions).length > 0) {
|
|
9774
|
+
console.log(
|
|
9775
|
+
`${"Volumes:".padEnd(16)}${Object.keys(schedule.volumeVersions).join(", ")}`
|
|
9776
|
+
);
|
|
9777
|
+
}
|
|
9778
|
+
}
|
|
9779
|
+
function printTimeSchedule(schedule) {
|
|
9780
|
+
console.log();
|
|
9781
|
+
console.log(`${"Trigger:".padEnd(16)}${formatTrigger(schedule)}`);
|
|
9782
|
+
console.log(`${"Timezone:".padEnd(16)}${detectTimezone()}`);
|
|
9783
|
+
if (schedule.enabled) {
|
|
9784
|
+
console.log(
|
|
9785
|
+
`${"Next Run:".padEnd(16)}${formatDateTimeStyled(schedule.nextRunAt)}`
|
|
9786
|
+
);
|
|
9787
|
+
}
|
|
9788
|
+
}
|
|
9789
|
+
async function printRecentRuns(name, composeId, limit) {
|
|
9790
|
+
if (limit <= 0) return;
|
|
9791
|
+
try {
|
|
9792
|
+
const { runs } = await listScheduleRuns({ name, composeId, limit });
|
|
9793
|
+
if (runs.length > 0) {
|
|
9794
|
+
console.log();
|
|
9795
|
+
console.log("Recent Runs:");
|
|
10307
9796
|
console.log(
|
|
10308
|
-
|
|
9797
|
+
chalk33.dim("RUN ID STATUS CREATED")
|
|
10309
9798
|
);
|
|
9799
|
+
for (const run of runs) {
|
|
9800
|
+
const id = run.id;
|
|
9801
|
+
const status = formatRunStatus(run.status).padEnd(10);
|
|
9802
|
+
const created = formatDateTimeStyled(run.createdAt);
|
|
9803
|
+
console.log(`${id} ${status} ${created}`);
|
|
9804
|
+
}
|
|
10310
9805
|
}
|
|
9806
|
+
} catch {
|
|
10311
9807
|
console.log();
|
|
10312
|
-
console.log(
|
|
10313
|
-
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
9808
|
+
console.log(chalk33.dim("Recent Runs: (unable to fetch)"));
|
|
9809
|
+
}
|
|
9810
|
+
}
|
|
9811
|
+
function handleStatusError(error, agentName) {
|
|
9812
|
+
console.error(chalk33.red("\u2717 Failed to get schedule status"));
|
|
9813
|
+
if (error instanceof Error) {
|
|
9814
|
+
if (error.message.includes("Not authenticated")) {
|
|
9815
|
+
console.error(chalk33.dim(" Run: vm0 auth login"));
|
|
9816
|
+
} else if (error.message.includes("not found") || error.message.includes("Not found") || error.message.includes("No schedule found")) {
|
|
9817
|
+
console.error(chalk33.dim(` No schedule found for agent "${agentName}"`));
|
|
9818
|
+
console.error(chalk33.dim(" Run: vm0 schedule list"));
|
|
9819
|
+
} else {
|
|
9820
|
+
console.error(chalk33.dim(` ${error.message}`));
|
|
10318
9821
|
}
|
|
9822
|
+
}
|
|
9823
|
+
process.exit(1);
|
|
9824
|
+
}
|
|
9825
|
+
var statusCommand5 = new Command30().name("status").description("Show detailed status of a schedule").argument("<agent-name>", "Agent name").option(
|
|
9826
|
+
"-l, --limit <number>",
|
|
9827
|
+
"Number of recent runs to show (0 to hide)",
|
|
9828
|
+
"5"
|
|
9829
|
+
).action(async (agentName, options) => {
|
|
9830
|
+
try {
|
|
9831
|
+
const resolved = await resolveScheduleByAgent(agentName);
|
|
9832
|
+
const { name, composeId } = resolved;
|
|
9833
|
+
const schedule = await getScheduleByName({ name, composeId });
|
|
9834
|
+
console.log();
|
|
9835
|
+
console.log(`Schedule for agent: ${chalk33.cyan(agentName)}`);
|
|
9836
|
+
console.log(chalk33.dim("\u2501".repeat(50)));
|
|
9837
|
+
printRunConfiguration(schedule);
|
|
9838
|
+
printTimeSchedule(schedule);
|
|
10319
9839
|
const limit = Math.min(
|
|
10320
9840
|
Math.max(0, parseInt(options.limit, 10) || 5),
|
|
10321
9841
|
100
|
|
10322
9842
|
);
|
|
10323
|
-
|
|
10324
|
-
try {
|
|
10325
|
-
const { runs } = await listScheduleRuns({
|
|
10326
|
-
name,
|
|
10327
|
-
composeId,
|
|
10328
|
-
limit
|
|
10329
|
-
});
|
|
10330
|
-
if (runs.length > 0) {
|
|
10331
|
-
console.log();
|
|
10332
|
-
console.log("Recent Runs:");
|
|
10333
|
-
console.log(
|
|
10334
|
-
chalk35.dim(
|
|
10335
|
-
"RUN ID STATUS CREATED"
|
|
10336
|
-
)
|
|
10337
|
-
);
|
|
10338
|
-
for (const run of runs) {
|
|
10339
|
-
const id = run.id;
|
|
10340
|
-
const status = formatRunStatus(run.status).padEnd(10);
|
|
10341
|
-
const created = formatDateTimeStyled(run.createdAt);
|
|
10342
|
-
console.log(`${id} ${status} ${created}`);
|
|
10343
|
-
}
|
|
10344
|
-
}
|
|
10345
|
-
} catch {
|
|
10346
|
-
console.log();
|
|
10347
|
-
console.log(chalk35.dim("Recent Runs: (unable to fetch)"));
|
|
10348
|
-
}
|
|
10349
|
-
}
|
|
9843
|
+
await printRecentRuns(name, composeId, limit);
|
|
10350
9844
|
console.log();
|
|
10351
9845
|
} catch (error) {
|
|
10352
|
-
|
|
10353
|
-
if (error instanceof Error) {
|
|
10354
|
-
if (error.message.includes("Not authenticated")) {
|
|
10355
|
-
console.error(chalk35.dim(" Run: vm0 auth login"));
|
|
10356
|
-
} else if (error.message.includes("not found") || error.message.includes("Not found")) {
|
|
10357
|
-
console.error(
|
|
10358
|
-
chalk35.dim(` Schedule "${nameArg ?? "unknown"}" not found`)
|
|
10359
|
-
);
|
|
10360
|
-
console.error(chalk35.dim(" Run: vm0 schedule list"));
|
|
10361
|
-
} else {
|
|
10362
|
-
console.error(chalk35.dim(` ${error.message}`));
|
|
10363
|
-
}
|
|
10364
|
-
}
|
|
10365
|
-
process.exit(1);
|
|
9846
|
+
handleStatusError(error, agentName);
|
|
10366
9847
|
}
|
|
10367
9848
|
});
|
|
10368
9849
|
|
|
10369
9850
|
// src/commands/schedule/delete.ts
|
|
10370
|
-
import { Command as
|
|
10371
|
-
import
|
|
9851
|
+
import { Command as Command31 } from "commander";
|
|
9852
|
+
import chalk34 from "chalk";
|
|
10372
9853
|
import * as readline from "readline";
|
|
10373
9854
|
async function confirm(message) {
|
|
10374
9855
|
const rl = readline.createInterface({
|
|
10375
9856
|
input: process.stdin,
|
|
10376
9857
|
output: process.stdout
|
|
10377
9858
|
});
|
|
10378
|
-
return new Promise((
|
|
9859
|
+
return new Promise((resolve) => {
|
|
10379
9860
|
rl.question(`${message} (y/N) `, (answer) => {
|
|
10380
9861
|
rl.close();
|
|
10381
|
-
|
|
9862
|
+
resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
10382
9863
|
});
|
|
10383
9864
|
});
|
|
10384
9865
|
}
|
|
10385
|
-
var deleteCommand = new
|
|
10386
|
-
"[name]",
|
|
10387
|
-
"Schedule name (auto-detected from schedule.yaml if omitted)"
|
|
10388
|
-
).option("-f, --force", "Skip confirmation prompt").action(async (nameArg, options) => {
|
|
10389
|
-
let name = nameArg;
|
|
9866
|
+
var deleteCommand = new Command31().name("delete").alias("rm").description("Delete a schedule").argument("<agent-name>", "Agent name").option("-f, --force", "Skip confirmation prompt").action(async (agentName, options) => {
|
|
10390
9867
|
try {
|
|
10391
|
-
|
|
10392
|
-
const scheduleResult = loadScheduleName();
|
|
10393
|
-
if (scheduleResult.error) {
|
|
10394
|
-
console.error(chalk36.red(`\u2717 ${scheduleResult.error}`));
|
|
10395
|
-
process.exit(1);
|
|
10396
|
-
}
|
|
10397
|
-
if (!scheduleResult.scheduleName) {
|
|
10398
|
-
console.error(chalk36.red("\u2717 Schedule name required"));
|
|
10399
|
-
console.error(
|
|
10400
|
-
chalk36.dim(
|
|
10401
|
-
" Provide name or run from directory with schedule.yaml"
|
|
10402
|
-
)
|
|
10403
|
-
);
|
|
10404
|
-
process.exit(1);
|
|
10405
|
-
}
|
|
10406
|
-
name = scheduleResult.scheduleName;
|
|
10407
|
-
}
|
|
10408
|
-
const resolved = await resolveScheduleByName(name);
|
|
9868
|
+
const resolved = await resolveScheduleByAgent(agentName);
|
|
10409
9869
|
if (!options.force) {
|
|
10410
|
-
const confirmed = await confirm(
|
|
9870
|
+
const confirmed = await confirm(
|
|
9871
|
+
`Delete schedule for agent ${chalk34.cyan(agentName)}?`
|
|
9872
|
+
);
|
|
10411
9873
|
if (!confirmed) {
|
|
10412
|
-
console.log(
|
|
9874
|
+
console.log(chalk34.dim("Cancelled"));
|
|
10413
9875
|
return;
|
|
10414
9876
|
}
|
|
10415
9877
|
}
|
|
10416
|
-
await deleteSchedule({
|
|
10417
|
-
|
|
9878
|
+
await deleteSchedule({
|
|
9879
|
+
name: resolved.name,
|
|
9880
|
+
composeId: resolved.composeId
|
|
9881
|
+
});
|
|
9882
|
+
console.log(
|
|
9883
|
+
chalk34.green(`\u2713 Deleted schedule for agent ${chalk34.cyan(agentName)}`)
|
|
9884
|
+
);
|
|
10418
9885
|
} catch (error) {
|
|
10419
|
-
console.error(
|
|
9886
|
+
console.error(chalk34.red("\u2717 Failed to delete schedule"));
|
|
10420
9887
|
if (error instanceof Error) {
|
|
10421
9888
|
if (error.message.includes("Not authenticated")) {
|
|
10422
|
-
console.error(
|
|
10423
|
-
} else if (error.message.toLowerCase().includes("not found")) {
|
|
10424
|
-
console.error(
|
|
10425
|
-
|
|
9889
|
+
console.error(chalk34.dim(" Run: vm0 auth login"));
|
|
9890
|
+
} else if (error.message.toLowerCase().includes("not found") || error.message.includes("No schedule found")) {
|
|
9891
|
+
console.error(
|
|
9892
|
+
chalk34.dim(` No schedule found for agent "${agentName}"`)
|
|
9893
|
+
);
|
|
9894
|
+
console.error(chalk34.dim(" Run: vm0 schedule list"));
|
|
10426
9895
|
} else {
|
|
10427
|
-
console.error(
|
|
9896
|
+
console.error(chalk34.dim(` ${error.message}`));
|
|
10428
9897
|
}
|
|
10429
9898
|
}
|
|
10430
9899
|
process.exit(1);
|
|
@@ -10432,44 +9901,30 @@ var deleteCommand = new Command33().name("delete").alias("rm").description("Dele
|
|
|
10432
9901
|
});
|
|
10433
9902
|
|
|
10434
9903
|
// src/commands/schedule/enable.ts
|
|
10435
|
-
import { Command as
|
|
10436
|
-
import
|
|
10437
|
-
var enableCommand = new
|
|
10438
|
-
"[name]",
|
|
10439
|
-
"Schedule name (auto-detected from schedule.yaml if omitted)"
|
|
10440
|
-
).action(async (nameArg) => {
|
|
9904
|
+
import { Command as Command32 } from "commander";
|
|
9905
|
+
import chalk35 from "chalk";
|
|
9906
|
+
var enableCommand = new Command32().name("enable").description("Enable a schedule").argument("<agent-name>", "Agent name").action(async (agentName) => {
|
|
10441
9907
|
try {
|
|
10442
|
-
|
|
10443
|
-
|
|
10444
|
-
|
|
10445
|
-
|
|
10446
|
-
|
|
10447
|
-
|
|
10448
|
-
}
|
|
10449
|
-
|
|
10450
|
-
console.error(chalk37.red("\u2717 Schedule name required"));
|
|
10451
|
-
console.error(
|
|
10452
|
-
chalk37.dim(
|
|
10453
|
-
" Provide name or run from directory with schedule.yaml"
|
|
10454
|
-
)
|
|
10455
|
-
);
|
|
10456
|
-
process.exit(1);
|
|
10457
|
-
}
|
|
10458
|
-
name = scheduleResult.scheduleName;
|
|
10459
|
-
}
|
|
10460
|
-
const resolved = await resolveScheduleByName(name);
|
|
10461
|
-
await enableSchedule({ name, composeId: resolved.composeId });
|
|
10462
|
-
console.log(chalk37.green(`\u2713 Enabled schedule ${chalk37.cyan(name)}`));
|
|
9908
|
+
const resolved = await resolveScheduleByAgent(agentName);
|
|
9909
|
+
await enableSchedule({
|
|
9910
|
+
name: resolved.name,
|
|
9911
|
+
composeId: resolved.composeId
|
|
9912
|
+
});
|
|
9913
|
+
console.log(
|
|
9914
|
+
chalk35.green(`\u2713 Enabled schedule for agent ${chalk35.cyan(agentName)}`)
|
|
9915
|
+
);
|
|
10463
9916
|
} catch (error) {
|
|
10464
|
-
console.error(
|
|
9917
|
+
console.error(chalk35.red("\u2717 Failed to enable schedule"));
|
|
10465
9918
|
if (error instanceof Error) {
|
|
10466
9919
|
if (error.message.includes("Not authenticated")) {
|
|
10467
|
-
console.error(
|
|
10468
|
-
} else if (error.message.toLowerCase().includes("not found")) {
|
|
10469
|
-
console.error(
|
|
10470
|
-
|
|
9920
|
+
console.error(chalk35.dim(" Run: vm0 auth login"));
|
|
9921
|
+
} else if (error.message.toLowerCase().includes("not found") || error.message.includes("No schedule found")) {
|
|
9922
|
+
console.error(
|
|
9923
|
+
chalk35.dim(` No schedule found for agent "${agentName}"`)
|
|
9924
|
+
);
|
|
9925
|
+
console.error(chalk35.dim(" Run: vm0 schedule list"));
|
|
10471
9926
|
} else {
|
|
10472
|
-
console.error(
|
|
9927
|
+
console.error(chalk35.dim(` ${error.message}`));
|
|
10473
9928
|
}
|
|
10474
9929
|
}
|
|
10475
9930
|
process.exit(1);
|
|
@@ -10477,44 +9932,30 @@ var enableCommand = new Command34().name("enable").description("Enable a schedul
|
|
|
10477
9932
|
});
|
|
10478
9933
|
|
|
10479
9934
|
// src/commands/schedule/disable.ts
|
|
10480
|
-
import { Command as
|
|
10481
|
-
import
|
|
10482
|
-
var disableCommand = new
|
|
10483
|
-
"[name]",
|
|
10484
|
-
"Schedule name (auto-detected from schedule.yaml if omitted)"
|
|
10485
|
-
).action(async (nameArg) => {
|
|
9935
|
+
import { Command as Command33 } from "commander";
|
|
9936
|
+
import chalk36 from "chalk";
|
|
9937
|
+
var disableCommand = new Command33().name("disable").description("Disable a schedule").argument("<agent-name>", "Agent name").action(async (agentName) => {
|
|
10486
9938
|
try {
|
|
10487
|
-
|
|
10488
|
-
|
|
10489
|
-
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
}
|
|
10494
|
-
|
|
10495
|
-
console.error(chalk38.red("\u2717 Schedule name required"));
|
|
10496
|
-
console.error(
|
|
10497
|
-
chalk38.dim(
|
|
10498
|
-
" Provide name or run from directory with schedule.yaml"
|
|
10499
|
-
)
|
|
10500
|
-
);
|
|
10501
|
-
process.exit(1);
|
|
10502
|
-
}
|
|
10503
|
-
name = scheduleResult.scheduleName;
|
|
10504
|
-
}
|
|
10505
|
-
const resolved = await resolveScheduleByName(name);
|
|
10506
|
-
await disableSchedule({ name, composeId: resolved.composeId });
|
|
10507
|
-
console.log(chalk38.green(`\u2713 Disabled schedule ${chalk38.cyan(name)}`));
|
|
9939
|
+
const resolved = await resolveScheduleByAgent(agentName);
|
|
9940
|
+
await disableSchedule({
|
|
9941
|
+
name: resolved.name,
|
|
9942
|
+
composeId: resolved.composeId
|
|
9943
|
+
});
|
|
9944
|
+
console.log(
|
|
9945
|
+
chalk36.green(`\u2713 Disabled schedule for agent ${chalk36.cyan(agentName)}`)
|
|
9946
|
+
);
|
|
10508
9947
|
} catch (error) {
|
|
10509
|
-
console.error(
|
|
9948
|
+
console.error(chalk36.red("\u2717 Failed to disable schedule"));
|
|
10510
9949
|
if (error instanceof Error) {
|
|
10511
9950
|
if (error.message.includes("Not authenticated")) {
|
|
10512
|
-
console.error(
|
|
10513
|
-
} else if (error.message.toLowerCase().includes("not found")) {
|
|
10514
|
-
console.error(
|
|
10515
|
-
|
|
9951
|
+
console.error(chalk36.dim(" Run: vm0 auth login"));
|
|
9952
|
+
} else if (error.message.toLowerCase().includes("not found") || error.message.includes("No schedule found")) {
|
|
9953
|
+
console.error(
|
|
9954
|
+
chalk36.dim(` No schedule found for agent "${agentName}"`)
|
|
9955
|
+
);
|
|
9956
|
+
console.error(chalk36.dim(" Run: vm0 schedule list"));
|
|
10516
9957
|
} else {
|
|
10517
|
-
console.error(
|
|
9958
|
+
console.error(chalk36.dim(` ${error.message}`));
|
|
10518
9959
|
}
|
|
10519
9960
|
}
|
|
10520
9961
|
process.exit(1);
|
|
@@ -10522,11 +9963,11 @@ var disableCommand = new Command35().name("disable").description("Disable a sche
|
|
|
10522
9963
|
});
|
|
10523
9964
|
|
|
10524
9965
|
// src/commands/schedule/index.ts
|
|
10525
|
-
var scheduleCommand = new
|
|
9966
|
+
var scheduleCommand = new Command34().name("schedule").description("Manage agent schedules").addCommand(setupCommand).addCommand(listCommand4).addCommand(statusCommand5).addCommand(deleteCommand).addCommand(enableCommand).addCommand(disableCommand);
|
|
10526
9967
|
|
|
10527
9968
|
// src/commands/usage.ts
|
|
10528
|
-
import { Command as
|
|
10529
|
-
import
|
|
9969
|
+
import { Command as Command35 } from "commander";
|
|
9970
|
+
import chalk37 from "chalk";
|
|
10530
9971
|
|
|
10531
9972
|
// src/lib/utils/duration-formatter.ts
|
|
10532
9973
|
function formatDuration(ms) {
|
|
@@ -10599,7 +10040,7 @@ function fillMissingDates(daily, startDate, endDate) {
|
|
|
10599
10040
|
result.sort((a, b) => b.date.localeCompare(a.date));
|
|
10600
10041
|
return result;
|
|
10601
10042
|
}
|
|
10602
|
-
var usageCommand = new
|
|
10043
|
+
var usageCommand = new Command35().name("usage").description("View usage statistics").option("--since <date>", "Start date (ISO format or relative: 7d, 30d)").option(
|
|
10603
10044
|
"--until <date>",
|
|
10604
10045
|
"End date (ISO format or relative, defaults to now)"
|
|
10605
10046
|
).action(async (options) => {
|
|
@@ -10613,7 +10054,7 @@ var usageCommand = new Command37().name("usage").description("View usage statist
|
|
|
10613
10054
|
endDate = new Date(untilMs);
|
|
10614
10055
|
} catch {
|
|
10615
10056
|
console.error(
|
|
10616
|
-
|
|
10057
|
+
chalk37.red(
|
|
10617
10058
|
"Error: Invalid --until format. Use ISO (2026-01-01) or relative (7d, 30d)"
|
|
10618
10059
|
)
|
|
10619
10060
|
);
|
|
@@ -10628,7 +10069,7 @@ var usageCommand = new Command37().name("usage").description("View usage statist
|
|
|
10628
10069
|
startDate = new Date(sinceMs);
|
|
10629
10070
|
} catch {
|
|
10630
10071
|
console.error(
|
|
10631
|
-
|
|
10072
|
+
chalk37.red(
|
|
10632
10073
|
"Error: Invalid --since format. Use ISO (2026-01-01) or relative (7d, 30d)"
|
|
10633
10074
|
)
|
|
10634
10075
|
);
|
|
@@ -10638,13 +10079,13 @@ var usageCommand = new Command37().name("usage").description("View usage statist
|
|
|
10638
10079
|
startDate = new Date(endDate.getTime() - DEFAULT_RANGE_MS);
|
|
10639
10080
|
}
|
|
10640
10081
|
if (startDate >= endDate) {
|
|
10641
|
-
console.error(
|
|
10082
|
+
console.error(chalk37.red("Error: --since must be before --until"));
|
|
10642
10083
|
process.exit(1);
|
|
10643
10084
|
}
|
|
10644
10085
|
const rangeMs = endDate.getTime() - startDate.getTime();
|
|
10645
10086
|
if (rangeMs > MAX_RANGE_MS) {
|
|
10646
10087
|
console.error(
|
|
10647
|
-
|
|
10088
|
+
chalk37.red(
|
|
10648
10089
|
"Error: Time range exceeds maximum of 30 days. Use --until to specify an end date."
|
|
10649
10090
|
)
|
|
10650
10091
|
);
|
|
@@ -10661,19 +10102,19 @@ var usageCommand = new Command37().name("usage").description("View usage statist
|
|
|
10661
10102
|
);
|
|
10662
10103
|
console.log();
|
|
10663
10104
|
console.log(
|
|
10664
|
-
|
|
10105
|
+
chalk37.bold(
|
|
10665
10106
|
`Usage Summary (${formatDateRange(usage.period.start, usage.period.end)})`
|
|
10666
10107
|
)
|
|
10667
10108
|
);
|
|
10668
10109
|
console.log();
|
|
10669
|
-
console.log(
|
|
10110
|
+
console.log(chalk37.dim("DATE RUNS RUN TIME"));
|
|
10670
10111
|
for (const day of filledDaily) {
|
|
10671
10112
|
const dateDisplay = formatDateDisplay(day.date).padEnd(10);
|
|
10672
10113
|
const runsDisplay = String(day.run_count).padStart(6);
|
|
10673
10114
|
const timeDisplay = formatDuration(day.run_time_ms);
|
|
10674
10115
|
console.log(`${dateDisplay}${runsDisplay} ${timeDisplay}`);
|
|
10675
10116
|
}
|
|
10676
|
-
console.log(
|
|
10117
|
+
console.log(chalk37.dim("\u2500".repeat(29)));
|
|
10677
10118
|
const totalRunsDisplay = String(usage.summary.total_runs).padStart(6);
|
|
10678
10119
|
const totalTimeDisplay = formatDuration(usage.summary.total_run_time_ms);
|
|
10679
10120
|
console.log(
|
|
@@ -10684,68 +10125,68 @@ var usageCommand = new Command37().name("usage").description("View usage statist
|
|
|
10684
10125
|
if (error instanceof Error) {
|
|
10685
10126
|
if (error.message.includes("Not authenticated")) {
|
|
10686
10127
|
console.error(
|
|
10687
|
-
|
|
10128
|
+
chalk37.red("Error: Not authenticated. Run: vm0 auth login")
|
|
10688
10129
|
);
|
|
10689
10130
|
} else {
|
|
10690
|
-
console.error(
|
|
10131
|
+
console.error(chalk37.red(`Error: ${error.message}`));
|
|
10691
10132
|
}
|
|
10692
10133
|
} else {
|
|
10693
|
-
console.error(
|
|
10134
|
+
console.error(chalk37.red("Error: An unexpected error occurred"));
|
|
10694
10135
|
}
|
|
10695
10136
|
process.exit(1);
|
|
10696
10137
|
}
|
|
10697
10138
|
});
|
|
10698
10139
|
|
|
10699
10140
|
// src/commands/credential/index.ts
|
|
10700
|
-
import { Command as
|
|
10141
|
+
import { Command as Command39 } from "commander";
|
|
10701
10142
|
|
|
10702
10143
|
// src/commands/credential/list.ts
|
|
10703
|
-
import { Command as
|
|
10704
|
-
import
|
|
10705
|
-
var listCommand5 = new
|
|
10144
|
+
import { Command as Command36 } from "commander";
|
|
10145
|
+
import chalk38 from "chalk";
|
|
10146
|
+
var listCommand5 = new Command36().name("list").alias("ls").description("List all credentials").action(async () => {
|
|
10706
10147
|
try {
|
|
10707
10148
|
const result = await listCredentials();
|
|
10708
10149
|
if (result.credentials.length === 0) {
|
|
10709
|
-
console.log(
|
|
10150
|
+
console.log(chalk38.dim("No credentials found."));
|
|
10710
10151
|
console.log();
|
|
10711
10152
|
console.log("To add a credential:");
|
|
10712
|
-
console.log(
|
|
10153
|
+
console.log(chalk38.cyan(" vm0 credential set MY_API_KEY <value>"));
|
|
10713
10154
|
return;
|
|
10714
10155
|
}
|
|
10715
|
-
console.log(
|
|
10156
|
+
console.log(chalk38.bold("Credentials:"));
|
|
10716
10157
|
console.log();
|
|
10717
10158
|
for (const credential of result.credentials) {
|
|
10718
|
-
const typeIndicator = credential.type === "model-provider" ?
|
|
10719
|
-
console.log(` ${
|
|
10159
|
+
const typeIndicator = credential.type === "model-provider" ? chalk38.dim(" [model-provider]") : "";
|
|
10160
|
+
console.log(` ${chalk38.cyan(credential.name)}${typeIndicator}`);
|
|
10720
10161
|
if (credential.description) {
|
|
10721
|
-
console.log(` ${
|
|
10162
|
+
console.log(` ${chalk38.dim(credential.description)}`);
|
|
10722
10163
|
}
|
|
10723
10164
|
console.log(
|
|
10724
|
-
` ${
|
|
10165
|
+
` ${chalk38.dim(`Updated: ${new Date(credential.updatedAt).toLocaleString()}`)}`
|
|
10725
10166
|
);
|
|
10726
10167
|
console.log();
|
|
10727
10168
|
}
|
|
10728
10169
|
console.log(
|
|
10729
|
-
|
|
10170
|
+
chalk38.dim(`Total: ${result.credentials.length} credential(s)`)
|
|
10730
10171
|
);
|
|
10731
10172
|
} catch (error) {
|
|
10732
10173
|
if (error instanceof Error) {
|
|
10733
10174
|
if (error.message.includes("Not authenticated")) {
|
|
10734
|
-
console.error(
|
|
10175
|
+
console.error(chalk38.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
10735
10176
|
} else {
|
|
10736
|
-
console.error(
|
|
10177
|
+
console.error(chalk38.red(`\u2717 ${error.message}`));
|
|
10737
10178
|
}
|
|
10738
10179
|
} else {
|
|
10739
|
-
console.error(
|
|
10180
|
+
console.error(chalk38.red("\u2717 An unexpected error occurred"));
|
|
10740
10181
|
}
|
|
10741
10182
|
process.exit(1);
|
|
10742
10183
|
}
|
|
10743
10184
|
});
|
|
10744
10185
|
|
|
10745
10186
|
// src/commands/credential/set.ts
|
|
10746
|
-
import { Command as
|
|
10747
|
-
import
|
|
10748
|
-
var setCommand2 = new
|
|
10187
|
+
import { Command as Command37 } from "commander";
|
|
10188
|
+
import chalk39 from "chalk";
|
|
10189
|
+
var setCommand2 = new Command37().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(
|
|
10749
10190
|
async (name, value, options) => {
|
|
10750
10191
|
try {
|
|
10751
10192
|
const credential = await setCredential({
|
|
@@ -10753,29 +10194,29 @@ var setCommand2 = new Command39().name("set").description("Create or update a cr
|
|
|
10753
10194
|
value,
|
|
10754
10195
|
description: options.description
|
|
10755
10196
|
});
|
|
10756
|
-
console.log(
|
|
10197
|
+
console.log(chalk39.green(`\u2713 Credential "${credential.name}" saved`));
|
|
10757
10198
|
console.log();
|
|
10758
10199
|
console.log("Use in vm0.yaml:");
|
|
10759
|
-
console.log(
|
|
10760
|
-
console.log(
|
|
10200
|
+
console.log(chalk39.cyan(` environment:`));
|
|
10201
|
+
console.log(chalk39.cyan(` ${name}: \${{ credentials.${name} }}`));
|
|
10761
10202
|
} catch (error) {
|
|
10762
10203
|
if (error instanceof Error) {
|
|
10763
10204
|
if (error.message.includes("Not authenticated")) {
|
|
10764
10205
|
console.error(
|
|
10765
|
-
|
|
10206
|
+
chalk39.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
10766
10207
|
);
|
|
10767
10208
|
} else if (error.message.includes("must contain only uppercase")) {
|
|
10768
|
-
console.error(
|
|
10209
|
+
console.error(chalk39.red(`\u2717 ${error.message}`));
|
|
10769
10210
|
console.log();
|
|
10770
10211
|
console.log("Examples of valid credential names:");
|
|
10771
|
-
console.log(
|
|
10772
|
-
console.log(
|
|
10773
|
-
console.log(
|
|
10212
|
+
console.log(chalk39.dim(" MY_API_KEY"));
|
|
10213
|
+
console.log(chalk39.dim(" GITHUB_TOKEN"));
|
|
10214
|
+
console.log(chalk39.dim(" AWS_ACCESS_KEY_ID"));
|
|
10774
10215
|
} else {
|
|
10775
|
-
console.error(
|
|
10216
|
+
console.error(chalk39.red(`\u2717 ${error.message}`));
|
|
10776
10217
|
}
|
|
10777
10218
|
} else {
|
|
10778
|
-
console.error(
|
|
10219
|
+
console.error(chalk39.red("\u2717 An unexpected error occurred"));
|
|
10779
10220
|
}
|
|
10780
10221
|
process.exit(1);
|
|
10781
10222
|
}
|
|
@@ -10783,14 +10224,14 @@ var setCommand2 = new Command39().name("set").description("Create or update a cr
|
|
|
10783
10224
|
);
|
|
10784
10225
|
|
|
10785
10226
|
// src/commands/credential/delete.ts
|
|
10786
|
-
import { Command as
|
|
10787
|
-
import
|
|
10788
|
-
var deleteCommand2 = new
|
|
10227
|
+
import { Command as Command38 } from "commander";
|
|
10228
|
+
import chalk40 from "chalk";
|
|
10229
|
+
var deleteCommand2 = new Command38().name("delete").description("Delete a credential").argument("<name>", "Credential name to delete").option("-y, --yes", "Skip confirmation prompt").action(async (name, options) => {
|
|
10789
10230
|
try {
|
|
10790
10231
|
try {
|
|
10791
10232
|
await getCredential(name);
|
|
10792
10233
|
} catch {
|
|
10793
|
-
console.error(
|
|
10234
|
+
console.error(chalk40.red(`\u2717 Credential "${name}" not found`));
|
|
10794
10235
|
process.exit(1);
|
|
10795
10236
|
}
|
|
10796
10237
|
if (!options.yes) {
|
|
@@ -10799,55 +10240,55 @@ var deleteCommand2 = new Command40().name("delete").description("Delete a creden
|
|
|
10799
10240
|
input: process.stdin,
|
|
10800
10241
|
output: process.stdout
|
|
10801
10242
|
});
|
|
10802
|
-
const confirmed = await new Promise((
|
|
10243
|
+
const confirmed = await new Promise((resolve) => {
|
|
10803
10244
|
rl.question(
|
|
10804
|
-
|
|
10245
|
+
chalk40.yellow(
|
|
10805
10246
|
`Are you sure you want to delete credential "${name}"? (y/N) `
|
|
10806
10247
|
),
|
|
10807
10248
|
(answer) => {
|
|
10808
10249
|
rl.close();
|
|
10809
|
-
|
|
10250
|
+
resolve(answer.toLowerCase() === "y");
|
|
10810
10251
|
}
|
|
10811
10252
|
);
|
|
10812
10253
|
});
|
|
10813
10254
|
if (!confirmed) {
|
|
10814
|
-
console.log(
|
|
10255
|
+
console.log(chalk40.dim("Cancelled."));
|
|
10815
10256
|
return;
|
|
10816
10257
|
}
|
|
10817
10258
|
}
|
|
10818
10259
|
await deleteCredential(name);
|
|
10819
|
-
console.log(
|
|
10260
|
+
console.log(chalk40.green(`\u2713 Credential "${name}" deleted`));
|
|
10820
10261
|
} catch (error) {
|
|
10821
10262
|
if (error instanceof Error) {
|
|
10822
10263
|
if (error.message.includes("Not authenticated")) {
|
|
10823
|
-
console.error(
|
|
10264
|
+
console.error(chalk40.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
10824
10265
|
} else {
|
|
10825
|
-
console.error(
|
|
10266
|
+
console.error(chalk40.red(`\u2717 ${error.message}`));
|
|
10826
10267
|
}
|
|
10827
10268
|
} else {
|
|
10828
|
-
console.error(
|
|
10269
|
+
console.error(chalk40.red("\u2717 An unexpected error occurred"));
|
|
10829
10270
|
}
|
|
10830
10271
|
process.exit(1);
|
|
10831
10272
|
}
|
|
10832
10273
|
});
|
|
10833
10274
|
|
|
10834
10275
|
// src/commands/credential/index.ts
|
|
10835
|
-
var credentialCommand = new
|
|
10276
|
+
var credentialCommand = new Command39().name("credential").description("Manage stored credentials for agent runs").addCommand(listCommand5).addCommand(setCommand2).addCommand(deleteCommand2);
|
|
10836
10277
|
|
|
10837
10278
|
// src/commands/model-provider/index.ts
|
|
10838
|
-
import { Command as
|
|
10279
|
+
import { Command as Command44 } from "commander";
|
|
10839
10280
|
|
|
10840
10281
|
// src/commands/model-provider/list.ts
|
|
10841
|
-
import { Command as
|
|
10842
|
-
import
|
|
10843
|
-
var listCommand6 = new
|
|
10282
|
+
import { Command as Command40 } from "commander";
|
|
10283
|
+
import chalk41 from "chalk";
|
|
10284
|
+
var listCommand6 = new Command40().name("list").alias("ls").description("List all model providers").action(async () => {
|
|
10844
10285
|
try {
|
|
10845
10286
|
const result = await listModelProviders();
|
|
10846
10287
|
if (result.modelProviders.length === 0) {
|
|
10847
|
-
console.log(
|
|
10288
|
+
console.log(chalk41.dim("No model providers configured."));
|
|
10848
10289
|
console.log();
|
|
10849
10290
|
console.log("To add a model provider:");
|
|
10850
|
-
console.log(
|
|
10291
|
+
console.log(chalk41.cyan(" vm0 model-provider setup"));
|
|
10851
10292
|
return;
|
|
10852
10293
|
}
|
|
10853
10294
|
const byFramework = result.modelProviders.reduce(
|
|
@@ -10861,15 +10302,15 @@ var listCommand6 = new Command42().name("list").alias("ls").description("List al
|
|
|
10861
10302
|
},
|
|
10862
10303
|
{}
|
|
10863
10304
|
);
|
|
10864
|
-
console.log(
|
|
10305
|
+
console.log(chalk41.bold("Model Providers:"));
|
|
10865
10306
|
console.log();
|
|
10866
10307
|
for (const [framework, providers] of Object.entries(byFramework)) {
|
|
10867
|
-
console.log(` ${
|
|
10308
|
+
console.log(` ${chalk41.cyan(framework)}:`);
|
|
10868
10309
|
for (const provider of providers) {
|
|
10869
|
-
const defaultTag = provider.isDefault ?
|
|
10310
|
+
const defaultTag = provider.isDefault ? chalk41.green(" (default)") : "";
|
|
10870
10311
|
console.log(` ${provider.type}${defaultTag}`);
|
|
10871
10312
|
console.log(
|
|
10872
|
-
|
|
10313
|
+
chalk41.dim(
|
|
10873
10314
|
` Updated: ${new Date(provider.updatedAt).toLocaleString()}`
|
|
10874
10315
|
)
|
|
10875
10316
|
);
|
|
@@ -10877,25 +10318,25 @@ var listCommand6 = new Command42().name("list").alias("ls").description("List al
|
|
|
10877
10318
|
console.log();
|
|
10878
10319
|
}
|
|
10879
10320
|
console.log(
|
|
10880
|
-
|
|
10321
|
+
chalk41.dim(`Total: ${result.modelProviders.length} provider(s)`)
|
|
10881
10322
|
);
|
|
10882
10323
|
} catch (error) {
|
|
10883
10324
|
if (error instanceof Error) {
|
|
10884
10325
|
if (error.message.includes("Not authenticated")) {
|
|
10885
|
-
console.error(
|
|
10326
|
+
console.error(chalk41.red("x Not authenticated. Run: vm0 auth login"));
|
|
10886
10327
|
} else {
|
|
10887
|
-
console.error(
|
|
10328
|
+
console.error(chalk41.red(`x ${error.message}`));
|
|
10888
10329
|
}
|
|
10889
10330
|
} else {
|
|
10890
|
-
console.error(
|
|
10331
|
+
console.error(chalk41.red("x An unexpected error occurred"));
|
|
10891
10332
|
}
|
|
10892
10333
|
process.exit(1);
|
|
10893
10334
|
}
|
|
10894
10335
|
});
|
|
10895
10336
|
|
|
10896
10337
|
// src/commands/model-provider/setup.ts
|
|
10897
|
-
import { Command as
|
|
10898
|
-
import
|
|
10338
|
+
import { Command as Command41 } from "commander";
|
|
10339
|
+
import chalk42 from "chalk";
|
|
10899
10340
|
import prompts3 from "prompts";
|
|
10900
10341
|
var providerChoices = Object.entries(MODEL_PROVIDER_TYPES).map(
|
|
10901
10342
|
([type, config]) => ({
|
|
@@ -10903,7 +10344,7 @@ var providerChoices = Object.entries(MODEL_PROVIDER_TYPES).map(
|
|
|
10903
10344
|
value: type
|
|
10904
10345
|
})
|
|
10905
10346
|
);
|
|
10906
|
-
var
|
|
10347
|
+
var setupCommand2 = new Command41().name("setup").description("Configure a model provider").option("-t, --type <type>", "Provider type (for non-interactive mode)").option(
|
|
10907
10348
|
"-c, --credential <credential>",
|
|
10908
10349
|
"Credential value (for non-interactive mode)"
|
|
10909
10350
|
).option("--convert", "Convert existing user credential to model provider").action(
|
|
@@ -10914,11 +10355,11 @@ var setupCommand = new Command43().name("setup").description("Configure a model
|
|
|
10914
10355
|
const shouldConvert = options.convert ?? false;
|
|
10915
10356
|
if (options.type && options.credential) {
|
|
10916
10357
|
if (!Object.keys(MODEL_PROVIDER_TYPES).includes(options.type)) {
|
|
10917
|
-
console.error(
|
|
10358
|
+
console.error(chalk42.red(`x Invalid type "${options.type}"`));
|
|
10918
10359
|
console.log();
|
|
10919
10360
|
console.log("Valid types:");
|
|
10920
10361
|
for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
|
|
10921
|
-
console.log(` ${
|
|
10362
|
+
console.log(` ${chalk42.cyan(t)} - ${config.label}`);
|
|
10922
10363
|
}
|
|
10923
10364
|
process.exit(1);
|
|
10924
10365
|
}
|
|
@@ -10926,16 +10367,16 @@ var setupCommand = new Command43().name("setup").description("Configure a model
|
|
|
10926
10367
|
credential = options.credential;
|
|
10927
10368
|
} else if (options.type || options.credential) {
|
|
10928
10369
|
console.error(
|
|
10929
|
-
|
|
10370
|
+
chalk42.red("x Both --type and --credential are required")
|
|
10930
10371
|
);
|
|
10931
10372
|
process.exit(1);
|
|
10932
10373
|
} else {
|
|
10933
10374
|
if (!isInteractive()) {
|
|
10934
|
-
console.error(
|
|
10375
|
+
console.error(chalk42.red("x Interactive mode requires a TTY"));
|
|
10935
10376
|
console.log();
|
|
10936
10377
|
console.log("Use non-interactive mode:");
|
|
10937
10378
|
console.log(
|
|
10938
|
-
|
|
10379
|
+
chalk42.cyan(
|
|
10939
10380
|
' vm0 model-provider setup --type <type> --credential "<value>"'
|
|
10940
10381
|
)
|
|
10941
10382
|
);
|
|
@@ -10966,19 +10407,19 @@ var setupCommand = new Command43().name("setup").description("Configure a model
|
|
|
10966
10407
|
const provider2 = await convertModelProviderCredential(type);
|
|
10967
10408
|
const defaultNote2 = provider2.isDefault ? ` (default for ${provider2.framework})` : "";
|
|
10968
10409
|
console.log(
|
|
10969
|
-
|
|
10410
|
+
chalk42.green(
|
|
10970
10411
|
`Done Converted "${checkResult.credentialName}" to model provider${defaultNote2}`
|
|
10971
10412
|
)
|
|
10972
10413
|
);
|
|
10973
10414
|
return;
|
|
10974
10415
|
} else {
|
|
10975
|
-
console.log(
|
|
10416
|
+
console.log(chalk42.dim("Aborted."));
|
|
10976
10417
|
process.exit(0);
|
|
10977
10418
|
}
|
|
10978
10419
|
}
|
|
10979
10420
|
const config = MODEL_PROVIDER_TYPES[type];
|
|
10980
10421
|
console.log();
|
|
10981
|
-
console.log(
|
|
10422
|
+
console.log(chalk42.dim(config.helpText));
|
|
10982
10423
|
console.log();
|
|
10983
10424
|
const credentialResponse = await prompts3(
|
|
10984
10425
|
{
|
|
@@ -10999,24 +10440,24 @@ var setupCommand = new Command43().name("setup").description("Configure a model
|
|
|
10999
10440
|
const action = created ? "created" : "updated";
|
|
11000
10441
|
const defaultNote = provider.isDefault ? ` (default for ${provider.framework})` : "";
|
|
11001
10442
|
console.log(
|
|
11002
|
-
|
|
10443
|
+
chalk42.green(`Done Model provider "${type}" ${action}${defaultNote}`)
|
|
11003
10444
|
);
|
|
11004
10445
|
} catch (error) {
|
|
11005
10446
|
if (error instanceof Error) {
|
|
11006
10447
|
if (error.message.includes("already exists")) {
|
|
11007
|
-
console.error(
|
|
10448
|
+
console.error(chalk42.red(`x ${error.message}`));
|
|
11008
10449
|
console.log();
|
|
11009
10450
|
console.log("To convert the existing credential, run:");
|
|
11010
|
-
console.log(
|
|
10451
|
+
console.log(chalk42.cyan(" vm0 model-provider setup --convert"));
|
|
11011
10452
|
} else if (error.message.includes("Not authenticated")) {
|
|
11012
10453
|
console.error(
|
|
11013
|
-
|
|
10454
|
+
chalk42.red("x Not authenticated. Run: vm0 auth login")
|
|
11014
10455
|
);
|
|
11015
10456
|
} else {
|
|
11016
|
-
console.error(
|
|
10457
|
+
console.error(chalk42.red(`x ${error.message}`));
|
|
11017
10458
|
}
|
|
11018
10459
|
} else {
|
|
11019
|
-
console.error(
|
|
10460
|
+
console.error(chalk42.red("x An unexpected error occurred"));
|
|
11020
10461
|
}
|
|
11021
10462
|
process.exit(1);
|
|
11022
10463
|
}
|
|
@@ -11024,81 +10465,81 @@ var setupCommand = new Command43().name("setup").description("Configure a model
|
|
|
11024
10465
|
);
|
|
11025
10466
|
|
|
11026
10467
|
// src/commands/model-provider/delete.ts
|
|
11027
|
-
import { Command as
|
|
11028
|
-
import
|
|
11029
|
-
var deleteCommand3 = new
|
|
10468
|
+
import { Command as Command42 } from "commander";
|
|
10469
|
+
import chalk43 from "chalk";
|
|
10470
|
+
var deleteCommand3 = new Command42().name("delete").description("Delete a model provider").argument("<type>", "Model provider type to delete").action(async (type) => {
|
|
11030
10471
|
try {
|
|
11031
10472
|
if (!Object.keys(MODEL_PROVIDER_TYPES).includes(type)) {
|
|
11032
|
-
console.error(
|
|
10473
|
+
console.error(chalk43.red(`x Invalid type "${type}"`));
|
|
11033
10474
|
console.log();
|
|
11034
10475
|
console.log("Valid types:");
|
|
11035
10476
|
for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
|
|
11036
|
-
console.log(` ${
|
|
10477
|
+
console.log(` ${chalk43.cyan(t)} - ${config.label}`);
|
|
11037
10478
|
}
|
|
11038
10479
|
process.exit(1);
|
|
11039
10480
|
}
|
|
11040
10481
|
await deleteModelProvider(type);
|
|
11041
|
-
console.log(
|
|
10482
|
+
console.log(chalk43.green(`Done Model provider "${type}" deleted`));
|
|
11042
10483
|
} catch (error) {
|
|
11043
10484
|
if (error instanceof Error) {
|
|
11044
10485
|
if (error.message.includes("not found")) {
|
|
11045
|
-
console.error(
|
|
10486
|
+
console.error(chalk43.red(`x Model provider "${type}" not found`));
|
|
11046
10487
|
} else if (error.message.includes("Not authenticated")) {
|
|
11047
|
-
console.error(
|
|
10488
|
+
console.error(chalk43.red("x Not authenticated. Run: vm0 auth login"));
|
|
11048
10489
|
} else {
|
|
11049
|
-
console.error(
|
|
10490
|
+
console.error(chalk43.red(`x ${error.message}`));
|
|
11050
10491
|
}
|
|
11051
10492
|
} else {
|
|
11052
|
-
console.error(
|
|
10493
|
+
console.error(chalk43.red("x An unexpected error occurred"));
|
|
11053
10494
|
}
|
|
11054
10495
|
process.exit(1);
|
|
11055
10496
|
}
|
|
11056
10497
|
});
|
|
11057
10498
|
|
|
11058
10499
|
// src/commands/model-provider/set-default.ts
|
|
11059
|
-
import { Command as
|
|
11060
|
-
import
|
|
11061
|
-
var setDefaultCommand = new
|
|
10500
|
+
import { Command as Command43 } from "commander";
|
|
10501
|
+
import chalk44 from "chalk";
|
|
10502
|
+
var setDefaultCommand = new Command43().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) => {
|
|
11062
10503
|
try {
|
|
11063
10504
|
if (!Object.keys(MODEL_PROVIDER_TYPES).includes(type)) {
|
|
11064
|
-
console.error(
|
|
10505
|
+
console.error(chalk44.red(`x Invalid type "${type}"`));
|
|
11065
10506
|
console.log();
|
|
11066
10507
|
console.log("Valid types:");
|
|
11067
10508
|
for (const [t, config] of Object.entries(MODEL_PROVIDER_TYPES)) {
|
|
11068
|
-
console.log(` ${
|
|
10509
|
+
console.log(` ${chalk44.cyan(t)} - ${config.label}`);
|
|
11069
10510
|
}
|
|
11070
10511
|
process.exit(1);
|
|
11071
10512
|
}
|
|
11072
10513
|
const provider = await setModelProviderDefault(type);
|
|
11073
10514
|
console.log(
|
|
11074
|
-
|
|
10515
|
+
chalk44.green(
|
|
11075
10516
|
`Done Default for ${provider.framework} set to "${provider.type}"`
|
|
11076
10517
|
)
|
|
11077
10518
|
);
|
|
11078
10519
|
} catch (error) {
|
|
11079
10520
|
if (error instanceof Error) {
|
|
11080
10521
|
if (error.message.includes("not found")) {
|
|
11081
|
-
console.error(
|
|
10522
|
+
console.error(chalk44.red(`x Model provider "${type}" not found`));
|
|
11082
10523
|
} else if (error.message.includes("Not authenticated")) {
|
|
11083
|
-
console.error(
|
|
10524
|
+
console.error(chalk44.red("x Not authenticated. Run: vm0 auth login"));
|
|
11084
10525
|
} else {
|
|
11085
|
-
console.error(
|
|
10526
|
+
console.error(chalk44.red(`x ${error.message}`));
|
|
11086
10527
|
}
|
|
11087
10528
|
} else {
|
|
11088
|
-
console.error(
|
|
10529
|
+
console.error(chalk44.red("x An unexpected error occurred"));
|
|
11089
10530
|
}
|
|
11090
10531
|
process.exit(1);
|
|
11091
10532
|
}
|
|
11092
10533
|
});
|
|
11093
10534
|
|
|
11094
10535
|
// src/commands/model-provider/index.ts
|
|
11095
|
-
var modelProviderCommand = new
|
|
10536
|
+
var modelProviderCommand = new Command44().name("model-provider").description("Manage model providers for agent runs").addCommand(listCommand6).addCommand(setupCommand2).addCommand(deleteCommand3).addCommand(setDefaultCommand);
|
|
11096
10537
|
|
|
11097
10538
|
// src/index.ts
|
|
11098
|
-
var program = new
|
|
11099
|
-
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("
|
|
10539
|
+
var program = new Command45();
|
|
10540
|
+
program.name("vm0").description("VM0 CLI - Build and run agents with natural language").version("8.0.0");
|
|
11100
10541
|
program.command("info").description("Display environment information").action(async () => {
|
|
11101
|
-
console.log(
|
|
10542
|
+
console.log(chalk45.bold("System Information:"));
|
|
11102
10543
|
console.log(`Node Version: ${process.version}`);
|
|
11103
10544
|
console.log(`Platform: ${process.platform}`);
|
|
11104
10545
|
console.log(`Architecture: ${process.arch}`);
|
|
@@ -11127,7 +10568,6 @@ program.addCommand(logsCommand);
|
|
|
11127
10568
|
program.addCommand(scopeCommand);
|
|
11128
10569
|
program.addCommand(agentCommand);
|
|
11129
10570
|
program.addCommand(initCommand3);
|
|
11130
|
-
program.addCommand(setupGithubCommand);
|
|
11131
10571
|
program.addCommand(scheduleCommand);
|
|
11132
10572
|
program.addCommand(usageCommand);
|
|
11133
10573
|
program.addCommand(credentialCommand);
|