@vm0/cli 5.5.0 → 5.7.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 +595 -510
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command as Command35 } from "commander";
|
|
5
|
-
import
|
|
5
|
+
import chalk36 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/lib/api/auth.ts
|
|
8
8
|
import chalk from "chalk";
|
|
@@ -5132,7 +5132,7 @@ import { Command as Command9 } from "commander";
|
|
|
5132
5132
|
|
|
5133
5133
|
// src/commands/volume/init.ts
|
|
5134
5134
|
import { Command as Command3 } from "commander";
|
|
5135
|
-
import
|
|
5135
|
+
import chalk6 from "chalk";
|
|
5136
5136
|
import path7 from "path";
|
|
5137
5137
|
|
|
5138
5138
|
// src/lib/storage/storage-utils.ts
|
|
@@ -5184,7 +5184,6 @@ async function writeStorageConfig(storageName, basePath = process.cwd(), type =
|
|
|
5184
5184
|
|
|
5185
5185
|
// src/lib/utils/prompt-utils.ts
|
|
5186
5186
|
import prompts2 from "prompts";
|
|
5187
|
-
import chalk6 from "chalk";
|
|
5188
5187
|
function isInteractive() {
|
|
5189
5188
|
return process.stdout.isTTY === true;
|
|
5190
5189
|
}
|
|
@@ -5247,48 +5246,6 @@ async function promptSelect(message, choices, initial) {
|
|
|
5247
5246
|
);
|
|
5248
5247
|
return response.value;
|
|
5249
5248
|
}
|
|
5250
|
-
async function promptTextWithHint(message, hint, initial, validate) {
|
|
5251
|
-
if (!isInteractive()) {
|
|
5252
|
-
return void 0;
|
|
5253
|
-
}
|
|
5254
|
-
const hintedInitial = `${hint} ${initial}`;
|
|
5255
|
-
const response = await prompts2(
|
|
5256
|
-
{
|
|
5257
|
-
type: "text",
|
|
5258
|
-
name: "value",
|
|
5259
|
-
message,
|
|
5260
|
-
initial: hintedInitial,
|
|
5261
|
-
// Custom render to show hint in gray
|
|
5262
|
-
onRender() {
|
|
5263
|
-
if (this.value.startsWith(hint + " ")) {
|
|
5264
|
-
const hintPart = hint + " ";
|
|
5265
|
-
const valuePart = this.value.slice(hintPart.length);
|
|
5266
|
-
this.rendered = chalk6.dim(hintPart) + valuePart;
|
|
5267
|
-
}
|
|
5268
|
-
},
|
|
5269
|
-
// Validate after stripping hint
|
|
5270
|
-
validate: validate ? (value) => {
|
|
5271
|
-
const stripped = stripHintPrefix(value, hint);
|
|
5272
|
-
return validate(stripped);
|
|
5273
|
-
} : void 0,
|
|
5274
|
-
// Format the final value to strip hint
|
|
5275
|
-
format: (value) => stripHintPrefix(value, hint)
|
|
5276
|
-
},
|
|
5277
|
-
{
|
|
5278
|
-
onCancel: () => {
|
|
5279
|
-
return false;
|
|
5280
|
-
}
|
|
5281
|
-
}
|
|
5282
|
-
);
|
|
5283
|
-
return response.value;
|
|
5284
|
-
}
|
|
5285
|
-
function stripHintPrefix(value, hint) {
|
|
5286
|
-
const prefix = hint + " ";
|
|
5287
|
-
if (value.startsWith(prefix)) {
|
|
5288
|
-
return value.slice(prefix.length);
|
|
5289
|
-
}
|
|
5290
|
-
return value;
|
|
5291
|
-
}
|
|
5292
5249
|
|
|
5293
5250
|
// src/commands/volume/init.ts
|
|
5294
5251
|
var initCommand = new Command3().name("init").description("Initialize a volume in the current directory").option("-n, --name <name>", "Volume name (required in non-interactive mode)").action(async (options) => {
|
|
@@ -5298,10 +5255,10 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
5298
5255
|
const existingConfig = await readStorageConfig(cwd);
|
|
5299
5256
|
if (existingConfig) {
|
|
5300
5257
|
console.log(
|
|
5301
|
-
|
|
5258
|
+
chalk6.yellow(`Volume already initialized: ${existingConfig.name}`)
|
|
5302
5259
|
);
|
|
5303
5260
|
console.log(
|
|
5304
|
-
|
|
5261
|
+
chalk6.dim(`Config file: ${path7.join(cwd, ".vm0", "storage.yaml")}`)
|
|
5305
5262
|
);
|
|
5306
5263
|
return;
|
|
5307
5264
|
}
|
|
@@ -5310,10 +5267,10 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
5310
5267
|
volumeName = options.name;
|
|
5311
5268
|
} else if (!isInteractive()) {
|
|
5312
5269
|
console.error(
|
|
5313
|
-
|
|
5270
|
+
chalk6.red("\u2717 --name flag is required in non-interactive mode")
|
|
5314
5271
|
);
|
|
5315
5272
|
console.error(
|
|
5316
|
-
|
|
5273
|
+
chalk6.dim(" Usage: vm0 volume init --name <volume-name>")
|
|
5317
5274
|
);
|
|
5318
5275
|
process.exit(1);
|
|
5319
5276
|
} else {
|
|
@@ -5329,34 +5286,34 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
5329
5286
|
}
|
|
5330
5287
|
);
|
|
5331
5288
|
if (name === void 0) {
|
|
5332
|
-
console.log(
|
|
5289
|
+
console.log(chalk6.dim("Cancelled"));
|
|
5333
5290
|
return;
|
|
5334
5291
|
}
|
|
5335
5292
|
volumeName = name;
|
|
5336
5293
|
}
|
|
5337
5294
|
if (!isValidStorageName(volumeName)) {
|
|
5338
|
-
console.error(
|
|
5295
|
+
console.error(chalk6.red(`\u2717 Invalid volume name: "${volumeName}"`));
|
|
5339
5296
|
console.error(
|
|
5340
|
-
|
|
5297
|
+
chalk6.dim(
|
|
5341
5298
|
" Volume names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
5342
5299
|
)
|
|
5343
5300
|
);
|
|
5344
5301
|
console.error(
|
|
5345
|
-
|
|
5302
|
+
chalk6.dim(" Example: my-dataset, user-data-v2, training-set-2024")
|
|
5346
5303
|
);
|
|
5347
5304
|
process.exit(1);
|
|
5348
5305
|
}
|
|
5349
5306
|
await writeStorageConfig(volumeName, cwd);
|
|
5350
|
-
console.log(
|
|
5307
|
+
console.log(chalk6.green(`\u2713 Initialized volume: ${volumeName}`));
|
|
5351
5308
|
console.log(
|
|
5352
|
-
|
|
5309
|
+
chalk6.dim(
|
|
5353
5310
|
`\u2713 Config saved to ${path7.join(cwd, ".vm0", "storage.yaml")}`
|
|
5354
5311
|
)
|
|
5355
5312
|
);
|
|
5356
5313
|
} catch (error) {
|
|
5357
|
-
console.error(
|
|
5314
|
+
console.error(chalk6.red("\u2717 Failed to initialize volume"));
|
|
5358
5315
|
if (error instanceof Error) {
|
|
5359
|
-
console.error(
|
|
5316
|
+
console.error(chalk6.dim(` ${error.message}`));
|
|
5360
5317
|
}
|
|
5361
5318
|
process.exit(1);
|
|
5362
5319
|
}
|
|
@@ -5364,7 +5321,7 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
5364
5321
|
|
|
5365
5322
|
// src/commands/volume/push.ts
|
|
5366
5323
|
import { Command as Command4 } from "commander";
|
|
5367
|
-
import
|
|
5324
|
+
import chalk7 from "chalk";
|
|
5368
5325
|
function formatBytes2(bytes) {
|
|
5369
5326
|
if (bytes === 0) return "0 B";
|
|
5370
5327
|
const k = 1024;
|
|
@@ -5380,35 +5337,35 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
5380
5337
|
const cwd = process.cwd();
|
|
5381
5338
|
const config = await readStorageConfig(cwd);
|
|
5382
5339
|
if (!config) {
|
|
5383
|
-
console.error(
|
|
5384
|
-
console.error(
|
|
5340
|
+
console.error(chalk7.red("\u2717 No volume initialized in this directory"));
|
|
5341
|
+
console.error(chalk7.dim(" Run: vm0 volume init"));
|
|
5385
5342
|
process.exit(1);
|
|
5386
5343
|
}
|
|
5387
5344
|
console.log(`Pushing volume: ${config.name}`);
|
|
5388
5345
|
const result = await directUpload(config.name, "volume", cwd, {
|
|
5389
5346
|
onProgress: (message) => {
|
|
5390
|
-
console.log(
|
|
5347
|
+
console.log(chalk7.dim(message));
|
|
5391
5348
|
},
|
|
5392
5349
|
force: options.force
|
|
5393
5350
|
});
|
|
5394
5351
|
const shortVersion = result.versionId.slice(0, 8);
|
|
5395
5352
|
if (result.empty) {
|
|
5396
|
-
console.log(
|
|
5353
|
+
console.log(chalk7.yellow("No files found (empty volume)"));
|
|
5397
5354
|
} else if (result.deduplicated) {
|
|
5398
|
-
console.log(
|
|
5355
|
+
console.log(chalk7.green("\u2713 Content unchanged (deduplicated)"));
|
|
5399
5356
|
} else {
|
|
5400
|
-
console.log(
|
|
5357
|
+
console.log(chalk7.green("\u2713 Upload complete"));
|
|
5401
5358
|
}
|
|
5402
|
-
console.log(
|
|
5403
|
-
console.log(
|
|
5404
|
-
console.log(
|
|
5359
|
+
console.log(chalk7.dim(` Version: ${shortVersion}`));
|
|
5360
|
+
console.log(chalk7.dim(` Files: ${result.fileCount.toLocaleString()}`));
|
|
5361
|
+
console.log(chalk7.dim(` Size: ${formatBytes2(result.size)}`));
|
|
5405
5362
|
} catch (error) {
|
|
5406
|
-
console.error(
|
|
5363
|
+
console.error(chalk7.red("\u2717 Push failed"));
|
|
5407
5364
|
if (error instanceof Error) {
|
|
5408
5365
|
if (error.message.includes("Not authenticated")) {
|
|
5409
|
-
console.error(
|
|
5366
|
+
console.error(chalk7.dim(" Run: vm0 auth login"));
|
|
5410
5367
|
} else {
|
|
5411
|
-
console.error(
|
|
5368
|
+
console.error(chalk7.dim(` ${error.message}`));
|
|
5412
5369
|
}
|
|
5413
5370
|
}
|
|
5414
5371
|
process.exit(1);
|
|
@@ -5417,21 +5374,21 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
5417
5374
|
|
|
5418
5375
|
// src/commands/volume/pull.ts
|
|
5419
5376
|
import { Command as Command5 } from "commander";
|
|
5420
|
-
import
|
|
5377
|
+
import chalk9 from "chalk";
|
|
5421
5378
|
import path8 from "path";
|
|
5422
5379
|
import * as fs6 from "fs";
|
|
5423
5380
|
import * as os4 from "os";
|
|
5424
5381
|
import * as tar3 from "tar";
|
|
5425
5382
|
|
|
5426
5383
|
// src/lib/storage/pull-utils.ts
|
|
5427
|
-
import
|
|
5384
|
+
import chalk8 from "chalk";
|
|
5428
5385
|
async function handleEmptyStorageResponse(cwd) {
|
|
5429
|
-
console.log(
|
|
5386
|
+
console.log(chalk8.dim("Syncing local files..."));
|
|
5430
5387
|
const removedCount = await removeExtraFiles(cwd, /* @__PURE__ */ new Set());
|
|
5431
5388
|
if (removedCount > 0) {
|
|
5432
|
-
console.log(
|
|
5389
|
+
console.log(chalk8.green(`\u2713 Removed ${removedCount} files not in remote`));
|
|
5433
5390
|
}
|
|
5434
|
-
console.log(
|
|
5391
|
+
console.log(chalk8.green("\u2713 Synced (0 files)"));
|
|
5435
5392
|
return { removedCount };
|
|
5436
5393
|
}
|
|
5437
5394
|
|
|
@@ -5448,8 +5405,8 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
5448
5405
|
const cwd = process.cwd();
|
|
5449
5406
|
const config = await readStorageConfig(cwd);
|
|
5450
5407
|
if (!config) {
|
|
5451
|
-
console.error(
|
|
5452
|
-
console.error(
|
|
5408
|
+
console.error(chalk9.red("\u2717 No volume initialized in this directory"));
|
|
5409
|
+
console.error(chalk9.dim(" Run: vm0 volume init"));
|
|
5453
5410
|
process.exit(1);
|
|
5454
5411
|
}
|
|
5455
5412
|
if (versionId) {
|
|
@@ -5457,7 +5414,7 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
5457
5414
|
} else {
|
|
5458
5415
|
console.log(`Pulling volume: ${config.name}`);
|
|
5459
5416
|
}
|
|
5460
|
-
console.log(
|
|
5417
|
+
console.log(chalk9.dim("Getting download URL..."));
|
|
5461
5418
|
let url = `/api/storages/download?name=${encodeURIComponent(config.name)}&type=volume`;
|
|
5462
5419
|
if (versionId) {
|
|
5463
5420
|
const quotedVersion = JSON.stringify(versionId);
|
|
@@ -5466,14 +5423,14 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
5466
5423
|
const response = await apiClient.get(url);
|
|
5467
5424
|
if (!response.ok) {
|
|
5468
5425
|
if (response.status === 404) {
|
|
5469
|
-
console.error(
|
|
5426
|
+
console.error(chalk9.red(`\u2717 Volume "${config.name}" not found`));
|
|
5470
5427
|
console.error(
|
|
5471
|
-
|
|
5428
|
+
chalk9.dim(
|
|
5472
5429
|
" Make sure the volume name is correct in .vm0/storage.yaml"
|
|
5473
5430
|
)
|
|
5474
5431
|
);
|
|
5475
5432
|
console.error(
|
|
5476
|
-
|
|
5433
|
+
chalk9.dim(" Or push the volume first with: vm0 volume push")
|
|
5477
5434
|
);
|
|
5478
5435
|
} else {
|
|
5479
5436
|
const error = await response.json();
|
|
@@ -5489,18 +5446,18 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
5489
5446
|
if (!downloadInfo.url) {
|
|
5490
5447
|
throw new Error("No download URL returned");
|
|
5491
5448
|
}
|
|
5492
|
-
console.log(
|
|
5449
|
+
console.log(chalk9.dim("Downloading from S3..."));
|
|
5493
5450
|
const s3Response = await fetch(downloadInfo.url);
|
|
5494
5451
|
if (!s3Response.ok) {
|
|
5495
5452
|
throw new Error(`S3 download failed: ${s3Response.status}`);
|
|
5496
5453
|
}
|
|
5497
5454
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
5498
5455
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
5499
|
-
console.log(
|
|
5456
|
+
console.log(chalk9.green(`\u2713 Downloaded ${formatBytes3(tarBuffer.length)}`));
|
|
5500
5457
|
const tmpDir = fs6.mkdtempSync(path8.join(os4.tmpdir(), "vm0-"));
|
|
5501
5458
|
const tarPath = path8.join(tmpDir, "volume.tar.gz");
|
|
5502
5459
|
await fs6.promises.writeFile(tarPath, tarBuffer);
|
|
5503
|
-
console.log(
|
|
5460
|
+
console.log(chalk9.dim("Syncing local files..."));
|
|
5504
5461
|
const remoteFiles = await listTarFiles(tarPath);
|
|
5505
5462
|
const remoteFilesSet = new Set(
|
|
5506
5463
|
remoteFiles.map((f) => f.replace(/\\/g, "/"))
|
|
@@ -5508,10 +5465,10 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
5508
5465
|
const removedCount = await removeExtraFiles(cwd, remoteFilesSet);
|
|
5509
5466
|
if (removedCount > 0) {
|
|
5510
5467
|
console.log(
|
|
5511
|
-
|
|
5468
|
+
chalk9.green(`\u2713 Removed ${removedCount} files not in remote`)
|
|
5512
5469
|
);
|
|
5513
5470
|
}
|
|
5514
|
-
console.log(
|
|
5471
|
+
console.log(chalk9.dim("Extracting files..."));
|
|
5515
5472
|
await tar3.extract({
|
|
5516
5473
|
file: tarPath,
|
|
5517
5474
|
cwd,
|
|
@@ -5519,14 +5476,14 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
5519
5476
|
});
|
|
5520
5477
|
await fs6.promises.unlink(tarPath);
|
|
5521
5478
|
await fs6.promises.rmdir(tmpDir);
|
|
5522
|
-
console.log(
|
|
5479
|
+
console.log(chalk9.green(`\u2713 Extracted ${remoteFiles.length} files`));
|
|
5523
5480
|
} catch (error) {
|
|
5524
|
-
console.error(
|
|
5481
|
+
console.error(chalk9.red("\u2717 Pull failed"));
|
|
5525
5482
|
if (error instanceof Error) {
|
|
5526
5483
|
if (error.message.includes("Not authenticated")) {
|
|
5527
|
-
console.error(
|
|
5484
|
+
console.error(chalk9.dim(" Run: vm0 auth login"));
|
|
5528
5485
|
} else {
|
|
5529
|
-
console.error(
|
|
5486
|
+
console.error(chalk9.dim(` ${error.message}`));
|
|
5530
5487
|
}
|
|
5531
5488
|
}
|
|
5532
5489
|
process.exit(1);
|
|
@@ -5535,7 +5492,7 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
5535
5492
|
|
|
5536
5493
|
// src/commands/volume/status.ts
|
|
5537
5494
|
import { Command as Command6 } from "commander";
|
|
5538
|
-
import
|
|
5495
|
+
import chalk10 from "chalk";
|
|
5539
5496
|
function formatBytes4(bytes) {
|
|
5540
5497
|
if (bytes === 0) return "0 B";
|
|
5541
5498
|
const k = 1024;
|
|
@@ -5548,17 +5505,17 @@ var statusCommand = new Command6().name("status").description("Show status of cl
|
|
|
5548
5505
|
const cwd = process.cwd();
|
|
5549
5506
|
const config = await readStorageConfig(cwd);
|
|
5550
5507
|
if (!config) {
|
|
5551
|
-
console.error(
|
|
5552
|
-
console.error(
|
|
5508
|
+
console.error(chalk10.red("\u2717 No volume initialized in this directory"));
|
|
5509
|
+
console.error(chalk10.dim(" Run: vm0 volume init"));
|
|
5553
5510
|
process.exit(1);
|
|
5554
5511
|
}
|
|
5555
5512
|
if (config.type !== "volume") {
|
|
5556
5513
|
console.error(
|
|
5557
|
-
|
|
5514
|
+
chalk10.red(
|
|
5558
5515
|
"\u2717 This directory is initialized as an artifact, not a volume"
|
|
5559
5516
|
)
|
|
5560
5517
|
);
|
|
5561
|
-
console.error(
|
|
5518
|
+
console.error(chalk10.dim(" Use: vm0 artifact status"));
|
|
5562
5519
|
process.exit(1);
|
|
5563
5520
|
}
|
|
5564
5521
|
console.log(`Checking volume: ${config.name}`);
|
|
@@ -5566,8 +5523,8 @@ var statusCommand = new Command6().name("status").description("Show status of cl
|
|
|
5566
5523
|
const response = await apiClient.get(url);
|
|
5567
5524
|
if (!response.ok) {
|
|
5568
5525
|
if (response.status === 404) {
|
|
5569
|
-
console.error(
|
|
5570
|
-
console.error(
|
|
5526
|
+
console.error(chalk10.red("\u2717 Not found on remote"));
|
|
5527
|
+
console.error(chalk10.dim(" Run: vm0 volume push"));
|
|
5571
5528
|
} else {
|
|
5572
5529
|
const error = await response.json();
|
|
5573
5530
|
throw new Error(error.error?.message || "Status check failed");
|
|
@@ -5577,21 +5534,21 @@ var statusCommand = new Command6().name("status").description("Show status of cl
|
|
|
5577
5534
|
const info = await response.json();
|
|
5578
5535
|
const shortVersion = info.versionId.slice(0, 8);
|
|
5579
5536
|
if (info.empty) {
|
|
5580
|
-
console.log(
|
|
5581
|
-
console.log(
|
|
5537
|
+
console.log(chalk10.green("\u2713 Found (empty)"));
|
|
5538
|
+
console.log(chalk10.dim(` Version: ${shortVersion}`));
|
|
5582
5539
|
} else {
|
|
5583
|
-
console.log(
|
|
5584
|
-
console.log(
|
|
5585
|
-
console.log(
|
|
5586
|
-
console.log(
|
|
5540
|
+
console.log(chalk10.green("\u2713 Found"));
|
|
5541
|
+
console.log(chalk10.dim(` Version: ${shortVersion}`));
|
|
5542
|
+
console.log(chalk10.dim(` Files: ${info.fileCount.toLocaleString()}`));
|
|
5543
|
+
console.log(chalk10.dim(` Size: ${formatBytes4(info.size)}`));
|
|
5587
5544
|
}
|
|
5588
5545
|
} catch (error) {
|
|
5589
|
-
console.error(
|
|
5546
|
+
console.error(chalk10.red("\u2717 Status check failed"));
|
|
5590
5547
|
if (error instanceof Error) {
|
|
5591
5548
|
if (error.message.includes("Not authenticated")) {
|
|
5592
|
-
console.error(
|
|
5549
|
+
console.error(chalk10.dim(" Run: vm0 auth login"));
|
|
5593
5550
|
} else {
|
|
5594
|
-
console.error(
|
|
5551
|
+
console.error(chalk10.dim(` ${error.message}`));
|
|
5595
5552
|
}
|
|
5596
5553
|
}
|
|
5597
5554
|
process.exit(1);
|
|
@@ -5600,7 +5557,7 @@ var statusCommand = new Command6().name("status").description("Show status of cl
|
|
|
5600
5557
|
|
|
5601
5558
|
// src/commands/volume/list.ts
|
|
5602
5559
|
import { Command as Command7 } from "commander";
|
|
5603
|
-
import
|
|
5560
|
+
import chalk11 from "chalk";
|
|
5604
5561
|
var listCommand = new Command7().name("list").alias("ls").description("List all remote volumes").action(async () => {
|
|
5605
5562
|
try {
|
|
5606
5563
|
const url = "/api/storages/list?type=volume";
|
|
@@ -5611,9 +5568,9 @@ var listCommand = new Command7().name("list").alias("ls").description("List all
|
|
|
5611
5568
|
}
|
|
5612
5569
|
const items = await response.json();
|
|
5613
5570
|
if (items.length === 0) {
|
|
5614
|
-
console.log(
|
|
5571
|
+
console.log(chalk11.dim("No volumes found"));
|
|
5615
5572
|
console.log(
|
|
5616
|
-
|
|
5573
|
+
chalk11.dim(" Create one with: vm0 volume init && vm0 volume push")
|
|
5617
5574
|
);
|
|
5618
5575
|
return;
|
|
5619
5576
|
}
|
|
@@ -5632,7 +5589,7 @@ var listCommand = new Command7().name("list").alias("ls").description("List all
|
|
|
5632
5589
|
"FILES".padStart(filesWidth),
|
|
5633
5590
|
"UPDATED"
|
|
5634
5591
|
].join(" ");
|
|
5635
|
-
console.log(
|
|
5592
|
+
console.log(chalk11.dim(header));
|
|
5636
5593
|
for (const item of items) {
|
|
5637
5594
|
const row = [
|
|
5638
5595
|
item.name.padEnd(nameWidth),
|
|
@@ -5643,12 +5600,12 @@ var listCommand = new Command7().name("list").alias("ls").description("List all
|
|
|
5643
5600
|
console.log(row);
|
|
5644
5601
|
}
|
|
5645
5602
|
} catch (error) {
|
|
5646
|
-
console.error(
|
|
5603
|
+
console.error(chalk11.red("\u2717 Failed to list volumes"));
|
|
5647
5604
|
if (error instanceof Error) {
|
|
5648
5605
|
if (error.message.includes("Not authenticated")) {
|
|
5649
|
-
console.error(
|
|
5606
|
+
console.error(chalk11.dim(" Run: vm0 auth login"));
|
|
5650
5607
|
} else {
|
|
5651
|
-
console.error(
|
|
5608
|
+
console.error(chalk11.dim(` ${error.message}`));
|
|
5652
5609
|
}
|
|
5653
5610
|
}
|
|
5654
5611
|
process.exit(1);
|
|
@@ -5657,10 +5614,10 @@ var listCommand = new Command7().name("list").alias("ls").description("List all
|
|
|
5657
5614
|
|
|
5658
5615
|
// src/commands/volume/clone.ts
|
|
5659
5616
|
import { Command as Command8 } from "commander";
|
|
5660
|
-
import
|
|
5617
|
+
import chalk13 from "chalk";
|
|
5661
5618
|
|
|
5662
5619
|
// src/lib/storage/clone-utils.ts
|
|
5663
|
-
import
|
|
5620
|
+
import chalk12 from "chalk";
|
|
5664
5621
|
import path9 from "path";
|
|
5665
5622
|
import * as fs7 from "fs";
|
|
5666
5623
|
import * as os5 from "os";
|
|
@@ -5670,7 +5627,7 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
5670
5627
|
if (fs7.existsSync(destination)) {
|
|
5671
5628
|
throw new Error(`Directory "${destination}" already exists`);
|
|
5672
5629
|
}
|
|
5673
|
-
console.log(
|
|
5630
|
+
console.log(chalk12.dim(`Checking remote ${typeLabel}...`));
|
|
5674
5631
|
let url = `/api/storages/download?name=${encodeURIComponent(name)}&type=${type}`;
|
|
5675
5632
|
if (options.version) {
|
|
5676
5633
|
const quotedVersion = JSON.stringify(options.version);
|
|
@@ -5687,12 +5644,12 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
5687
5644
|
throw new Error(error.error?.message || "Clone failed");
|
|
5688
5645
|
}
|
|
5689
5646
|
const downloadInfo = await response.json();
|
|
5690
|
-
console.log(
|
|
5647
|
+
console.log(chalk12.dim(`Creating directory: ${destination}/`));
|
|
5691
5648
|
await fs7.promises.mkdir(destination, { recursive: true });
|
|
5692
5649
|
if (downloadInfo.empty) {
|
|
5693
5650
|
await writeStorageConfig(name, destination, type);
|
|
5694
|
-
console.log(
|
|
5695
|
-
console.log(
|
|
5651
|
+
console.log(chalk12.green(`\u2713 Cloned empty ${typeLabel}: ${name}`));
|
|
5652
|
+
console.log(chalk12.dim(`\u2713 Initialized .vm0/storage.yaml`));
|
|
5696
5653
|
return {
|
|
5697
5654
|
success: true,
|
|
5698
5655
|
fileCount: 0,
|
|
@@ -5703,7 +5660,7 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
5703
5660
|
if (!downloadInfo.url) {
|
|
5704
5661
|
throw new Error("No download URL returned");
|
|
5705
5662
|
}
|
|
5706
|
-
console.log(
|
|
5663
|
+
console.log(chalk12.dim("Downloading from S3..."));
|
|
5707
5664
|
const s3Response = await fetch(downloadInfo.url);
|
|
5708
5665
|
if (!s3Response.ok) {
|
|
5709
5666
|
await fs7.promises.rm(destination, { recursive: true, force: true });
|
|
@@ -5711,12 +5668,12 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
5711
5668
|
}
|
|
5712
5669
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
5713
5670
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
5714
|
-
console.log(
|
|
5671
|
+
console.log(chalk12.green(`\u2713 Downloaded ${formatBytes(tarBuffer.length)}`));
|
|
5715
5672
|
const tmpDir = fs7.mkdtempSync(path9.join(os5.tmpdir(), "vm0-clone-"));
|
|
5716
5673
|
const tarPath = path9.join(tmpDir, "archive.tar.gz");
|
|
5717
5674
|
await fs7.promises.writeFile(tarPath, tarBuffer);
|
|
5718
5675
|
const files = await listTarFiles(tarPath);
|
|
5719
|
-
console.log(
|
|
5676
|
+
console.log(chalk12.dim("Extracting files..."));
|
|
5720
5677
|
await tar4.extract({
|
|
5721
5678
|
file: tarPath,
|
|
5722
5679
|
cwd: destination,
|
|
@@ -5724,9 +5681,9 @@ async function cloneStorage(name, type, destination, options = {}) {
|
|
|
5724
5681
|
});
|
|
5725
5682
|
await fs7.promises.unlink(tarPath);
|
|
5726
5683
|
await fs7.promises.rmdir(tmpDir);
|
|
5727
|
-
console.log(
|
|
5684
|
+
console.log(chalk12.green(`\u2713 Extracted ${files.length} files`));
|
|
5728
5685
|
await writeStorageConfig(name, destination, type);
|
|
5729
|
-
console.log(
|
|
5686
|
+
console.log(chalk12.green(`\u2713 Initialized .vm0/storage.yaml`));
|
|
5730
5687
|
return {
|
|
5731
5688
|
success: true,
|
|
5732
5689
|
fileCount: downloadInfo.fileCount,
|
|
@@ -5741,17 +5698,17 @@ var cloneCommand = new Command8().name("clone").description("Clone a remote volu
|
|
|
5741
5698
|
const targetDir = destination || name;
|
|
5742
5699
|
console.log(`Cloning volume: ${name}`);
|
|
5743
5700
|
const result = await cloneStorage(name, "volume", targetDir);
|
|
5744
|
-
console.log(
|
|
5701
|
+
console.log(chalk13.green(`
|
|
5745
5702
|
\u2713 Successfully cloned volume: ${name}`));
|
|
5746
|
-
console.log(
|
|
5747
|
-
console.log(
|
|
5703
|
+
console.log(chalk13.dim(` Location: ${targetDir}/`));
|
|
5704
|
+
console.log(chalk13.dim(` Version: ${result.versionId.slice(0, 8)}`));
|
|
5748
5705
|
} catch (error) {
|
|
5749
|
-
console.error(
|
|
5706
|
+
console.error(chalk13.red("\u2717 Clone failed"));
|
|
5750
5707
|
if (error instanceof Error) {
|
|
5751
5708
|
if (error.message.includes("Not authenticated")) {
|
|
5752
|
-
console.error(
|
|
5709
|
+
console.error(chalk13.dim(" Run: vm0 auth login"));
|
|
5753
5710
|
} else {
|
|
5754
|
-
console.error(
|
|
5711
|
+
console.error(chalk13.dim(` ${error.message}`));
|
|
5755
5712
|
}
|
|
5756
5713
|
}
|
|
5757
5714
|
process.exit(1);
|
|
@@ -5766,7 +5723,7 @@ import { Command as Command16 } from "commander";
|
|
|
5766
5723
|
|
|
5767
5724
|
// src/commands/artifact/init.ts
|
|
5768
5725
|
import { Command as Command10 } from "commander";
|
|
5769
|
-
import
|
|
5726
|
+
import chalk14 from "chalk";
|
|
5770
5727
|
import path10 from "path";
|
|
5771
5728
|
var initCommand2 = new Command10().name("init").description("Initialize an artifact in the current directory").option(
|
|
5772
5729
|
"-n, --name <name>",
|
|
@@ -5779,24 +5736,24 @@ var initCommand2 = new Command10().name("init").description("Initialize an artif
|
|
|
5779
5736
|
if (existingConfig) {
|
|
5780
5737
|
if (existingConfig.type === "artifact") {
|
|
5781
5738
|
console.log(
|
|
5782
|
-
|
|
5739
|
+
chalk14.yellow(
|
|
5783
5740
|
`Artifact already initialized: ${existingConfig.name}`
|
|
5784
5741
|
)
|
|
5785
5742
|
);
|
|
5786
5743
|
} else {
|
|
5787
5744
|
console.log(
|
|
5788
|
-
|
|
5745
|
+
chalk14.yellow(
|
|
5789
5746
|
`Directory already initialized as volume: ${existingConfig.name}`
|
|
5790
5747
|
)
|
|
5791
5748
|
);
|
|
5792
5749
|
console.log(
|
|
5793
|
-
|
|
5750
|
+
chalk14.dim(
|
|
5794
5751
|
" To change type, delete .vm0/storage.yaml and reinitialize"
|
|
5795
5752
|
)
|
|
5796
5753
|
);
|
|
5797
5754
|
}
|
|
5798
5755
|
console.log(
|
|
5799
|
-
|
|
5756
|
+
chalk14.dim(`Config file: ${path10.join(cwd, ".vm0", "storage.yaml")}`)
|
|
5800
5757
|
);
|
|
5801
5758
|
return;
|
|
5802
5759
|
}
|
|
@@ -5805,10 +5762,10 @@ var initCommand2 = new Command10().name("init").description("Initialize an artif
|
|
|
5805
5762
|
artifactName = options.name;
|
|
5806
5763
|
} else if (!isInteractive()) {
|
|
5807
5764
|
console.error(
|
|
5808
|
-
|
|
5765
|
+
chalk14.red("\u2717 --name flag is required in non-interactive mode")
|
|
5809
5766
|
);
|
|
5810
5767
|
console.error(
|
|
5811
|
-
|
|
5768
|
+
chalk14.dim(" Usage: vm0 artifact init --name <artifact-name>")
|
|
5812
5769
|
);
|
|
5813
5770
|
process.exit(1);
|
|
5814
5771
|
} else {
|
|
@@ -5824,34 +5781,34 @@ var initCommand2 = new Command10().name("init").description("Initialize an artif
|
|
|
5824
5781
|
}
|
|
5825
5782
|
);
|
|
5826
5783
|
if (name === void 0) {
|
|
5827
|
-
console.log(
|
|
5784
|
+
console.log(chalk14.dim("Cancelled"));
|
|
5828
5785
|
return;
|
|
5829
5786
|
}
|
|
5830
5787
|
artifactName = name;
|
|
5831
5788
|
}
|
|
5832
5789
|
if (!isValidStorageName(artifactName)) {
|
|
5833
|
-
console.error(
|
|
5790
|
+
console.error(chalk14.red(`\u2717 Invalid artifact name: "${artifactName}"`));
|
|
5834
5791
|
console.error(
|
|
5835
|
-
|
|
5792
|
+
chalk14.dim(
|
|
5836
5793
|
" Artifact names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
5837
5794
|
)
|
|
5838
5795
|
);
|
|
5839
5796
|
console.error(
|
|
5840
|
-
|
|
5797
|
+
chalk14.dim(" Example: my-project, user-workspace, code-artifact")
|
|
5841
5798
|
);
|
|
5842
5799
|
process.exit(1);
|
|
5843
5800
|
}
|
|
5844
5801
|
await writeStorageConfig(artifactName, cwd, "artifact");
|
|
5845
|
-
console.log(
|
|
5802
|
+
console.log(chalk14.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
5846
5803
|
console.log(
|
|
5847
|
-
|
|
5804
|
+
chalk14.dim(
|
|
5848
5805
|
`\u2713 Config saved to ${path10.join(cwd, ".vm0", "storage.yaml")}`
|
|
5849
5806
|
)
|
|
5850
5807
|
);
|
|
5851
5808
|
} catch (error) {
|
|
5852
|
-
console.error(
|
|
5809
|
+
console.error(chalk14.red("\u2717 Failed to initialize artifact"));
|
|
5853
5810
|
if (error instanceof Error) {
|
|
5854
|
-
console.error(
|
|
5811
|
+
console.error(chalk14.dim(` ${error.message}`));
|
|
5855
5812
|
}
|
|
5856
5813
|
process.exit(1);
|
|
5857
5814
|
}
|
|
@@ -5859,7 +5816,7 @@ var initCommand2 = new Command10().name("init").description("Initialize an artif
|
|
|
5859
5816
|
|
|
5860
5817
|
// src/commands/artifact/push.ts
|
|
5861
5818
|
import { Command as Command11 } from "commander";
|
|
5862
|
-
import
|
|
5819
|
+
import chalk15 from "chalk";
|
|
5863
5820
|
function formatBytes5(bytes) {
|
|
5864
5821
|
if (bytes === 0) return "0 B";
|
|
5865
5822
|
const k = 1024;
|
|
@@ -5875,41 +5832,41 @@ var pushCommand2 = new Command11().name("push").description("Push local files to
|
|
|
5875
5832
|
const cwd = process.cwd();
|
|
5876
5833
|
const config = await readStorageConfig(cwd);
|
|
5877
5834
|
if (!config) {
|
|
5878
|
-
console.error(
|
|
5879
|
-
console.error(
|
|
5835
|
+
console.error(chalk15.red("\u2717 No artifact initialized in this directory"));
|
|
5836
|
+
console.error(chalk15.dim(" Run: vm0 artifact init"));
|
|
5880
5837
|
process.exit(1);
|
|
5881
5838
|
}
|
|
5882
5839
|
if (config.type !== "artifact") {
|
|
5883
5840
|
console.error(
|
|
5884
|
-
|
|
5841
|
+
chalk15.red(
|
|
5885
5842
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
5886
5843
|
)
|
|
5887
5844
|
);
|
|
5888
|
-
console.error(
|
|
5845
|
+
console.error(chalk15.dim(" Use: vm0 volume push"));
|
|
5889
5846
|
process.exit(1);
|
|
5890
5847
|
}
|
|
5891
5848
|
console.log(`Pushing artifact: ${config.name}`);
|
|
5892
5849
|
const result = await directUpload(config.name, "artifact", cwd, {
|
|
5893
5850
|
onProgress: (message) => {
|
|
5894
|
-
console.log(
|
|
5851
|
+
console.log(chalk15.dim(message));
|
|
5895
5852
|
},
|
|
5896
5853
|
force: options.force
|
|
5897
5854
|
});
|
|
5898
5855
|
const shortVersion = result.versionId.slice(0, 8);
|
|
5899
5856
|
if (result.empty) {
|
|
5900
|
-
console.log(
|
|
5857
|
+
console.log(chalk15.yellow("No files found (empty artifact)"));
|
|
5901
5858
|
} else if (result.deduplicated) {
|
|
5902
|
-
console.log(
|
|
5859
|
+
console.log(chalk15.green("\u2713 Content unchanged (deduplicated)"));
|
|
5903
5860
|
} else {
|
|
5904
|
-
console.log(
|
|
5861
|
+
console.log(chalk15.green("\u2713 Upload complete"));
|
|
5905
5862
|
}
|
|
5906
|
-
console.log(
|
|
5907
|
-
console.log(
|
|
5908
|
-
console.log(
|
|
5863
|
+
console.log(chalk15.dim(` Version: ${shortVersion}`));
|
|
5864
|
+
console.log(chalk15.dim(` Files: ${result.fileCount.toLocaleString()}`));
|
|
5865
|
+
console.log(chalk15.dim(` Size: ${formatBytes5(result.size)}`));
|
|
5909
5866
|
} catch (error) {
|
|
5910
|
-
console.error(
|
|
5867
|
+
console.error(chalk15.red("\u2717 Push failed"));
|
|
5911
5868
|
if (error instanceof Error) {
|
|
5912
|
-
console.error(
|
|
5869
|
+
console.error(chalk15.dim(` ${error.message}`));
|
|
5913
5870
|
}
|
|
5914
5871
|
process.exit(1);
|
|
5915
5872
|
}
|
|
@@ -5917,7 +5874,7 @@ var pushCommand2 = new Command11().name("push").description("Push local files to
|
|
|
5917
5874
|
|
|
5918
5875
|
// src/commands/artifact/pull.ts
|
|
5919
5876
|
import { Command as Command12 } from "commander";
|
|
5920
|
-
import
|
|
5877
|
+
import chalk16 from "chalk";
|
|
5921
5878
|
import path11 from "path";
|
|
5922
5879
|
import * as fs8 from "fs";
|
|
5923
5880
|
import * as os6 from "os";
|
|
@@ -5934,17 +5891,17 @@ var pullCommand2 = new Command12().name("pull").description("Pull cloud artifact
|
|
|
5934
5891
|
const cwd = process.cwd();
|
|
5935
5892
|
const config = await readStorageConfig(cwd);
|
|
5936
5893
|
if (!config) {
|
|
5937
|
-
console.error(
|
|
5938
|
-
console.error(
|
|
5894
|
+
console.error(chalk16.red("\u2717 No artifact initialized in this directory"));
|
|
5895
|
+
console.error(chalk16.dim(" Run: vm0 artifact init"));
|
|
5939
5896
|
process.exit(1);
|
|
5940
5897
|
}
|
|
5941
5898
|
if (config.type !== "artifact") {
|
|
5942
5899
|
console.error(
|
|
5943
|
-
|
|
5900
|
+
chalk16.red(
|
|
5944
5901
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
5945
5902
|
)
|
|
5946
5903
|
);
|
|
5947
|
-
console.error(
|
|
5904
|
+
console.error(chalk16.dim(" Use: vm0 volume pull"));
|
|
5948
5905
|
process.exit(1);
|
|
5949
5906
|
}
|
|
5950
5907
|
if (versionId) {
|
|
@@ -5952,7 +5909,7 @@ var pullCommand2 = new Command12().name("pull").description("Pull cloud artifact
|
|
|
5952
5909
|
} else {
|
|
5953
5910
|
console.log(`Pulling artifact: ${config.name}`);
|
|
5954
5911
|
}
|
|
5955
|
-
console.log(
|
|
5912
|
+
console.log(chalk16.dim("Getting download URL..."));
|
|
5956
5913
|
let url = `/api/storages/download?name=${encodeURIComponent(config.name)}&type=artifact`;
|
|
5957
5914
|
if (versionId) {
|
|
5958
5915
|
const quotedVersion = JSON.stringify(versionId);
|
|
@@ -5961,14 +5918,14 @@ var pullCommand2 = new Command12().name("pull").description("Pull cloud artifact
|
|
|
5961
5918
|
const response = await apiClient.get(url);
|
|
5962
5919
|
if (!response.ok) {
|
|
5963
5920
|
if (response.status === 404) {
|
|
5964
|
-
console.error(
|
|
5921
|
+
console.error(chalk16.red(`\u2717 Artifact "${config.name}" not found`));
|
|
5965
5922
|
console.error(
|
|
5966
|
-
|
|
5923
|
+
chalk16.dim(
|
|
5967
5924
|
" Make sure the artifact name is correct in .vm0/storage.yaml"
|
|
5968
5925
|
)
|
|
5969
5926
|
);
|
|
5970
5927
|
console.error(
|
|
5971
|
-
|
|
5928
|
+
chalk16.dim(" Or push the artifact first with: vm0 artifact push")
|
|
5972
5929
|
);
|
|
5973
5930
|
} else {
|
|
5974
5931
|
const error = await response.json();
|
|
@@ -5984,18 +5941,18 @@ var pullCommand2 = new Command12().name("pull").description("Pull cloud artifact
|
|
|
5984
5941
|
if (!downloadInfo.url) {
|
|
5985
5942
|
throw new Error("No download URL returned");
|
|
5986
5943
|
}
|
|
5987
|
-
console.log(
|
|
5944
|
+
console.log(chalk16.dim("Downloading from S3..."));
|
|
5988
5945
|
const s3Response = await fetch(downloadInfo.url);
|
|
5989
5946
|
if (!s3Response.ok) {
|
|
5990
5947
|
throw new Error(`S3 download failed: ${s3Response.status}`);
|
|
5991
5948
|
}
|
|
5992
5949
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
5993
5950
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
5994
|
-
console.log(
|
|
5951
|
+
console.log(chalk16.green(`\u2713 Downloaded ${formatBytes6(tarBuffer.length)}`));
|
|
5995
5952
|
const tmpDir = fs8.mkdtempSync(path11.join(os6.tmpdir(), "vm0-"));
|
|
5996
5953
|
const tarPath = path11.join(tmpDir, "artifact.tar.gz");
|
|
5997
5954
|
await fs8.promises.writeFile(tarPath, tarBuffer);
|
|
5998
|
-
console.log(
|
|
5955
|
+
console.log(chalk16.dim("Syncing local files..."));
|
|
5999
5956
|
const remoteFiles = await listTarFiles(tarPath);
|
|
6000
5957
|
const remoteFilesSet = new Set(
|
|
6001
5958
|
remoteFiles.map((f) => f.replace(/\\/g, "/"))
|
|
@@ -6003,10 +5960,10 @@ var pullCommand2 = new Command12().name("pull").description("Pull cloud artifact
|
|
|
6003
5960
|
const removedCount = await removeExtraFiles(cwd, remoteFilesSet);
|
|
6004
5961
|
if (removedCount > 0) {
|
|
6005
5962
|
console.log(
|
|
6006
|
-
|
|
5963
|
+
chalk16.green(`\u2713 Removed ${removedCount} files not in remote`)
|
|
6007
5964
|
);
|
|
6008
5965
|
}
|
|
6009
|
-
console.log(
|
|
5966
|
+
console.log(chalk16.dim("Extracting files..."));
|
|
6010
5967
|
await tar5.extract({
|
|
6011
5968
|
file: tarPath,
|
|
6012
5969
|
cwd,
|
|
@@ -6014,11 +5971,11 @@ var pullCommand2 = new Command12().name("pull").description("Pull cloud artifact
|
|
|
6014
5971
|
});
|
|
6015
5972
|
await fs8.promises.unlink(tarPath);
|
|
6016
5973
|
await fs8.promises.rmdir(tmpDir);
|
|
6017
|
-
console.log(
|
|
5974
|
+
console.log(chalk16.green(`\u2713 Extracted ${remoteFiles.length} files`));
|
|
6018
5975
|
} catch (error) {
|
|
6019
|
-
console.error(
|
|
5976
|
+
console.error(chalk16.red("\u2717 Pull failed"));
|
|
6020
5977
|
if (error instanceof Error) {
|
|
6021
|
-
console.error(
|
|
5978
|
+
console.error(chalk16.dim(` ${error.message}`));
|
|
6022
5979
|
}
|
|
6023
5980
|
process.exit(1);
|
|
6024
5981
|
}
|
|
@@ -6026,7 +5983,7 @@ var pullCommand2 = new Command12().name("pull").description("Pull cloud artifact
|
|
|
6026
5983
|
|
|
6027
5984
|
// src/commands/artifact/status.ts
|
|
6028
5985
|
import { Command as Command13 } from "commander";
|
|
6029
|
-
import
|
|
5986
|
+
import chalk17 from "chalk";
|
|
6030
5987
|
function formatBytes7(bytes) {
|
|
6031
5988
|
if (bytes === 0) return "0 B";
|
|
6032
5989
|
const k = 1024;
|
|
@@ -6039,17 +5996,17 @@ var statusCommand2 = new Command13().name("status").description("Show status of
|
|
|
6039
5996
|
const cwd = process.cwd();
|
|
6040
5997
|
const config = await readStorageConfig(cwd);
|
|
6041
5998
|
if (!config) {
|
|
6042
|
-
console.error(
|
|
6043
|
-
console.error(
|
|
5999
|
+
console.error(chalk17.red("\u2717 No artifact initialized in this directory"));
|
|
6000
|
+
console.error(chalk17.dim(" Run: vm0 artifact init"));
|
|
6044
6001
|
process.exit(1);
|
|
6045
6002
|
}
|
|
6046
6003
|
if (config.type !== "artifact") {
|
|
6047
6004
|
console.error(
|
|
6048
|
-
|
|
6005
|
+
chalk17.red(
|
|
6049
6006
|
"\u2717 This directory is initialized as a volume, not an artifact"
|
|
6050
6007
|
)
|
|
6051
6008
|
);
|
|
6052
|
-
console.error(
|
|
6009
|
+
console.error(chalk17.dim(" Use: vm0 volume status"));
|
|
6053
6010
|
process.exit(1);
|
|
6054
6011
|
}
|
|
6055
6012
|
console.log(`Checking artifact: ${config.name}`);
|
|
@@ -6057,8 +6014,8 @@ var statusCommand2 = new Command13().name("status").description("Show status of
|
|
|
6057
6014
|
const response = await apiClient.get(url);
|
|
6058
6015
|
if (!response.ok) {
|
|
6059
6016
|
if (response.status === 404) {
|
|
6060
|
-
console.error(
|
|
6061
|
-
console.error(
|
|
6017
|
+
console.error(chalk17.red("\u2717 Not found on remote"));
|
|
6018
|
+
console.error(chalk17.dim(" Run: vm0 artifact push"));
|
|
6062
6019
|
} else {
|
|
6063
6020
|
const error = await response.json();
|
|
6064
6021
|
throw new Error(error.error?.message || "Status check failed");
|
|
@@ -6068,18 +6025,18 @@ var statusCommand2 = new Command13().name("status").description("Show status of
|
|
|
6068
6025
|
const info = await response.json();
|
|
6069
6026
|
const shortVersion = info.versionId.slice(0, 8);
|
|
6070
6027
|
if (info.empty) {
|
|
6071
|
-
console.log(
|
|
6072
|
-
console.log(
|
|
6028
|
+
console.log(chalk17.green("\u2713 Found (empty)"));
|
|
6029
|
+
console.log(chalk17.dim(` Version: ${shortVersion}`));
|
|
6073
6030
|
} else {
|
|
6074
|
-
console.log(
|
|
6075
|
-
console.log(
|
|
6076
|
-
console.log(
|
|
6077
|
-
console.log(
|
|
6031
|
+
console.log(chalk17.green("\u2713 Found"));
|
|
6032
|
+
console.log(chalk17.dim(` Version: ${shortVersion}`));
|
|
6033
|
+
console.log(chalk17.dim(` Files: ${info.fileCount.toLocaleString()}`));
|
|
6034
|
+
console.log(chalk17.dim(` Size: ${formatBytes7(info.size)}`));
|
|
6078
6035
|
}
|
|
6079
6036
|
} catch (error) {
|
|
6080
|
-
console.error(
|
|
6037
|
+
console.error(chalk17.red("\u2717 Status check failed"));
|
|
6081
6038
|
if (error instanceof Error) {
|
|
6082
|
-
console.error(
|
|
6039
|
+
console.error(chalk17.dim(` ${error.message}`));
|
|
6083
6040
|
}
|
|
6084
6041
|
process.exit(1);
|
|
6085
6042
|
}
|
|
@@ -6087,7 +6044,7 @@ var statusCommand2 = new Command13().name("status").description("Show status of
|
|
|
6087
6044
|
|
|
6088
6045
|
// src/commands/artifact/list.ts
|
|
6089
6046
|
import { Command as Command14 } from "commander";
|
|
6090
|
-
import
|
|
6047
|
+
import chalk18 from "chalk";
|
|
6091
6048
|
var listCommand2 = new Command14().name("list").alias("ls").description("List all remote artifacts").action(async () => {
|
|
6092
6049
|
try {
|
|
6093
6050
|
const url = "/api/storages/list?type=artifact";
|
|
@@ -6098,9 +6055,9 @@ var listCommand2 = new Command14().name("list").alias("ls").description("List al
|
|
|
6098
6055
|
}
|
|
6099
6056
|
const items = await response.json();
|
|
6100
6057
|
if (items.length === 0) {
|
|
6101
|
-
console.log(
|
|
6058
|
+
console.log(chalk18.dim("No artifacts found"));
|
|
6102
6059
|
console.log(
|
|
6103
|
-
|
|
6060
|
+
chalk18.dim(
|
|
6104
6061
|
" Create one with: vm0 artifact init && vm0 artifact push"
|
|
6105
6062
|
)
|
|
6106
6063
|
);
|
|
@@ -6121,7 +6078,7 @@ var listCommand2 = new Command14().name("list").alias("ls").description("List al
|
|
|
6121
6078
|
"FILES".padStart(filesWidth),
|
|
6122
6079
|
"UPDATED"
|
|
6123
6080
|
].join(" ");
|
|
6124
|
-
console.log(
|
|
6081
|
+
console.log(chalk18.dim(header));
|
|
6125
6082
|
for (const item of items) {
|
|
6126
6083
|
const row = [
|
|
6127
6084
|
item.name.padEnd(nameWidth),
|
|
@@ -6132,12 +6089,12 @@ var listCommand2 = new Command14().name("list").alias("ls").description("List al
|
|
|
6132
6089
|
console.log(row);
|
|
6133
6090
|
}
|
|
6134
6091
|
} catch (error) {
|
|
6135
|
-
console.error(
|
|
6092
|
+
console.error(chalk18.red("\u2717 Failed to list artifacts"));
|
|
6136
6093
|
if (error instanceof Error) {
|
|
6137
6094
|
if (error.message.includes("Not authenticated")) {
|
|
6138
|
-
console.error(
|
|
6095
|
+
console.error(chalk18.dim(" Run: vm0 auth login"));
|
|
6139
6096
|
} else {
|
|
6140
|
-
console.error(
|
|
6097
|
+
console.error(chalk18.dim(` ${error.message}`));
|
|
6141
6098
|
}
|
|
6142
6099
|
}
|
|
6143
6100
|
process.exit(1);
|
|
@@ -6146,23 +6103,23 @@ var listCommand2 = new Command14().name("list").alias("ls").description("List al
|
|
|
6146
6103
|
|
|
6147
6104
|
// src/commands/artifact/clone.ts
|
|
6148
6105
|
import { Command as Command15 } from "commander";
|
|
6149
|
-
import
|
|
6106
|
+
import chalk19 from "chalk";
|
|
6150
6107
|
var cloneCommand2 = new Command15().name("clone").description("Clone a remote artifact to local directory (latest version)").argument("<name>", "Artifact name to clone").argument("[destination]", "Destination directory (default: artifact name)").action(async (name, destination) => {
|
|
6151
6108
|
try {
|
|
6152
6109
|
const targetDir = destination || name;
|
|
6153
6110
|
console.log(`Cloning artifact: ${name}`);
|
|
6154
6111
|
const result = await cloneStorage(name, "artifact", targetDir);
|
|
6155
|
-
console.log(
|
|
6112
|
+
console.log(chalk19.green(`
|
|
6156
6113
|
\u2713 Successfully cloned artifact: ${name}`));
|
|
6157
|
-
console.log(
|
|
6158
|
-
console.log(
|
|
6114
|
+
console.log(chalk19.dim(` Location: ${targetDir}/`));
|
|
6115
|
+
console.log(chalk19.dim(` Version: ${result.versionId.slice(0, 8)}`));
|
|
6159
6116
|
} catch (error) {
|
|
6160
|
-
console.error(
|
|
6117
|
+
console.error(chalk19.red("\u2717 Clone failed"));
|
|
6161
6118
|
if (error instanceof Error) {
|
|
6162
6119
|
if (error.message.includes("Not authenticated")) {
|
|
6163
|
-
console.error(
|
|
6120
|
+
console.error(chalk19.dim(" Run: vm0 auth login"));
|
|
6164
6121
|
} else {
|
|
6165
|
-
console.error(
|
|
6122
|
+
console.error(chalk19.dim(` ${error.message}`));
|
|
6166
6123
|
}
|
|
6167
6124
|
}
|
|
6168
6125
|
process.exit(1);
|
|
@@ -6174,7 +6131,7 @@ var artifactCommand = new Command16().name("artifact").description("Manage cloud
|
|
|
6174
6131
|
|
|
6175
6132
|
// src/commands/cook.ts
|
|
6176
6133
|
import { Command as Command17 } from "commander";
|
|
6177
|
-
import
|
|
6134
|
+
import chalk21 from "chalk";
|
|
6178
6135
|
import { readFile as readFile7, mkdir as mkdir6, writeFile as writeFile6, appendFile } from "fs/promises";
|
|
6179
6136
|
import { existsSync as existsSync8, readFileSync } from "fs";
|
|
6180
6137
|
import path12 from "path";
|
|
@@ -6185,7 +6142,7 @@ import { config as dotenvConfig2 } from "dotenv";
|
|
|
6185
6142
|
// src/lib/utils/update-checker.ts
|
|
6186
6143
|
import https from "https";
|
|
6187
6144
|
import { spawn } from "child_process";
|
|
6188
|
-
import
|
|
6145
|
+
import chalk20 from "chalk";
|
|
6189
6146
|
var PACKAGE_NAME = "@vm0/cli";
|
|
6190
6147
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`;
|
|
6191
6148
|
var TIMEOUT_MS = 5e3;
|
|
@@ -6250,21 +6207,21 @@ function performUpgrade(packageManager) {
|
|
|
6250
6207
|
async function checkAndUpgrade(currentVersion, prompt) {
|
|
6251
6208
|
const latestVersion = await getLatestVersion();
|
|
6252
6209
|
if (latestVersion === null) {
|
|
6253
|
-
console.log(
|
|
6210
|
+
console.log(chalk20.yellow("Warning: Could not check for updates"));
|
|
6254
6211
|
console.log();
|
|
6255
6212
|
return false;
|
|
6256
6213
|
}
|
|
6257
6214
|
if (latestVersion === currentVersion) {
|
|
6258
6215
|
return false;
|
|
6259
6216
|
}
|
|
6260
|
-
console.log(
|
|
6217
|
+
console.log(chalk20.yellow("vm0 is currently in Early Access (EA)."));
|
|
6261
6218
|
console.log(
|
|
6262
|
-
|
|
6219
|
+
chalk20.yellow(
|
|
6263
6220
|
`Current version: ${currentVersion} -> Latest version: ${latestVersion}`
|
|
6264
6221
|
)
|
|
6265
6222
|
);
|
|
6266
6223
|
console.log(
|
|
6267
|
-
|
|
6224
|
+
chalk20.yellow(
|
|
6268
6225
|
"Please always use the latest version for best compatibility."
|
|
6269
6226
|
)
|
|
6270
6227
|
);
|
|
@@ -6273,20 +6230,20 @@ async function checkAndUpgrade(currentVersion, prompt) {
|
|
|
6273
6230
|
console.log(`Upgrading via ${packageManager}...`);
|
|
6274
6231
|
const success = await performUpgrade(packageManager);
|
|
6275
6232
|
if (success) {
|
|
6276
|
-
console.log(
|
|
6233
|
+
console.log(chalk20.green(`Upgraded to ${latestVersion}`));
|
|
6277
6234
|
console.log();
|
|
6278
6235
|
console.log("To continue, run:");
|
|
6279
|
-
console.log(
|
|
6236
|
+
console.log(chalk20.cyan(` ${buildRerunCommand(prompt)}`));
|
|
6280
6237
|
return true;
|
|
6281
6238
|
}
|
|
6282
6239
|
console.log();
|
|
6283
|
-
console.log(
|
|
6284
|
-
console.log(
|
|
6285
|
-
console.log(
|
|
6286
|
-
console.log(
|
|
6240
|
+
console.log(chalk20.red("Upgrade failed. Please run manually:"));
|
|
6241
|
+
console.log(chalk20.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
6242
|
+
console.log(chalk20.dim(" # or"));
|
|
6243
|
+
console.log(chalk20.cyan(` pnpm add -g ${PACKAGE_NAME}@latest`));
|
|
6287
6244
|
console.log();
|
|
6288
6245
|
console.log("Then re-run:");
|
|
6289
|
-
console.log(
|
|
6246
|
+
console.log(chalk20.cyan(` ${buildRerunCommand(prompt)}`));
|
|
6290
6247
|
return true;
|
|
6291
6248
|
}
|
|
6292
6249
|
|
|
@@ -6359,7 +6316,7 @@ async function saveCookState(state) {
|
|
|
6359
6316
|
var CONFIG_FILE3 = "vm0.yaml";
|
|
6360
6317
|
var ARTIFACT_DIR = "artifact";
|
|
6361
6318
|
function printCommand(cmd) {
|
|
6362
|
-
console.log(
|
|
6319
|
+
console.log(chalk21.dim(`> ${cmd}`));
|
|
6363
6320
|
}
|
|
6364
6321
|
function execVm0Command(args, options = {}) {
|
|
6365
6322
|
return new Promise((resolve2, reject) => {
|
|
@@ -6496,7 +6453,7 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
6496
6453
|
);
|
|
6497
6454
|
if (serverVersion && existsSync8(artifactDir)) {
|
|
6498
6455
|
console.log();
|
|
6499
|
-
console.log(
|
|
6456
|
+
console.log(chalk21.bold("Pulling updated artifact:"));
|
|
6500
6457
|
printCommand(`cd ${ARTIFACT_DIR}`);
|
|
6501
6458
|
printCommand(`vm0 artifact pull ${serverVersion}`);
|
|
6502
6459
|
try {
|
|
@@ -6506,23 +6463,23 @@ async function autoPullArtifact(runOutput, artifactDir) {
|
|
|
6506
6463
|
});
|
|
6507
6464
|
printCommand("cd ..");
|
|
6508
6465
|
} catch (error) {
|
|
6509
|
-
console.error(
|
|
6466
|
+
console.error(chalk21.red(`\u2717 Artifact pull failed`));
|
|
6510
6467
|
if (error instanceof Error) {
|
|
6511
|
-
console.error(
|
|
6468
|
+
console.error(chalk21.dim(` ${error.message}`));
|
|
6512
6469
|
}
|
|
6513
6470
|
}
|
|
6514
6471
|
}
|
|
6515
6472
|
}
|
|
6516
6473
|
var cookCmd = new Command17().name("cook").description("One-click agent preparation and execution from vm0.yaml");
|
|
6517
6474
|
cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip confirmation prompts").action(async (prompt, options) => {
|
|
6518
|
-
const shouldExit = await checkAndUpgrade("5.
|
|
6475
|
+
const shouldExit = await checkAndUpgrade("5.7.0", prompt);
|
|
6519
6476
|
if (shouldExit) {
|
|
6520
6477
|
process.exit(0);
|
|
6521
6478
|
}
|
|
6522
6479
|
const cwd = process.cwd();
|
|
6523
|
-
console.log(
|
|
6480
|
+
console.log(chalk21.bold(`Reading config: ${CONFIG_FILE3}`));
|
|
6524
6481
|
if (!existsSync8(CONFIG_FILE3)) {
|
|
6525
|
-
console.error(
|
|
6482
|
+
console.error(chalk21.red(`\u2717 Config file not found: ${CONFIG_FILE3}`));
|
|
6526
6483
|
process.exit(1);
|
|
6527
6484
|
}
|
|
6528
6485
|
let config;
|
|
@@ -6530,22 +6487,22 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
|
|
|
6530
6487
|
const content = await readFile7(CONFIG_FILE3, "utf8");
|
|
6531
6488
|
config = parseYaml4(content);
|
|
6532
6489
|
} catch (error) {
|
|
6533
|
-
console.error(
|
|
6490
|
+
console.error(chalk21.red("\u2717 Invalid YAML format"));
|
|
6534
6491
|
if (error instanceof Error) {
|
|
6535
|
-
console.error(
|
|
6492
|
+
console.error(chalk21.dim(` ${error.message}`));
|
|
6536
6493
|
}
|
|
6537
6494
|
process.exit(1);
|
|
6538
6495
|
}
|
|
6539
6496
|
const validation = validateAgentCompose(config);
|
|
6540
6497
|
if (!validation.valid) {
|
|
6541
|
-
console.error(
|
|
6498
|
+
console.error(chalk21.red(`\u2717 ${validation.error}`));
|
|
6542
6499
|
process.exit(1);
|
|
6543
6500
|
}
|
|
6544
6501
|
const agentNames = Object.keys(config.agents);
|
|
6545
6502
|
const agentName = agentNames[0];
|
|
6546
6503
|
const volumeCount = config.volumes ? Object.keys(config.volumes).length : 0;
|
|
6547
6504
|
console.log(
|
|
6548
|
-
|
|
6505
|
+
chalk21.green(`\u2713 Config validated: 1 agent, ${volumeCount} volume(s)`)
|
|
6549
6506
|
);
|
|
6550
6507
|
const requiredVarNames = extractRequiredVarNames(config);
|
|
6551
6508
|
if (requiredVarNames.length > 0) {
|
|
@@ -6555,24 +6512,24 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
|
|
|
6555
6512
|
await generateEnvPlaceholders(missingVars, envFilePath);
|
|
6556
6513
|
console.log();
|
|
6557
6514
|
console.log(
|
|
6558
|
-
|
|
6515
|
+
chalk21.yellow(
|
|
6559
6516
|
`\u26A0 Missing environment variables. Please fill in values in .env file:`
|
|
6560
6517
|
)
|
|
6561
6518
|
);
|
|
6562
6519
|
for (const varName of missingVars) {
|
|
6563
|
-
console.log(
|
|
6520
|
+
console.log(chalk21.yellow(` ${varName}`));
|
|
6564
6521
|
}
|
|
6565
6522
|
process.exit(1);
|
|
6566
6523
|
}
|
|
6567
6524
|
}
|
|
6568
6525
|
if (config.volumes && Object.keys(config.volumes).length > 0) {
|
|
6569
6526
|
console.log();
|
|
6570
|
-
console.log(
|
|
6527
|
+
console.log(chalk21.bold("Processing volumes:"));
|
|
6571
6528
|
for (const volumeConfig of Object.values(config.volumes)) {
|
|
6572
6529
|
const volumeDir = path12.join(cwd, volumeConfig.name);
|
|
6573
6530
|
if (!existsSync8(volumeDir)) {
|
|
6574
6531
|
console.error(
|
|
6575
|
-
|
|
6532
|
+
chalk21.red(
|
|
6576
6533
|
`\u2717 Directory not found: ${volumeConfig.name}. Create the directory and add files first.`
|
|
6577
6534
|
)
|
|
6578
6535
|
);
|
|
@@ -6598,16 +6555,16 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
|
|
|
6598
6555
|
});
|
|
6599
6556
|
printCommand("cd ..");
|
|
6600
6557
|
} catch (error) {
|
|
6601
|
-
console.error(
|
|
6558
|
+
console.error(chalk21.red(`\u2717 Failed`));
|
|
6602
6559
|
if (error instanceof Error) {
|
|
6603
|
-
console.error(
|
|
6560
|
+
console.error(chalk21.dim(` ${error.message}`));
|
|
6604
6561
|
}
|
|
6605
6562
|
process.exit(1);
|
|
6606
6563
|
}
|
|
6607
6564
|
}
|
|
6608
6565
|
}
|
|
6609
6566
|
console.log();
|
|
6610
|
-
console.log(
|
|
6567
|
+
console.log(chalk21.bold("Processing artifact:"));
|
|
6611
6568
|
const artifactDir = path12.join(cwd, ARTIFACT_DIR);
|
|
6612
6569
|
try {
|
|
6613
6570
|
if (!existsSync8(artifactDir)) {
|
|
@@ -6630,14 +6587,14 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
|
|
|
6630
6587
|
});
|
|
6631
6588
|
printCommand("cd ..");
|
|
6632
6589
|
} catch (error) {
|
|
6633
|
-
console.error(
|
|
6590
|
+
console.error(chalk21.red(`\u2717 Failed`));
|
|
6634
6591
|
if (error instanceof Error) {
|
|
6635
|
-
console.error(
|
|
6592
|
+
console.error(chalk21.dim(` ${error.message}`));
|
|
6636
6593
|
}
|
|
6637
6594
|
process.exit(1);
|
|
6638
6595
|
}
|
|
6639
6596
|
console.log();
|
|
6640
|
-
console.log(
|
|
6597
|
+
console.log(chalk21.bold("Composing agent:"));
|
|
6641
6598
|
const composeArgs = options.yes ? ["compose", "--yes", CONFIG_FILE3] : ["compose", CONFIG_FILE3];
|
|
6642
6599
|
printCommand(`vm0 ${composeArgs.join(" ")}`);
|
|
6643
6600
|
try {
|
|
@@ -6645,15 +6602,15 @@ cookCmd.argument("[prompt]", "Prompt for the agent").option("-y, --yes", "Skip c
|
|
|
6645
6602
|
cwd
|
|
6646
6603
|
});
|
|
6647
6604
|
} catch (error) {
|
|
6648
|
-
console.error(
|
|
6605
|
+
console.error(chalk21.red(`\u2717 Compose failed`));
|
|
6649
6606
|
if (error instanceof Error) {
|
|
6650
|
-
console.error(
|
|
6607
|
+
console.error(chalk21.dim(` ${error.message}`));
|
|
6651
6608
|
}
|
|
6652
6609
|
process.exit(1);
|
|
6653
6610
|
}
|
|
6654
6611
|
if (prompt) {
|
|
6655
6612
|
console.log();
|
|
6656
|
-
console.log(
|
|
6613
|
+
console.log(chalk21.bold("Running agent:"));
|
|
6657
6614
|
printCommand(
|
|
6658
6615
|
`vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "${prompt}"`
|
|
6659
6616
|
);
|
|
@@ -6695,8 +6652,8 @@ cookCmd.command("logs").description("View logs from the last cook run").option("
|
|
|
6695
6652
|
async (options) => {
|
|
6696
6653
|
const state = await loadCookState();
|
|
6697
6654
|
if (!state.lastRunId) {
|
|
6698
|
-
console.error(
|
|
6699
|
-
console.error(
|
|
6655
|
+
console.error(chalk21.red("\u2717 No previous run found"));
|
|
6656
|
+
console.error(chalk21.dim(" Run 'vm0 cook <prompt>' first"));
|
|
6700
6657
|
process.exit(1);
|
|
6701
6658
|
}
|
|
6702
6659
|
const args = ["logs", state.lastRunId];
|
|
@@ -6738,8 +6695,8 @@ cookCmd.command("continue").description(
|
|
|
6738
6695
|
).argument("<prompt>", "Prompt for the continued agent").action(async (prompt) => {
|
|
6739
6696
|
const state = await loadCookState();
|
|
6740
6697
|
if (!state.lastSessionId) {
|
|
6741
|
-
console.error(
|
|
6742
|
-
console.error(
|
|
6698
|
+
console.error(chalk21.red("\u2717 No previous session found"));
|
|
6699
|
+
console.error(chalk21.dim(" Run 'vm0 cook <prompt>' first"));
|
|
6743
6700
|
process.exit(1);
|
|
6744
6701
|
}
|
|
6745
6702
|
const cwd = process.cwd();
|
|
@@ -6770,8 +6727,8 @@ cookCmd.command("resume").description(
|
|
|
6770
6727
|
).argument("<prompt>", "Prompt for the resumed agent").action(async (prompt) => {
|
|
6771
6728
|
const state = await loadCookState();
|
|
6772
6729
|
if (!state.lastCheckpointId) {
|
|
6773
|
-
console.error(
|
|
6774
|
-
console.error(
|
|
6730
|
+
console.error(chalk21.red("\u2717 No previous checkpoint found"));
|
|
6731
|
+
console.error(chalk21.dim(" Run 'vm0 cook <prompt>' first"));
|
|
6775
6732
|
process.exit(1);
|
|
6776
6733
|
}
|
|
6777
6734
|
const cwd = process.cwd();
|
|
@@ -6801,7 +6758,7 @@ var cookCommand = cookCmd;
|
|
|
6801
6758
|
|
|
6802
6759
|
// src/commands/logs/index.ts
|
|
6803
6760
|
import { Command as Command18 } from "commander";
|
|
6804
|
-
import
|
|
6761
|
+
import chalk22 from "chalk";
|
|
6805
6762
|
|
|
6806
6763
|
// src/lib/utils/time-parser.ts
|
|
6807
6764
|
function parseTime(timeStr) {
|
|
@@ -6862,36 +6819,36 @@ function formatMetric(metric) {
|
|
|
6862
6819
|
}
|
|
6863
6820
|
function formatNetworkLog(entry) {
|
|
6864
6821
|
if (entry.mode === "sni" || !entry.method) {
|
|
6865
|
-
const actionColor = entry.action === "ALLOW" ?
|
|
6822
|
+
const actionColor = entry.action === "ALLOW" ? chalk22.green : chalk22.red;
|
|
6866
6823
|
const host = entry.host || "unknown";
|
|
6867
6824
|
const port = entry.port || 443;
|
|
6868
|
-
return `[${entry.timestamp}] ${
|
|
6825
|
+
return `[${entry.timestamp}] ${chalk22.cyan("SNI")} ${actionColor(entry.action || "ALLOW")} ${host}:${port} ${chalk22.dim(entry.rule_matched || "")}`;
|
|
6869
6826
|
}
|
|
6870
6827
|
let statusColor;
|
|
6871
6828
|
const status = entry.status || 0;
|
|
6872
6829
|
if (status >= 200 && status < 300) {
|
|
6873
|
-
statusColor =
|
|
6830
|
+
statusColor = chalk22.green;
|
|
6874
6831
|
} else if (status >= 300 && status < 400) {
|
|
6875
|
-
statusColor =
|
|
6832
|
+
statusColor = chalk22.yellow;
|
|
6876
6833
|
} else if (status >= 400) {
|
|
6877
|
-
statusColor =
|
|
6834
|
+
statusColor = chalk22.red;
|
|
6878
6835
|
} else {
|
|
6879
|
-
statusColor =
|
|
6836
|
+
statusColor = chalk22.gray;
|
|
6880
6837
|
}
|
|
6881
6838
|
let latencyColor;
|
|
6882
6839
|
const latencyMs = entry.latency_ms || 0;
|
|
6883
6840
|
if (latencyMs < 500) {
|
|
6884
|
-
latencyColor =
|
|
6841
|
+
latencyColor = chalk22.green;
|
|
6885
6842
|
} else if (latencyMs < 2e3) {
|
|
6886
|
-
latencyColor =
|
|
6843
|
+
latencyColor = chalk22.yellow;
|
|
6887
6844
|
} else {
|
|
6888
|
-
latencyColor =
|
|
6845
|
+
latencyColor = chalk22.red;
|
|
6889
6846
|
}
|
|
6890
6847
|
const method = entry.method || "???";
|
|
6891
6848
|
const requestSize = entry.request_size || 0;
|
|
6892
6849
|
const responseSize = entry.response_size || 0;
|
|
6893
6850
|
const url = entry.url || entry.host || "unknown";
|
|
6894
|
-
return `[${entry.timestamp}] ${method.padEnd(6)} ${statusColor(status)} ${latencyColor(latencyMs + "ms")} ${formatBytes8(requestSize)}/${formatBytes8(responseSize)} ${
|
|
6851
|
+
return `[${entry.timestamp}] ${method.padEnd(6)} ${statusColor(status)} ${latencyColor(latencyMs + "ms")} ${formatBytes8(requestSize)}/${formatBytes8(responseSize)} ${chalk22.dim(url)}`;
|
|
6895
6852
|
}
|
|
6896
6853
|
function renderAgentEvent(event, provider) {
|
|
6897
6854
|
const eventData = event.eventData;
|
|
@@ -6914,7 +6871,7 @@ function getLogType(options) {
|
|
|
6914
6871
|
].filter(Boolean).length;
|
|
6915
6872
|
if (selected > 1) {
|
|
6916
6873
|
console.error(
|
|
6917
|
-
|
|
6874
|
+
chalk22.red(
|
|
6918
6875
|
"Options --agent, --system, --metrics, and --network are mutually exclusive"
|
|
6919
6876
|
)
|
|
6920
6877
|
);
|
|
@@ -6934,7 +6891,7 @@ var logsCommand = new Command18().name("logs").description("View logs for an age
|
|
|
6934
6891
|
const logType = getLogType(options);
|
|
6935
6892
|
if (options.tail !== void 0 && options.head !== void 0) {
|
|
6936
6893
|
console.error(
|
|
6937
|
-
|
|
6894
|
+
chalk22.red("Options --tail and --head are mutually exclusive")
|
|
6938
6895
|
);
|
|
6939
6896
|
process.exit(1);
|
|
6940
6897
|
}
|
|
@@ -6971,7 +6928,7 @@ var logsCommand = new Command18().name("logs").description("View logs for an age
|
|
|
6971
6928
|
async function showAgentEvents(runId, options) {
|
|
6972
6929
|
const response = await apiClient.getAgentEvents(runId, options);
|
|
6973
6930
|
if (response.events.length === 0) {
|
|
6974
|
-
console.log(
|
|
6931
|
+
console.log(chalk22.yellow("No agent events found for this run."));
|
|
6975
6932
|
return;
|
|
6976
6933
|
}
|
|
6977
6934
|
const events = options.order === "desc" ? [...response.events].reverse() : response.events;
|
|
@@ -6981,7 +6938,7 @@ async function showAgentEvents(runId, options) {
|
|
|
6981
6938
|
if (response.hasMore) {
|
|
6982
6939
|
console.log();
|
|
6983
6940
|
console.log(
|
|
6984
|
-
|
|
6941
|
+
chalk22.dim(
|
|
6985
6942
|
`Showing ${response.events.length} events. Use --tail to see more.`
|
|
6986
6943
|
)
|
|
6987
6944
|
);
|
|
@@ -6990,21 +6947,21 @@ async function showAgentEvents(runId, options) {
|
|
|
6990
6947
|
async function showSystemLog(runId, options) {
|
|
6991
6948
|
const response = await apiClient.getSystemLog(runId, options);
|
|
6992
6949
|
if (!response.systemLog) {
|
|
6993
|
-
console.log(
|
|
6950
|
+
console.log(chalk22.yellow("No system log found for this run."));
|
|
6994
6951
|
return;
|
|
6995
6952
|
}
|
|
6996
6953
|
console.log(response.systemLog);
|
|
6997
6954
|
if (response.hasMore) {
|
|
6998
6955
|
console.log();
|
|
6999
6956
|
console.log(
|
|
7000
|
-
|
|
6957
|
+
chalk22.dim("More log entries available. Use --tail to see more.")
|
|
7001
6958
|
);
|
|
7002
6959
|
}
|
|
7003
6960
|
}
|
|
7004
6961
|
async function showMetrics(runId, options) {
|
|
7005
6962
|
const response = await apiClient.getMetrics(runId, options);
|
|
7006
6963
|
if (response.metrics.length === 0) {
|
|
7007
|
-
console.log(
|
|
6964
|
+
console.log(chalk22.yellow("No metrics found for this run."));
|
|
7008
6965
|
return;
|
|
7009
6966
|
}
|
|
7010
6967
|
const metrics = options.order === "desc" ? [...response.metrics].reverse() : response.metrics;
|
|
@@ -7014,7 +6971,7 @@ async function showMetrics(runId, options) {
|
|
|
7014
6971
|
if (response.hasMore) {
|
|
7015
6972
|
console.log();
|
|
7016
6973
|
console.log(
|
|
7017
|
-
|
|
6974
|
+
chalk22.dim(
|
|
7018
6975
|
`Showing ${response.metrics.length} metrics. Use --tail to see more.`
|
|
7019
6976
|
)
|
|
7020
6977
|
);
|
|
@@ -7024,7 +6981,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
7024
6981
|
const response = await apiClient.getNetworkLogs(runId, options);
|
|
7025
6982
|
if (response.networkLogs.length === 0) {
|
|
7026
6983
|
console.log(
|
|
7027
|
-
|
|
6984
|
+
chalk22.yellow(
|
|
7028
6985
|
"No network logs found for this run. Network logs are only captured when experimental_firewall is enabled on an experimental_runner."
|
|
7029
6986
|
)
|
|
7030
6987
|
);
|
|
@@ -7037,7 +6994,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
7037
6994
|
if (response.hasMore) {
|
|
7038
6995
|
console.log();
|
|
7039
6996
|
console.log(
|
|
7040
|
-
|
|
6997
|
+
chalk22.dim(
|
|
7041
6998
|
`Showing ${response.networkLogs.length} network logs. Use --tail to see more.`
|
|
7042
6999
|
)
|
|
7043
7000
|
);
|
|
@@ -7046,17 +7003,17 @@ async function showNetworkLogs(runId, options) {
|
|
|
7046
7003
|
function handleError(error, runId) {
|
|
7047
7004
|
if (error instanceof Error) {
|
|
7048
7005
|
if (error.message.includes("Not authenticated")) {
|
|
7049
|
-
console.error(
|
|
7006
|
+
console.error(chalk22.red("Not authenticated. Run: vm0 auth login"));
|
|
7050
7007
|
} else if (error.message.includes("not found")) {
|
|
7051
|
-
console.error(
|
|
7008
|
+
console.error(chalk22.red(`Run not found: ${runId}`));
|
|
7052
7009
|
} else if (error.message.includes("Invalid time format")) {
|
|
7053
|
-
console.error(
|
|
7010
|
+
console.error(chalk22.red(error.message));
|
|
7054
7011
|
} else {
|
|
7055
|
-
console.error(
|
|
7056
|
-
console.error(
|
|
7012
|
+
console.error(chalk22.red("Failed to fetch logs"));
|
|
7013
|
+
console.error(chalk22.dim(` ${error.message}`));
|
|
7057
7014
|
}
|
|
7058
7015
|
} else {
|
|
7059
|
-
console.error(
|
|
7016
|
+
console.error(chalk22.red("An unexpected error occurred"));
|
|
7060
7017
|
}
|
|
7061
7018
|
}
|
|
7062
7019
|
|
|
@@ -7065,12 +7022,12 @@ import { Command as Command21 } from "commander";
|
|
|
7065
7022
|
|
|
7066
7023
|
// src/commands/scope/status.ts
|
|
7067
7024
|
import { Command as Command19 } from "commander";
|
|
7068
|
-
import
|
|
7025
|
+
import chalk23 from "chalk";
|
|
7069
7026
|
var statusCommand3 = new Command19().name("status").description("View current scope status").action(async () => {
|
|
7070
7027
|
try {
|
|
7071
7028
|
const scope = await apiClient.getScope();
|
|
7072
|
-
console.log(
|
|
7073
|
-
console.log(` Slug: ${
|
|
7029
|
+
console.log(chalk23.bold("Scope Information:"));
|
|
7030
|
+
console.log(` Slug: ${chalk23.green(scope.slug)}`);
|
|
7074
7031
|
console.log(` Type: ${scope.type}`);
|
|
7075
7032
|
if (scope.displayName) {
|
|
7076
7033
|
console.log(` Display Name: ${scope.displayName}`);
|
|
@@ -7081,20 +7038,20 @@ var statusCommand3 = new Command19().name("status").description("View current sc
|
|
|
7081
7038
|
} catch (error) {
|
|
7082
7039
|
if (error instanceof Error) {
|
|
7083
7040
|
if (error.message.includes("Not authenticated")) {
|
|
7084
|
-
console.error(
|
|
7041
|
+
console.error(chalk23.red("\u2717 Not authenticated. Run: vm0 auth login"));
|
|
7085
7042
|
} else if (error.message.includes("No scope configured")) {
|
|
7086
|
-
console.log(
|
|
7043
|
+
console.log(chalk23.yellow("No scope configured."));
|
|
7087
7044
|
console.log();
|
|
7088
7045
|
console.log("Set your scope with:");
|
|
7089
|
-
console.log(
|
|
7046
|
+
console.log(chalk23.cyan(" vm0 scope set <slug>"));
|
|
7090
7047
|
console.log();
|
|
7091
7048
|
console.log("Example:");
|
|
7092
|
-
console.log(
|
|
7049
|
+
console.log(chalk23.dim(" vm0 scope set myusername"));
|
|
7093
7050
|
} else {
|
|
7094
|
-
console.error(
|
|
7051
|
+
console.error(chalk23.red(`\u2717 ${error.message}`));
|
|
7095
7052
|
}
|
|
7096
7053
|
} else {
|
|
7097
|
-
console.error(
|
|
7054
|
+
console.error(chalk23.red("\u2717 An unexpected error occurred"));
|
|
7098
7055
|
}
|
|
7099
7056
|
process.exit(1);
|
|
7100
7057
|
}
|
|
@@ -7102,7 +7059,7 @@ var statusCommand3 = new Command19().name("status").description("View current sc
|
|
|
7102
7059
|
|
|
7103
7060
|
// src/commands/scope/set.ts
|
|
7104
7061
|
import { Command as Command20 } from "commander";
|
|
7105
|
-
import
|
|
7062
|
+
import chalk24 from "chalk";
|
|
7106
7063
|
var setCommand = new Command20().name("set").description("Set your scope slug").argument("<slug>", "The scope slug (e.g., your username)").option("--force", "Force change existing scope (may break references)").option("--display-name <name>", "Display name for the scope").action(
|
|
7107
7064
|
async (slug, options) => {
|
|
7108
7065
|
try {
|
|
@@ -7118,56 +7075,56 @@ var setCommand = new Command20().name("set").description("Set your scope slug").
|
|
|
7118
7075
|
if (existingScope) {
|
|
7119
7076
|
if (!options.force) {
|
|
7120
7077
|
console.error(
|
|
7121
|
-
|
|
7078
|
+
chalk24.yellow(`You already have a scope: ${existingScope.slug}`)
|
|
7122
7079
|
);
|
|
7123
7080
|
console.error();
|
|
7124
7081
|
console.error("To change your scope, use --force:");
|
|
7125
|
-
console.error(
|
|
7082
|
+
console.error(chalk24.cyan(` vm0 scope set ${slug} --force`));
|
|
7126
7083
|
console.error();
|
|
7127
7084
|
console.error(
|
|
7128
|
-
|
|
7085
|
+
chalk24.yellow(
|
|
7129
7086
|
"Warning: Changing your scope may break existing image references."
|
|
7130
7087
|
)
|
|
7131
7088
|
);
|
|
7132
7089
|
process.exit(1);
|
|
7133
7090
|
}
|
|
7134
7091
|
scope = await apiClient.updateScope({ slug, force: true });
|
|
7135
|
-
console.log(
|
|
7092
|
+
console.log(chalk24.green(`\u2713 Scope updated to ${scope.slug}`));
|
|
7136
7093
|
} else {
|
|
7137
7094
|
scope = await apiClient.createScope({
|
|
7138
7095
|
slug,
|
|
7139
7096
|
displayName: options.displayName
|
|
7140
7097
|
});
|
|
7141
|
-
console.log(
|
|
7098
|
+
console.log(chalk24.green(`\u2713 Scope created: ${scope.slug}`));
|
|
7142
7099
|
}
|
|
7143
7100
|
console.log();
|
|
7144
7101
|
console.log("Your images will now be namespaced as:");
|
|
7145
|
-
console.log(
|
|
7102
|
+
console.log(chalk24.cyan(` ${scope.slug}/<image-name>`));
|
|
7146
7103
|
} catch (error) {
|
|
7147
7104
|
if (error instanceof Error) {
|
|
7148
7105
|
if (error.message.includes("Not authenticated")) {
|
|
7149
7106
|
console.error(
|
|
7150
|
-
|
|
7107
|
+
chalk24.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
7151
7108
|
);
|
|
7152
7109
|
} else if (error.message.includes("already exists")) {
|
|
7153
7110
|
console.error(
|
|
7154
|
-
|
|
7111
|
+
chalk24.red(
|
|
7155
7112
|
`\u2717 Scope "${slug}" is already taken. Please choose a different slug.`
|
|
7156
7113
|
)
|
|
7157
7114
|
);
|
|
7158
7115
|
} else if (error.message.includes("reserved")) {
|
|
7159
|
-
console.error(
|
|
7116
|
+
console.error(chalk24.red(`\u2717 ${error.message}`));
|
|
7160
7117
|
} else if (error.message.includes("vm0")) {
|
|
7161
7118
|
console.error(
|
|
7162
|
-
|
|
7119
|
+
chalk24.red(
|
|
7163
7120
|
"\u2717 Scope slugs cannot start with 'vm0' (reserved for system use)"
|
|
7164
7121
|
)
|
|
7165
7122
|
);
|
|
7166
7123
|
} else {
|
|
7167
|
-
console.error(
|
|
7124
|
+
console.error(chalk24.red(`\u2717 ${error.message}`));
|
|
7168
7125
|
}
|
|
7169
7126
|
} else {
|
|
7170
|
-
console.error(
|
|
7127
|
+
console.error(chalk24.red("\u2717 An unexpected error occurred"));
|
|
7171
7128
|
}
|
|
7172
7129
|
process.exit(1);
|
|
7173
7130
|
}
|
|
@@ -7182,7 +7139,7 @@ import { Command as Command24 } from "commander";
|
|
|
7182
7139
|
|
|
7183
7140
|
// src/commands/agents/list.ts
|
|
7184
7141
|
import { Command as Command22 } from "commander";
|
|
7185
|
-
import
|
|
7142
|
+
import chalk25 from "chalk";
|
|
7186
7143
|
var listCommand3 = new Command22().name("list").alias("ls").description("List all agent composes").option("-s, --scope <scope>", "Scope to list composes from").action(async (options) => {
|
|
7187
7144
|
try {
|
|
7188
7145
|
const url = options.scope ? `/api/agent/composes/list?scope=${encodeURIComponent(options.scope)}` : "/api/agent/composes/list";
|
|
@@ -7193,9 +7150,9 @@ var listCommand3 = new Command22().name("list").alias("ls").description("List al
|
|
|
7193
7150
|
}
|
|
7194
7151
|
const data = await response.json();
|
|
7195
7152
|
if (data.composes.length === 0) {
|
|
7196
|
-
console.log(
|
|
7153
|
+
console.log(chalk25.dim("No agent composes found"));
|
|
7197
7154
|
console.log(
|
|
7198
|
-
|
|
7155
|
+
chalk25.dim(" Create one with: vm0 compose <agent-compose.yaml>")
|
|
7199
7156
|
);
|
|
7200
7157
|
return;
|
|
7201
7158
|
}
|
|
@@ -7203,9 +7160,9 @@ var listCommand3 = new Command22().name("list").alias("ls").description("List al
|
|
|
7203
7160
|
const header = ["NAME".padEnd(nameWidth), "VERSION", "UPDATED"].join(
|
|
7204
7161
|
" "
|
|
7205
7162
|
);
|
|
7206
|
-
console.log(
|
|
7163
|
+
console.log(chalk25.dim(header));
|
|
7207
7164
|
for (const compose of data.composes) {
|
|
7208
|
-
const versionShort = compose.headVersionId ? compose.headVersionId.slice(0, 8) :
|
|
7165
|
+
const versionShort = compose.headVersionId ? compose.headVersionId.slice(0, 8) : chalk25.dim("-");
|
|
7209
7166
|
const row = [
|
|
7210
7167
|
compose.name.padEnd(nameWidth),
|
|
7211
7168
|
versionShort,
|
|
@@ -7214,12 +7171,12 @@ var listCommand3 = new Command22().name("list").alias("ls").description("List al
|
|
|
7214
7171
|
console.log(row);
|
|
7215
7172
|
}
|
|
7216
7173
|
} catch (error) {
|
|
7217
|
-
console.error(
|
|
7174
|
+
console.error(chalk25.red("\u2717 Failed to list agent composes"));
|
|
7218
7175
|
if (error instanceof Error) {
|
|
7219
7176
|
if (error.message.includes("Not authenticated")) {
|
|
7220
|
-
console.error(
|
|
7177
|
+
console.error(chalk25.dim(" Run: vm0 auth login"));
|
|
7221
7178
|
} else {
|
|
7222
|
-
console.error(
|
|
7179
|
+
console.error(chalk25.dim(` ${error.message}`));
|
|
7223
7180
|
}
|
|
7224
7181
|
}
|
|
7225
7182
|
process.exit(1);
|
|
@@ -7228,7 +7185,7 @@ var listCommand3 = new Command22().name("list").alias("ls").description("List al
|
|
|
7228
7185
|
|
|
7229
7186
|
// src/commands/agents/inspect.ts
|
|
7230
7187
|
import { Command as Command23 } from "commander";
|
|
7231
|
-
import
|
|
7188
|
+
import chalk26 from "chalk";
|
|
7232
7189
|
|
|
7233
7190
|
// src/lib/domain/source-derivation.ts
|
|
7234
7191
|
import * as fs9 from "fs/promises";
|
|
@@ -7338,12 +7295,12 @@ async function deriveComposeVariableSources(content, options) {
|
|
|
7338
7295
|
|
|
7339
7296
|
// src/commands/agents/inspect.ts
|
|
7340
7297
|
function formatComposeOutput(name, versionId, content, variableSources) {
|
|
7341
|
-
console.log(
|
|
7342
|
-
console.log(
|
|
7298
|
+
console.log(chalk26.bold("Name:") + ` ${name}`);
|
|
7299
|
+
console.log(chalk26.bold("Version:") + ` ${versionId}`);
|
|
7343
7300
|
console.log();
|
|
7344
|
-
console.log(
|
|
7301
|
+
console.log(chalk26.bold("Agents:"));
|
|
7345
7302
|
for (const [agentName, agent] of Object.entries(content.agents)) {
|
|
7346
|
-
console.log(` ${
|
|
7303
|
+
console.log(` ${chalk26.cyan(agentName)}:`);
|
|
7347
7304
|
console.log(` Provider: ${agent.provider}`);
|
|
7348
7305
|
if (agent.image) {
|
|
7349
7306
|
console.log(` Image: ${agent.image}`);
|
|
@@ -7379,14 +7336,14 @@ function formatComposeOutput(name, versionId, content, variableSources) {
|
|
|
7379
7336
|
if (agentSources.secrets.length > 0) {
|
|
7380
7337
|
console.log(` Secrets:`);
|
|
7381
7338
|
for (const secret of agentSources.secrets) {
|
|
7382
|
-
const sourceInfo =
|
|
7339
|
+
const sourceInfo = chalk26.dim(`(${secret.source})`);
|
|
7383
7340
|
console.log(` - ${secret.name.padEnd(20)} ${sourceInfo}`);
|
|
7384
7341
|
}
|
|
7385
7342
|
}
|
|
7386
7343
|
if (agentSources.vars.length > 0) {
|
|
7387
7344
|
console.log(` Vars:`);
|
|
7388
7345
|
for (const v of agentSources.vars) {
|
|
7389
|
-
const sourceInfo =
|
|
7346
|
+
const sourceInfo = chalk26.dim(`(${v.source})`);
|
|
7390
7347
|
console.log(` - ${v.name.padEnd(20)} ${sourceInfo}`);
|
|
7391
7348
|
}
|
|
7392
7349
|
}
|
|
@@ -7417,8 +7374,8 @@ var inspectCommand = new Command23().name("inspect").description("Inspect an age
|
|
|
7417
7374
|
compose = await apiClient.getComposeByName(name, options.scope);
|
|
7418
7375
|
} catch (error) {
|
|
7419
7376
|
if (error instanceof Error && error.message.includes("not found")) {
|
|
7420
|
-
console.error(
|
|
7421
|
-
console.error(
|
|
7377
|
+
console.error(chalk26.red(`\u2717 Agent compose not found: ${name}`));
|
|
7378
|
+
console.error(chalk26.dim(" Run: vm0 agents list"));
|
|
7422
7379
|
process.exit(1);
|
|
7423
7380
|
}
|
|
7424
7381
|
throw error;
|
|
@@ -7434,9 +7391,9 @@ var inspectCommand = new Command23().name("inspect").description("Inspect an age
|
|
|
7434
7391
|
resolvedVersionId = versionInfo.versionId;
|
|
7435
7392
|
} catch (error) {
|
|
7436
7393
|
if (error instanceof Error && error.message.includes("not found")) {
|
|
7437
|
-
console.error(
|
|
7394
|
+
console.error(chalk26.red(`\u2717 Version not found: ${version}`));
|
|
7438
7395
|
console.error(
|
|
7439
|
-
|
|
7396
|
+
chalk26.dim(
|
|
7440
7397
|
` HEAD version: ${compose.headVersionId?.slice(0, 8)}`
|
|
7441
7398
|
)
|
|
7442
7399
|
);
|
|
@@ -7449,7 +7406,7 @@ var inspectCommand = new Command23().name("inspect").description("Inspect an age
|
|
|
7449
7406
|
}
|
|
7450
7407
|
}
|
|
7451
7408
|
if (!resolvedVersionId || !compose.content) {
|
|
7452
|
-
console.error(
|
|
7409
|
+
console.error(chalk26.red(`\u2717 No version found for: ${name}`));
|
|
7453
7410
|
process.exit(1);
|
|
7454
7411
|
}
|
|
7455
7412
|
const content = compose.content;
|
|
@@ -7459,7 +7416,7 @@ var inspectCommand = new Command23().name("inspect").description("Inspect an age
|
|
|
7459
7416
|
variableSources = await deriveComposeVariableSources(content);
|
|
7460
7417
|
} catch {
|
|
7461
7418
|
console.error(
|
|
7462
|
-
|
|
7419
|
+
chalk26.yellow(
|
|
7463
7420
|
"\u26A0 Warning: Failed to fetch skill sources, showing basic info"
|
|
7464
7421
|
)
|
|
7465
7422
|
);
|
|
@@ -7472,12 +7429,12 @@ var inspectCommand = new Command23().name("inspect").description("Inspect an age
|
|
|
7472
7429
|
variableSources
|
|
7473
7430
|
);
|
|
7474
7431
|
} catch (error) {
|
|
7475
|
-
console.error(
|
|
7432
|
+
console.error(chalk26.red("\u2717 Failed to inspect agent compose"));
|
|
7476
7433
|
if (error instanceof Error) {
|
|
7477
7434
|
if (error.message.includes("Not authenticated")) {
|
|
7478
|
-
console.error(
|
|
7435
|
+
console.error(chalk26.dim(" Run: vm0 auth login"));
|
|
7479
7436
|
} else {
|
|
7480
|
-
console.error(
|
|
7437
|
+
console.error(chalk26.dim(` ${error.message}`));
|
|
7481
7438
|
}
|
|
7482
7439
|
}
|
|
7483
7440
|
process.exit(1);
|
|
@@ -7490,7 +7447,7 @@ var agentsCommand = new Command24().name("agents").description("Manage agent com
|
|
|
7490
7447
|
|
|
7491
7448
|
// src/commands/init.ts
|
|
7492
7449
|
import { Command as Command25 } from "commander";
|
|
7493
|
-
import
|
|
7450
|
+
import chalk27 from "chalk";
|
|
7494
7451
|
import path14 from "path";
|
|
7495
7452
|
import { existsSync as existsSync9 } from "fs";
|
|
7496
7453
|
import { writeFile as writeFile7 } from "fs/promises";
|
|
@@ -7535,10 +7492,10 @@ var initCommand3 = new Command25().name("init").description("Initialize a new VM
|
|
|
7535
7492
|
const existingFiles = checkExistingFiles();
|
|
7536
7493
|
if (existingFiles.length > 0 && !options.force) {
|
|
7537
7494
|
for (const file of existingFiles) {
|
|
7538
|
-
console.log(
|
|
7495
|
+
console.log(chalk27.red(`\u2717 ${file} already exists`));
|
|
7539
7496
|
}
|
|
7540
7497
|
console.log();
|
|
7541
|
-
console.log(`To overwrite: ${
|
|
7498
|
+
console.log(`To overwrite: ${chalk27.cyan("vm0 init --force")}`);
|
|
7542
7499
|
process.exit(1);
|
|
7543
7500
|
}
|
|
7544
7501
|
let agentName;
|
|
@@ -7546,9 +7503,9 @@ var initCommand3 = new Command25().name("init").description("Initialize a new VM
|
|
|
7546
7503
|
agentName = options.name.trim();
|
|
7547
7504
|
} else if (!isInteractive()) {
|
|
7548
7505
|
console.error(
|
|
7549
|
-
|
|
7506
|
+
chalk27.red("\u2717 --name flag is required in non-interactive mode")
|
|
7550
7507
|
);
|
|
7551
|
-
console.error(
|
|
7508
|
+
console.error(chalk27.dim(" Usage: vm0 init --name <agent-name>"));
|
|
7552
7509
|
process.exit(1);
|
|
7553
7510
|
} else {
|
|
7554
7511
|
const dirName = path14.basename(process.cwd());
|
|
@@ -7564,40 +7521,40 @@ var initCommand3 = new Command25().name("init").description("Initialize a new VM
|
|
|
7564
7521
|
}
|
|
7565
7522
|
);
|
|
7566
7523
|
if (name === void 0) {
|
|
7567
|
-
console.log(
|
|
7524
|
+
console.log(chalk27.dim("Cancelled"));
|
|
7568
7525
|
return;
|
|
7569
7526
|
}
|
|
7570
7527
|
agentName = name;
|
|
7571
7528
|
}
|
|
7572
7529
|
if (!agentName || !validateAgentName(agentName)) {
|
|
7573
|
-
console.log(
|
|
7530
|
+
console.log(chalk27.red("\u2717 Invalid agent name"));
|
|
7574
7531
|
console.log(
|
|
7575
|
-
|
|
7532
|
+
chalk27.dim(" Must be 3-64 characters, alphanumeric and hyphens only")
|
|
7576
7533
|
);
|
|
7577
|
-
console.log(
|
|
7534
|
+
console.log(chalk27.dim(" Must start and end with letter or number"));
|
|
7578
7535
|
process.exit(1);
|
|
7579
7536
|
}
|
|
7580
7537
|
await writeFile7(VM0_YAML_FILE, generateVm0Yaml(agentName));
|
|
7581
7538
|
const vm0Status = existingFiles.includes(VM0_YAML_FILE) ? " (overwritten)" : "";
|
|
7582
|
-
console.log(
|
|
7539
|
+
console.log(chalk27.green(`\u2713 Created ${VM0_YAML_FILE}${vm0Status}`));
|
|
7583
7540
|
await writeFile7(AGENTS_MD_FILE, generateAgentsMd());
|
|
7584
7541
|
const agentsStatus = existingFiles.includes(AGENTS_MD_FILE) ? " (overwritten)" : "";
|
|
7585
|
-
console.log(
|
|
7542
|
+
console.log(chalk27.green(`\u2713 Created ${AGENTS_MD_FILE}${agentsStatus}`));
|
|
7586
7543
|
console.log();
|
|
7587
7544
|
console.log("Next steps:");
|
|
7588
7545
|
console.log(
|
|
7589
|
-
` 1. Get your Claude Code token: ${
|
|
7546
|
+
` 1. Get your Claude Code token: ${chalk27.cyan("claude setup-token")}`
|
|
7590
7547
|
);
|
|
7591
7548
|
console.log(` 2. Set the environment variable (or add to .env file):`);
|
|
7592
|
-
console.log(
|
|
7549
|
+
console.log(chalk27.dim(` export CLAUDE_CODE_OAUTH_TOKEN=<your-token>`));
|
|
7593
7550
|
console.log(
|
|
7594
|
-
` 3. Run your agent: ${
|
|
7551
|
+
` 3. Run your agent: ${chalk27.cyan(`vm0 cook "let's start working."`)}`
|
|
7595
7552
|
);
|
|
7596
7553
|
});
|
|
7597
7554
|
|
|
7598
7555
|
// src/commands/setup-github.ts
|
|
7599
7556
|
import { Command as Command26 } from "commander";
|
|
7600
|
-
import
|
|
7557
|
+
import chalk28 from "chalk";
|
|
7601
7558
|
import { existsSync as existsSync10 } from "fs";
|
|
7602
7559
|
import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
7603
7560
|
import { execSync, spawnSync } from "child_process";
|
|
@@ -7640,67 +7597,67 @@ async function checkPrerequisites() {
|
|
|
7640
7597
|
console.log("Checking prerequisites...");
|
|
7641
7598
|
const gitRoot = getGitRoot();
|
|
7642
7599
|
if (!gitRoot) {
|
|
7643
|
-
console.log(
|
|
7600
|
+
console.log(chalk28.red("\u2717 Not in a git repository"));
|
|
7644
7601
|
console.log();
|
|
7645
7602
|
console.log("This command must be run from within a git repository.");
|
|
7646
7603
|
console.log();
|
|
7647
7604
|
console.log("To initialize a git repository, run:");
|
|
7648
|
-
console.log(` ${
|
|
7605
|
+
console.log(` ${chalk28.cyan("git init")}`);
|
|
7649
7606
|
process.exit(1);
|
|
7650
7607
|
}
|
|
7651
|
-
console.log(
|
|
7608
|
+
console.log(chalk28.green("\u2713 Git repository detected"));
|
|
7652
7609
|
if (!isGhInstalled()) {
|
|
7653
|
-
console.log(
|
|
7610
|
+
console.log(chalk28.red("\u2717 GitHub CLI (gh) is not installed"));
|
|
7654
7611
|
console.log();
|
|
7655
7612
|
console.log("GitHub CLI is required for this command.");
|
|
7656
7613
|
console.log();
|
|
7657
|
-
console.log(` macOS: ${
|
|
7658
|
-
console.log(` Other: ${
|
|
7614
|
+
console.log(` macOS: ${chalk28.cyan("brew install gh")}`);
|
|
7615
|
+
console.log(` Other: ${chalk28.cyan("https://cli.github.com/")}`);
|
|
7659
7616
|
console.log();
|
|
7660
7617
|
console.log("After installation, run:");
|
|
7661
|
-
console.log(` ${
|
|
7618
|
+
console.log(` ${chalk28.cyan("gh auth login")}`);
|
|
7662
7619
|
console.log();
|
|
7663
7620
|
console.log("Then try again:");
|
|
7664
|
-
console.log(` ${
|
|
7621
|
+
console.log(` ${chalk28.cyan("vm0 setup-github")}`);
|
|
7665
7622
|
process.exit(1);
|
|
7666
7623
|
}
|
|
7667
|
-
console.log(
|
|
7624
|
+
console.log(chalk28.green("\u2713 GitHub CLI (gh) is installed"));
|
|
7668
7625
|
if (!isGhAuthenticated()) {
|
|
7669
|
-
console.log(
|
|
7626
|
+
console.log(chalk28.red("\u2717 GitHub CLI is not authenticated"));
|
|
7670
7627
|
console.log();
|
|
7671
7628
|
console.log("Please authenticate GitHub CLI first:");
|
|
7672
|
-
console.log(` ${
|
|
7629
|
+
console.log(` ${chalk28.cyan("gh auth login")}`);
|
|
7673
7630
|
console.log();
|
|
7674
7631
|
console.log("Then try again:");
|
|
7675
|
-
console.log(` ${
|
|
7632
|
+
console.log(` ${chalk28.cyan("vm0 setup-github")}`);
|
|
7676
7633
|
process.exit(1);
|
|
7677
7634
|
}
|
|
7678
|
-
console.log(
|
|
7635
|
+
console.log(chalk28.green("\u2713 GitHub CLI is authenticated"));
|
|
7679
7636
|
const token = await getToken();
|
|
7680
7637
|
if (!token) {
|
|
7681
|
-
console.log(
|
|
7638
|
+
console.log(chalk28.red("\u2717 VM0 not authenticated"));
|
|
7682
7639
|
console.log();
|
|
7683
7640
|
console.log("Please authenticate with VM0 first:");
|
|
7684
|
-
console.log(` ${
|
|
7641
|
+
console.log(` ${chalk28.cyan("vm0 auth login")}`);
|
|
7685
7642
|
console.log();
|
|
7686
7643
|
console.log("Then try again:");
|
|
7687
|
-
console.log(` ${
|
|
7644
|
+
console.log(` ${chalk28.cyan("vm0 setup-github")}`);
|
|
7688
7645
|
process.exit(1);
|
|
7689
7646
|
}
|
|
7690
|
-
console.log(
|
|
7647
|
+
console.log(chalk28.green("\u2713 VM0 authenticated"));
|
|
7691
7648
|
if (!existsSync10("vm0.yaml")) {
|
|
7692
|
-
console.log(
|
|
7649
|
+
console.log(chalk28.red("\u2717 vm0.yaml not found"));
|
|
7693
7650
|
console.log();
|
|
7694
7651
|
console.log("This command requires a vm0.yaml configuration file.");
|
|
7695
7652
|
console.log();
|
|
7696
7653
|
console.log("To create one, run:");
|
|
7697
|
-
console.log(` ${
|
|
7654
|
+
console.log(` ${chalk28.cyan("vm0 init")}`);
|
|
7698
7655
|
console.log();
|
|
7699
7656
|
console.log("Then try again:");
|
|
7700
|
-
console.log(` ${
|
|
7657
|
+
console.log(` ${chalk28.cyan("vm0 setup-github")}`);
|
|
7701
7658
|
process.exit(1);
|
|
7702
7659
|
}
|
|
7703
|
-
console.log(
|
|
7660
|
+
console.log(chalk28.green("\u2713 vm0.yaml found"));
|
|
7704
7661
|
return { token, gitRoot };
|
|
7705
7662
|
}
|
|
7706
7663
|
function generatePublishYaml(workingDir) {
|
|
@@ -7857,7 +7814,7 @@ function displaySecretsTable(secretStatuses, varStatuses) {
|
|
|
7857
7814
|
if (secretStatuses.length > 0) {
|
|
7858
7815
|
console.log("\u2502 Secrets: \u2502");
|
|
7859
7816
|
for (const s of secretStatuses) {
|
|
7860
|
-
const status = s.found ?
|
|
7817
|
+
const status = s.found ? chalk28.green("\u2713") : chalk28.red("\u2717");
|
|
7861
7818
|
const source = s.found ? `(from ${s.source})` : "not found";
|
|
7862
7819
|
const paddedName = (s.name + " ").padEnd(23, ".");
|
|
7863
7820
|
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
@@ -7866,7 +7823,7 @@ function displaySecretsTable(secretStatuses, varStatuses) {
|
|
|
7866
7823
|
if (varStatuses.length > 0) {
|
|
7867
7824
|
console.log("\u2502 Variables: \u2502");
|
|
7868
7825
|
for (const v of varStatuses) {
|
|
7869
|
-
const status = v.found ?
|
|
7826
|
+
const status = v.found ? chalk28.green("\u2713") : chalk28.red("\u2717");
|
|
7870
7827
|
const source = v.found ? `(from ${v.source})` : "not found";
|
|
7871
7828
|
const paddedName = (v.name + " ").padEnd(23, ".");
|
|
7872
7829
|
console.log(`\u2502 ${status} ${paddedName} ${source.padEnd(19)}\u2502`);
|
|
@@ -7878,17 +7835,17 @@ function showManualSetupInstructions(secrets, vars) {
|
|
|
7878
7835
|
console.log("Skipped automatic setup. Configure secrets manually:");
|
|
7879
7836
|
console.log();
|
|
7880
7837
|
console.log(" Step 1: Get your VM0 token");
|
|
7881
|
-
console.log(` ${
|
|
7838
|
+
console.log(` ${chalk28.cyan("vm0 auth setup-token")}`);
|
|
7882
7839
|
console.log();
|
|
7883
7840
|
console.log(" Step 2: Set GitHub secrets");
|
|
7884
7841
|
for (const s of secrets) {
|
|
7885
|
-
console.log(` ${
|
|
7842
|
+
console.log(` ${chalk28.cyan(`gh secret set ${s}`)}`);
|
|
7886
7843
|
}
|
|
7887
7844
|
if (vars.length > 0) {
|
|
7888
7845
|
console.log();
|
|
7889
7846
|
console.log(" Step 3: Set GitHub variables");
|
|
7890
7847
|
for (const v of vars) {
|
|
7891
|
-
console.log(` ${
|
|
7848
|
+
console.log(` ${chalk28.cyan(`gh variable set ${v}`)}`);
|
|
7892
7849
|
}
|
|
7893
7850
|
}
|
|
7894
7851
|
}
|
|
@@ -7945,10 +7902,10 @@ var setupGithubCommand = new Command26().name("setup-github").description("Initi
|
|
|
7945
7902
|
const config = parseYaml5(content);
|
|
7946
7903
|
const agents = config.agents;
|
|
7947
7904
|
const agentName = Object.keys(agents)[0];
|
|
7948
|
-
console.log(
|
|
7905
|
+
console.log(chalk28.green(`\u2713 Agent: ${agentName}`));
|
|
7949
7906
|
const { secrets, vars } = extractSecretsAndVars(config);
|
|
7950
7907
|
console.log(
|
|
7951
|
-
|
|
7908
|
+
chalk28.green(
|
|
7952
7909
|
`\u2713 Found ${secrets.length} secrets, ${vars.length} variables`
|
|
7953
7910
|
)
|
|
7954
7911
|
);
|
|
@@ -7961,7 +7918,7 @@ var setupGithubCommand = new Command26().name("setup-github").description("Initi
|
|
|
7961
7918
|
if (existsSync10(publishPath)) existingFiles.push(displayPublishPath);
|
|
7962
7919
|
if (existsSync10(runPath)) existingFiles.push(displayRunPath);
|
|
7963
7920
|
if (existingFiles.length > 0 && !options.force) {
|
|
7964
|
-
console.log(
|
|
7921
|
+
console.log(chalk28.yellow("\u26A0 Existing workflow files detected:"));
|
|
7965
7922
|
for (const file of existingFiles) {
|
|
7966
7923
|
console.log(` \u2022 ${file}`);
|
|
7967
7924
|
}
|
|
@@ -7974,7 +7931,7 @@ var setupGithubCommand = new Command26().name("setup-github").description("Initi
|
|
|
7974
7931
|
if (!overwrite) {
|
|
7975
7932
|
console.log();
|
|
7976
7933
|
console.log("Aborted. To force overwrite, run:");
|
|
7977
|
-
console.log(` ${
|
|
7934
|
+
console.log(` ${chalk28.cyan("vm0 setup-github --force")}`);
|
|
7978
7935
|
process.exit(0);
|
|
7979
7936
|
}
|
|
7980
7937
|
}
|
|
@@ -7984,13 +7941,13 @@ var setupGithubCommand = new Command26().name("setup-github").description("Initi
|
|
|
7984
7941
|
await mkdir7(path15.join(gitRoot, ".github/workflows"), { recursive: true });
|
|
7985
7942
|
await writeFile8(publishPath, generatePublishYaml(workingDir));
|
|
7986
7943
|
const publishStatus = existingFiles.includes(displayPublishPath) ? "Overwrote" : "Created";
|
|
7987
|
-
console.log(
|
|
7944
|
+
console.log(chalk28.green(`\u2713 ${publishStatus} ${displayPublishPath}`));
|
|
7988
7945
|
await writeFile8(runPath, generateRunYaml(agentName, secrets, vars));
|
|
7989
7946
|
const runStatus = existingFiles.includes(displayRunPath) ? "Overwrote" : "Created";
|
|
7990
|
-
console.log(
|
|
7947
|
+
console.log(chalk28.green(`\u2713 ${runStatus} ${displayRunPath}`));
|
|
7991
7948
|
console.log();
|
|
7992
7949
|
if (options.skipSecrets) {
|
|
7993
|
-
console.log(
|
|
7950
|
+
console.log(chalk28.green("\u2713 Done (secrets setup skipped)"));
|
|
7994
7951
|
return;
|
|
7995
7952
|
}
|
|
7996
7953
|
const { secretStatuses, varStatuses } = await detectSecretValues(
|
|
@@ -8030,14 +7987,14 @@ var setupGithubCommand = new Command26().name("setup-github").description("Initi
|
|
|
8030
7987
|
if (s.found && s.value) {
|
|
8031
7988
|
const success = setGitHubSecret(s.name, s.value);
|
|
8032
7989
|
if (success) {
|
|
8033
|
-
console.log(` ${
|
|
7990
|
+
console.log(` ${chalk28.green("\u2713")} ${s.name}`);
|
|
8034
7991
|
} else {
|
|
8035
|
-
console.log(` ${
|
|
7992
|
+
console.log(` ${chalk28.red("\u2717")} ${s.name} (failed)`);
|
|
8036
7993
|
failedSecrets.push(s.name);
|
|
8037
7994
|
}
|
|
8038
7995
|
} else {
|
|
8039
7996
|
console.log(
|
|
8040
|
-
` ${
|
|
7997
|
+
` ${chalk28.yellow("\u26A0")} ${s.name} (skipped - not found)`
|
|
8041
7998
|
);
|
|
8042
7999
|
}
|
|
8043
8000
|
}
|
|
@@ -8049,14 +8006,14 @@ var setupGithubCommand = new Command26().name("setup-github").description("Initi
|
|
|
8049
8006
|
if (v.found && v.value) {
|
|
8050
8007
|
const success = setGitHubVariable(v.name, v.value);
|
|
8051
8008
|
if (success) {
|
|
8052
|
-
console.log(` ${
|
|
8009
|
+
console.log(` ${chalk28.green("\u2713")} ${v.name}`);
|
|
8053
8010
|
} else {
|
|
8054
|
-
console.log(` ${
|
|
8011
|
+
console.log(` ${chalk28.red("\u2717")} ${v.name} (failed)`);
|
|
8055
8012
|
failedVars.push(v.name);
|
|
8056
8013
|
}
|
|
8057
8014
|
} else {
|
|
8058
8015
|
console.log(
|
|
8059
|
-
` ${
|
|
8016
|
+
` ${chalk28.yellow("\u26A0")} ${v.name} (skipped - not found)`
|
|
8060
8017
|
);
|
|
8061
8018
|
}
|
|
8062
8019
|
}
|
|
@@ -8083,7 +8040,7 @@ import { Command as Command34 } from "commander";
|
|
|
8083
8040
|
|
|
8084
8041
|
// src/commands/schedule/init.ts
|
|
8085
8042
|
import { Command as Command27 } from "commander";
|
|
8086
|
-
import
|
|
8043
|
+
import chalk29 from "chalk";
|
|
8087
8044
|
import { existsSync as existsSync12, writeFileSync } from "fs";
|
|
8088
8045
|
import { stringify as stringifyYaml2 } from "yaml";
|
|
8089
8046
|
|
|
@@ -8091,6 +8048,7 @@ import { stringify as stringifyYaml2 } from "yaml";
|
|
|
8091
8048
|
import { existsSync as existsSync11, readFileSync as readFileSync2 } from "fs";
|
|
8092
8049
|
import { parse as parseYaml6 } from "yaml";
|
|
8093
8050
|
var CONFIG_FILE4 = "vm0.yaml";
|
|
8051
|
+
var SCHEDULE_FILE = "schedule.yaml";
|
|
8094
8052
|
function loadAgentName() {
|
|
8095
8053
|
if (!existsSync11(CONFIG_FILE4)) {
|
|
8096
8054
|
return { agentName: null };
|
|
@@ -8107,6 +8065,28 @@ function loadAgentName() {
|
|
|
8107
8065
|
};
|
|
8108
8066
|
}
|
|
8109
8067
|
}
|
|
8068
|
+
function loadScheduleName() {
|
|
8069
|
+
if (!existsSync11(SCHEDULE_FILE)) {
|
|
8070
|
+
return { scheduleName: null };
|
|
8071
|
+
}
|
|
8072
|
+
try {
|
|
8073
|
+
const content = readFileSync2(SCHEDULE_FILE, "utf8");
|
|
8074
|
+
const parsed = parseYaml6(content);
|
|
8075
|
+
if (!parsed?.schedules) {
|
|
8076
|
+
return {
|
|
8077
|
+
scheduleName: null,
|
|
8078
|
+
error: "No schedules defined in schedule.yaml"
|
|
8079
|
+
};
|
|
8080
|
+
}
|
|
8081
|
+
const scheduleNames = Object.keys(parsed.schedules);
|
|
8082
|
+
return { scheduleName: scheduleNames[0] || null };
|
|
8083
|
+
} catch (err) {
|
|
8084
|
+
return {
|
|
8085
|
+
scheduleName: null,
|
|
8086
|
+
error: err instanceof Error ? err.message : "Failed to parse schedule.yaml"
|
|
8087
|
+
};
|
|
8088
|
+
}
|
|
8089
|
+
}
|
|
8110
8090
|
function formatRelativeTime2(dateStr) {
|
|
8111
8091
|
if (!dateStr) return "-";
|
|
8112
8092
|
const date = new Date(dateStr);
|
|
@@ -8259,7 +8239,7 @@ function toISODateTime(dateTimeStr) {
|
|
|
8259
8239
|
}
|
|
8260
8240
|
|
|
8261
8241
|
// src/commands/schedule/init.ts
|
|
8262
|
-
var
|
|
8242
|
+
var SCHEDULE_FILE2 = "schedule.yaml";
|
|
8263
8243
|
var FREQUENCY_CHOICES = [
|
|
8264
8244
|
{ title: "Daily", value: "daily", description: "Run every day" },
|
|
8265
8245
|
{
|
|
@@ -8312,20 +8292,20 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8312
8292
|
try {
|
|
8313
8293
|
const { agentName, error } = loadAgentName();
|
|
8314
8294
|
if (error) {
|
|
8315
|
-
console.error(
|
|
8295
|
+
console.error(chalk29.red(`\u2717 Invalid vm0.yaml: ${error}`));
|
|
8316
8296
|
process.exit(1);
|
|
8317
8297
|
}
|
|
8318
8298
|
if (!agentName) {
|
|
8319
|
-
console.error(
|
|
8299
|
+
console.error(chalk29.red("\u2717 No vm0.yaml found"));
|
|
8320
8300
|
console.error(
|
|
8321
|
-
|
|
8301
|
+
chalk29.dim(" Run this command from an agent directory")
|
|
8322
8302
|
);
|
|
8323
8303
|
process.exit(1);
|
|
8324
8304
|
}
|
|
8325
|
-
if (existsSync12(
|
|
8305
|
+
if (existsSync12(SCHEDULE_FILE2) && !options.force) {
|
|
8326
8306
|
if (!isInteractive()) {
|
|
8327
|
-
console.error(
|
|
8328
|
-
console.error(
|
|
8307
|
+
console.error(chalk29.red("\u2717 schedule.yaml already exists"));
|
|
8308
|
+
console.error(chalk29.dim(" Use --force to overwrite"));
|
|
8329
8309
|
process.exit(1);
|
|
8330
8310
|
}
|
|
8331
8311
|
const overwrite = await promptConfirm(
|
|
@@ -8333,7 +8313,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8333
8313
|
false
|
|
8334
8314
|
);
|
|
8335
8315
|
if (!overwrite) {
|
|
8336
|
-
console.log(
|
|
8316
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8337
8317
|
return;
|
|
8338
8318
|
}
|
|
8339
8319
|
}
|
|
@@ -8341,7 +8321,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8341
8321
|
if (!scheduleName) {
|
|
8342
8322
|
if (!isInteractive()) {
|
|
8343
8323
|
console.error(
|
|
8344
|
-
|
|
8324
|
+
chalk29.red("\u2717 --name is required in non-interactive mode")
|
|
8345
8325
|
);
|
|
8346
8326
|
process.exit(1);
|
|
8347
8327
|
}
|
|
@@ -8350,7 +8330,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8350
8330
|
`${agentName}-schedule`
|
|
8351
8331
|
);
|
|
8352
8332
|
if (!scheduleName) {
|
|
8353
|
-
console.log(
|
|
8333
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8354
8334
|
return;
|
|
8355
8335
|
}
|
|
8356
8336
|
}
|
|
@@ -8358,7 +8338,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8358
8338
|
if (!frequency || !["daily", "weekly", "monthly", "once"].includes(frequency)) {
|
|
8359
8339
|
if (!isInteractive()) {
|
|
8360
8340
|
console.error(
|
|
8361
|
-
|
|
8341
|
+
chalk29.red(
|
|
8362
8342
|
"\u2717 --frequency is required (daily|weekly|monthly|once)"
|
|
8363
8343
|
)
|
|
8364
8344
|
);
|
|
@@ -8370,7 +8350,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8370
8350
|
0
|
|
8371
8351
|
);
|
|
8372
8352
|
if (!frequency) {
|
|
8373
|
-
console.log(
|
|
8353
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8374
8354
|
return;
|
|
8375
8355
|
}
|
|
8376
8356
|
}
|
|
@@ -8380,7 +8360,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8380
8360
|
day = parseDayOption(options.day, frequency);
|
|
8381
8361
|
if (day === void 0) {
|
|
8382
8362
|
console.error(
|
|
8383
|
-
|
|
8363
|
+
chalk29.red(
|
|
8384
8364
|
`\u2717 Invalid day: ${options.day}. Use mon-sun for weekly or 1-31 for monthly.`
|
|
8385
8365
|
)
|
|
8386
8366
|
);
|
|
@@ -8390,23 +8370,23 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8390
8370
|
if (frequency === "weekly") {
|
|
8391
8371
|
day = await promptSelect("Day of week", DAY_OF_WEEK_CHOICES, 0);
|
|
8392
8372
|
if (day === void 0) {
|
|
8393
|
-
console.log(
|
|
8373
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8394
8374
|
return;
|
|
8395
8375
|
}
|
|
8396
8376
|
} else {
|
|
8397
8377
|
const dayStr = await promptText("Day of month (1-31)", "1");
|
|
8398
8378
|
if (!dayStr) {
|
|
8399
|
-
console.log(
|
|
8379
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8400
8380
|
return;
|
|
8401
8381
|
}
|
|
8402
8382
|
day = parseInt(dayStr, 10);
|
|
8403
8383
|
if (isNaN(day) || day < 1 || day > 31) {
|
|
8404
|
-
console.error(
|
|
8384
|
+
console.error(chalk29.red("\u2717 Day must be between 1 and 31"));
|
|
8405
8385
|
process.exit(1);
|
|
8406
8386
|
}
|
|
8407
8387
|
}
|
|
8408
8388
|
} else {
|
|
8409
|
-
console.error(
|
|
8389
|
+
console.error(chalk29.red("\u2717 --day is required for weekly/monthly"));
|
|
8410
8390
|
process.exit(1);
|
|
8411
8391
|
}
|
|
8412
8392
|
}
|
|
@@ -8415,22 +8395,21 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8415
8395
|
if (frequency === "once") {
|
|
8416
8396
|
if (!isInteractive()) {
|
|
8417
8397
|
console.error(
|
|
8418
|
-
|
|
8398
|
+
chalk29.red("\u2717 One-time schedules require interactive mode")
|
|
8419
8399
|
);
|
|
8420
8400
|
console.error(
|
|
8421
|
-
|
|
8401
|
+
chalk29.dim(" Use cron frequency for non-interactive mode")
|
|
8422
8402
|
);
|
|
8423
8403
|
process.exit(1);
|
|
8424
8404
|
}
|
|
8425
8405
|
const tomorrowDate = getTomorrowDateLocal();
|
|
8426
|
-
const date = await
|
|
8427
|
-
"Date (YYYY-MM-DD)",
|
|
8428
|
-
"tomorrow",
|
|
8406
|
+
const date = await promptText(
|
|
8407
|
+
"Date (YYYY-MM-DD, default tomorrow)",
|
|
8429
8408
|
tomorrowDate,
|
|
8430
8409
|
validateDateFormat
|
|
8431
8410
|
);
|
|
8432
8411
|
if (!date) {
|
|
8433
|
-
console.log(
|
|
8412
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8434
8413
|
return;
|
|
8435
8414
|
}
|
|
8436
8415
|
const currentTime = getCurrentTimeLocal();
|
|
@@ -8440,7 +8419,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8440
8419
|
validateTimeFormat
|
|
8441
8420
|
);
|
|
8442
8421
|
if (!time) {
|
|
8443
|
-
console.log(
|
|
8422
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8444
8423
|
return;
|
|
8445
8424
|
}
|
|
8446
8425
|
const dateStr = `${date} ${time}`;
|
|
@@ -8448,7 +8427,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8448
8427
|
} else {
|
|
8449
8428
|
if (!time) {
|
|
8450
8429
|
if (!isInteractive()) {
|
|
8451
|
-
console.error(
|
|
8430
|
+
console.error(chalk29.red("\u2717 --time is required (HH:MM format)"));
|
|
8452
8431
|
process.exit(1);
|
|
8453
8432
|
}
|
|
8454
8433
|
time = await promptText(
|
|
@@ -8457,13 +8436,13 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8457
8436
|
validateTimeFormat
|
|
8458
8437
|
);
|
|
8459
8438
|
if (!time) {
|
|
8460
|
-
console.log(
|
|
8439
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8461
8440
|
return;
|
|
8462
8441
|
}
|
|
8463
8442
|
} else {
|
|
8464
8443
|
const validation = validateTimeFormat(time);
|
|
8465
8444
|
if (validation !== true) {
|
|
8466
|
-
console.error(
|
|
8445
|
+
console.error(chalk29.red(`\u2717 Invalid time: ${validation}`));
|
|
8467
8446
|
process.exit(1);
|
|
8468
8447
|
}
|
|
8469
8448
|
}
|
|
@@ -8474,7 +8453,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8474
8453
|
if (isInteractive()) {
|
|
8475
8454
|
timezone = await promptText("Timezone", detectedTimezone);
|
|
8476
8455
|
if (!timezone) {
|
|
8477
|
-
console.log(
|
|
8456
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8478
8457
|
return;
|
|
8479
8458
|
}
|
|
8480
8459
|
} else {
|
|
@@ -8484,7 +8463,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8484
8463
|
let promptText_ = options.prompt;
|
|
8485
8464
|
if (!promptText_) {
|
|
8486
8465
|
if (!isInteractive()) {
|
|
8487
|
-
console.error(
|
|
8466
|
+
console.error(chalk29.red("\u2717 --prompt is required"));
|
|
8488
8467
|
process.exit(1);
|
|
8489
8468
|
}
|
|
8490
8469
|
promptText_ = await promptText(
|
|
@@ -8492,7 +8471,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8492
8471
|
"let's start working."
|
|
8493
8472
|
);
|
|
8494
8473
|
if (!promptText_) {
|
|
8495
|
-
console.log(
|
|
8474
|
+
console.log(chalk29.dim("Cancelled"));
|
|
8496
8475
|
return;
|
|
8497
8476
|
}
|
|
8498
8477
|
}
|
|
@@ -8558,13 +8537,13 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8558
8537
|
if (secrets && Object.keys(secrets).length > 0) {
|
|
8559
8538
|
scheduleYaml.schedules[scheduleName].run.secrets = secrets;
|
|
8560
8539
|
}
|
|
8561
|
-
writeFileSync(
|
|
8562
|
-
console.log(
|
|
8563
|
-
console.log(
|
|
8540
|
+
writeFileSync(SCHEDULE_FILE2, stringifyYaml2(scheduleYaml));
|
|
8541
|
+
console.log(chalk29.green(`\u2713 Created ${SCHEDULE_FILE2}`));
|
|
8542
|
+
console.log(chalk29.dim(" Deploy with: vm0 schedule deploy"));
|
|
8564
8543
|
} catch (error) {
|
|
8565
|
-
console.error(
|
|
8544
|
+
console.error(chalk29.red("\u2717 Failed to create schedule.yaml"));
|
|
8566
8545
|
if (error instanceof Error) {
|
|
8567
|
-
console.error(
|
|
8546
|
+
console.error(chalk29.dim(` ${error.message}`));
|
|
8568
8547
|
}
|
|
8569
8548
|
process.exit(1);
|
|
8570
8549
|
}
|
|
@@ -8573,7 +8552,7 @@ var initCommand4 = new Command27().name("init").description("Create a schedule.y
|
|
|
8573
8552
|
|
|
8574
8553
|
// src/commands/schedule/deploy.ts
|
|
8575
8554
|
import { Command as Command28 } from "commander";
|
|
8576
|
-
import
|
|
8555
|
+
import chalk30 from "chalk";
|
|
8577
8556
|
import { existsSync as existsSync13, readFileSync as readFileSync3 } from "fs";
|
|
8578
8557
|
import { parse as parseYaml7 } from "yaml";
|
|
8579
8558
|
function expandEnvVars(value) {
|
|
@@ -8581,7 +8560,7 @@ function expandEnvVars(value) {
|
|
|
8581
8560
|
const envValue = process.env[varName];
|
|
8582
8561
|
if (envValue === void 0) {
|
|
8583
8562
|
console.warn(
|
|
8584
|
-
|
|
8563
|
+
chalk30.yellow(` Warning: Environment variable ${varName} not set`)
|
|
8585
8564
|
);
|
|
8586
8565
|
return match;
|
|
8587
8566
|
}
|
|
@@ -8596,11 +8575,25 @@ function expandEnvVarsInObject(obj) {
|
|
|
8596
8575
|
}
|
|
8597
8576
|
return result;
|
|
8598
8577
|
}
|
|
8578
|
+
function formatInTimezone(isoDate, timezone) {
|
|
8579
|
+
const date = new Date(isoDate);
|
|
8580
|
+
const parts = new Intl.DateTimeFormat("en-CA", {
|
|
8581
|
+
timeZone: timezone,
|
|
8582
|
+
year: "numeric",
|
|
8583
|
+
month: "2-digit",
|
|
8584
|
+
day: "2-digit",
|
|
8585
|
+
hour: "2-digit",
|
|
8586
|
+
minute: "2-digit",
|
|
8587
|
+
hour12: false
|
|
8588
|
+
}).formatToParts(date);
|
|
8589
|
+
const get = (type) => parts.find((p) => p.type === type)?.value ?? "";
|
|
8590
|
+
return `${get("year")}-${get("month")}-${get("day")} ${get("hour")}:${get("minute")}`;
|
|
8591
|
+
}
|
|
8599
8592
|
var deployCommand = new Command28().name("deploy").description("Deploy a schedule from schedule.yaml (create or update)").argument("[file]", "Path to schedule.yaml", "schedule.yaml").action(async (file) => {
|
|
8600
8593
|
try {
|
|
8601
8594
|
if (!existsSync13(file)) {
|
|
8602
|
-
console.error(
|
|
8603
|
-
console.error(
|
|
8595
|
+
console.error(chalk30.red(`\u2717 File not found: ${file}`));
|
|
8596
|
+
console.error(chalk30.dim(" Create a schedule.yaml file first"));
|
|
8604
8597
|
process.exit(1);
|
|
8605
8598
|
}
|
|
8606
8599
|
const content = readFileSync3(file, "utf-8");
|
|
@@ -8608,18 +8601,18 @@ var deployCommand = new Command28().name("deploy").description("Deploy a schedul
|
|
|
8608
8601
|
try {
|
|
8609
8602
|
parsed = parseYaml7(content);
|
|
8610
8603
|
} catch (err) {
|
|
8611
|
-
console.error(
|
|
8604
|
+
console.error(chalk30.red("\u2717 Invalid YAML syntax"));
|
|
8612
8605
|
if (err instanceof Error) {
|
|
8613
|
-
console.error(
|
|
8606
|
+
console.error(chalk30.dim(` ${err.message}`));
|
|
8614
8607
|
}
|
|
8615
8608
|
process.exit(1);
|
|
8616
8609
|
}
|
|
8617
8610
|
const result = scheduleYamlSchema.safeParse(parsed);
|
|
8618
8611
|
if (!result.success) {
|
|
8619
|
-
console.error(
|
|
8612
|
+
console.error(chalk30.red("\u2717 Invalid schedule.yaml format"));
|
|
8620
8613
|
for (const issue of result.error.issues) {
|
|
8621
8614
|
console.error(
|
|
8622
|
-
|
|
8615
|
+
chalk30.dim(` ${issue.path.join(".")}: ${issue.message}`)
|
|
8623
8616
|
);
|
|
8624
8617
|
}
|
|
8625
8618
|
process.exit(1);
|
|
@@ -8627,18 +8620,18 @@ var deployCommand = new Command28().name("deploy").description("Deploy a schedul
|
|
|
8627
8620
|
const scheduleYaml = result.data;
|
|
8628
8621
|
const scheduleEntries = Object.entries(scheduleYaml.schedules);
|
|
8629
8622
|
if (scheduleEntries.length === 0) {
|
|
8630
|
-
console.error(
|
|
8623
|
+
console.error(chalk30.red("\u2717 No schedules defined in file"));
|
|
8631
8624
|
process.exit(1);
|
|
8632
8625
|
}
|
|
8633
8626
|
if (scheduleEntries.length > 1) {
|
|
8634
8627
|
console.error(
|
|
8635
|
-
|
|
8628
|
+
chalk30.red("\u2717 Multiple schedules per file not supported yet")
|
|
8636
8629
|
);
|
|
8637
|
-
console.error(
|
|
8630
|
+
console.error(chalk30.dim(" Please use one schedule per file"));
|
|
8638
8631
|
process.exit(1);
|
|
8639
8632
|
}
|
|
8640
8633
|
const [scheduleName, schedule] = scheduleEntries[0];
|
|
8641
|
-
console.log(`Deploying schedule ${
|
|
8634
|
+
console.log(`Deploying schedule ${chalk30.cyan(scheduleName)}...`);
|
|
8642
8635
|
const agentRef = schedule.run.agent;
|
|
8643
8636
|
let composeId;
|
|
8644
8637
|
try {
|
|
@@ -8647,8 +8640,8 @@ var deployCommand = new Command28().name("deploy").description("Deploy a schedul
|
|
|
8647
8640
|
const compose = await apiClient.getComposeByName(agentName);
|
|
8648
8641
|
composeId = compose.id;
|
|
8649
8642
|
} catch {
|
|
8650
|
-
console.error(
|
|
8651
|
-
console.error(
|
|
8643
|
+
console.error(chalk30.red(`\u2717 Agent not found: ${agentRef}`));
|
|
8644
|
+
console.error(chalk30.dim(" Make sure the agent is pushed first"));
|
|
8652
8645
|
process.exit(1);
|
|
8653
8646
|
}
|
|
8654
8647
|
const expandedVars = expandEnvVarsInObject(schedule.run.vars);
|
|
@@ -8677,33 +8670,39 @@ var deployCommand = new Command28().name("deploy").description("Deploy a schedul
|
|
|
8677
8670
|
const deployResult = await response.json();
|
|
8678
8671
|
if (deployResult.created) {
|
|
8679
8672
|
console.log(
|
|
8680
|
-
|
|
8673
|
+
chalk30.green(`\u2713 Created schedule ${chalk30.cyan(scheduleName)}`)
|
|
8681
8674
|
);
|
|
8682
8675
|
} else {
|
|
8683
8676
|
console.log(
|
|
8684
|
-
|
|
8677
|
+
chalk30.green(`\u2713 Updated schedule ${chalk30.cyan(scheduleName)}`)
|
|
8685
8678
|
);
|
|
8686
8679
|
}
|
|
8687
|
-
|
|
8688
|
-
const nextRun = new Date(deployResult.schedule.nextRunAt);
|
|
8689
|
-
console.log(chalk31.dim(` Next run: ${nextRun.toLocaleString()}`));
|
|
8690
|
-
}
|
|
8680
|
+
console.log(chalk30.dim(` Timezone: ${deployResult.schedule.timezone}`));
|
|
8691
8681
|
if (deployResult.schedule.cronExpression) {
|
|
8692
8682
|
console.log(
|
|
8693
|
-
|
|
8694
|
-
` Cron: ${deployResult.schedule.cronExpression} (${deployResult.schedule.timezone})`
|
|
8695
|
-
)
|
|
8683
|
+
chalk30.dim(` Cron: ${deployResult.schedule.cronExpression}`)
|
|
8696
8684
|
);
|
|
8685
|
+
if (deployResult.schedule.nextRunAt) {
|
|
8686
|
+
const nextRun = formatInTimezone(
|
|
8687
|
+
deployResult.schedule.nextRunAt,
|
|
8688
|
+
deployResult.schedule.timezone
|
|
8689
|
+
);
|
|
8690
|
+
console.log(chalk30.dim(` Next run: ${nextRun}`));
|
|
8691
|
+
}
|
|
8697
8692
|
} else if (deployResult.schedule.atTime) {
|
|
8698
|
-
|
|
8693
|
+
const atTime2 = formatInTimezone(
|
|
8694
|
+
deployResult.schedule.atTime,
|
|
8695
|
+
deployResult.schedule.timezone
|
|
8696
|
+
);
|
|
8697
|
+
console.log(chalk30.dim(` At: ${atTime2}`));
|
|
8699
8698
|
}
|
|
8700
8699
|
} catch (error) {
|
|
8701
|
-
console.error(
|
|
8700
|
+
console.error(chalk30.red("\u2717 Failed to deploy schedule"));
|
|
8702
8701
|
if (error instanceof Error) {
|
|
8703
8702
|
if (error.message.includes("Not authenticated")) {
|
|
8704
|
-
console.error(
|
|
8703
|
+
console.error(chalk30.dim(" Run: vm0 auth login"));
|
|
8705
8704
|
} else {
|
|
8706
|
-
console.error(
|
|
8705
|
+
console.error(chalk30.dim(` ${error.message}`));
|
|
8707
8706
|
}
|
|
8708
8707
|
}
|
|
8709
8708
|
process.exit(1);
|
|
@@ -8712,7 +8711,7 @@ var deployCommand = new Command28().name("deploy").description("Deploy a schedul
|
|
|
8712
8711
|
|
|
8713
8712
|
// src/commands/schedule/list.ts
|
|
8714
8713
|
import { Command as Command29 } from "commander";
|
|
8715
|
-
import
|
|
8714
|
+
import chalk31 from "chalk";
|
|
8716
8715
|
var listCommand4 = new Command29().name("list").alias("ls").description("List all schedules").action(async () => {
|
|
8717
8716
|
try {
|
|
8718
8717
|
const response = await apiClient.get("/api/agent/schedules");
|
|
@@ -8722,9 +8721,9 @@ var listCommand4 = new Command29().name("list").alias("ls").description("List al
|
|
|
8722
8721
|
}
|
|
8723
8722
|
const result = await response.json();
|
|
8724
8723
|
if (result.schedules.length === 0) {
|
|
8725
|
-
console.log(
|
|
8724
|
+
console.log(chalk31.dim("No schedules found"));
|
|
8726
8725
|
console.log(
|
|
8727
|
-
|
|
8726
|
+
chalk31.dim(" Create one with: vm0 schedule deploy schedule.yaml")
|
|
8728
8727
|
);
|
|
8729
8728
|
return;
|
|
8730
8729
|
}
|
|
@@ -8749,10 +8748,10 @@ var listCommand4 = new Command29().name("list").alias("ls").description("List al
|
|
|
8749
8748
|
"STATUS".padEnd(8),
|
|
8750
8749
|
"NEXT RUN"
|
|
8751
8750
|
].join(" ");
|
|
8752
|
-
console.log(
|
|
8751
|
+
console.log(chalk31.dim(header));
|
|
8753
8752
|
for (const schedule of result.schedules) {
|
|
8754
8753
|
const trigger = schedule.cronExpression ? `${schedule.cronExpression} (${schedule.timezone})` : schedule.atTime || "-";
|
|
8755
|
-
const status = schedule.enabled ?
|
|
8754
|
+
const status = schedule.enabled ? chalk31.green("enabled") : chalk31.yellow("disabled");
|
|
8756
8755
|
const nextRun = schedule.enabled ? formatRelativeTime2(schedule.nextRunAt) : "-";
|
|
8757
8756
|
const row = [
|
|
8758
8757
|
schedule.name.padEnd(nameWidth),
|
|
@@ -8765,12 +8764,12 @@ var listCommand4 = new Command29().name("list").alias("ls").description("List al
|
|
|
8765
8764
|
console.log(row);
|
|
8766
8765
|
}
|
|
8767
8766
|
} catch (error) {
|
|
8768
|
-
console.error(
|
|
8767
|
+
console.error(chalk31.red("\u2717 Failed to list schedules"));
|
|
8769
8768
|
if (error instanceof Error) {
|
|
8770
8769
|
if (error.message.includes("Not authenticated")) {
|
|
8771
|
-
console.error(
|
|
8770
|
+
console.error(chalk31.dim(" Run: vm0 auth login"));
|
|
8772
8771
|
} else {
|
|
8773
|
-
console.error(
|
|
8772
|
+
console.error(chalk31.dim(` ${error.message}`));
|
|
8774
8773
|
}
|
|
8775
8774
|
}
|
|
8776
8775
|
process.exit(1);
|
|
@@ -8779,50 +8778,71 @@ var listCommand4 = new Command29().name("list").alias("ls").description("List al
|
|
|
8779
8778
|
|
|
8780
8779
|
// src/commands/schedule/status.ts
|
|
8781
8780
|
import { Command as Command30 } from "commander";
|
|
8782
|
-
import
|
|
8781
|
+
import chalk32 from "chalk";
|
|
8783
8782
|
function formatDateTimeStyled(dateStr) {
|
|
8784
|
-
if (!dateStr) return
|
|
8783
|
+
if (!dateStr) return chalk32.dim("-");
|
|
8785
8784
|
const formatted = formatDateTime(dateStr);
|
|
8786
|
-
return formatted.replace(/\(([^)]+)\)$/,
|
|
8785
|
+
return formatted.replace(/\(([^)]+)\)$/, chalk32.dim("($1)"));
|
|
8787
8786
|
}
|
|
8788
8787
|
function formatTrigger(schedule) {
|
|
8789
8788
|
if (schedule.cronExpression) {
|
|
8790
8789
|
return schedule.cronExpression;
|
|
8791
8790
|
}
|
|
8792
8791
|
if (schedule.atTime) {
|
|
8793
|
-
return `${schedule.atTime} ${
|
|
8792
|
+
return `${schedule.atTime} ${chalk32.dim("(one-time)")}`;
|
|
8794
8793
|
}
|
|
8795
|
-
return
|
|
8794
|
+
return chalk32.dim("-");
|
|
8796
8795
|
}
|
|
8797
8796
|
function formatRunStatus(status) {
|
|
8798
8797
|
switch (status) {
|
|
8799
8798
|
case "completed":
|
|
8800
|
-
return
|
|
8799
|
+
return chalk32.green(status);
|
|
8801
8800
|
case "failed":
|
|
8802
8801
|
case "timeout":
|
|
8803
|
-
return
|
|
8802
|
+
return chalk32.red(status);
|
|
8804
8803
|
case "running":
|
|
8805
|
-
return
|
|
8804
|
+
return chalk32.blue(status);
|
|
8806
8805
|
case "pending":
|
|
8807
|
-
return
|
|
8806
|
+
return chalk32.yellow(status);
|
|
8808
8807
|
default:
|
|
8809
8808
|
return status;
|
|
8810
8809
|
}
|
|
8811
8810
|
}
|
|
8812
|
-
var statusCommand4 = new Command30().name("status").description("Show detailed status of a schedule").argument(
|
|
8811
|
+
var statusCommand4 = new Command30().name("status").description("Show detailed status of a schedule").argument(
|
|
8812
|
+
"[name]",
|
|
8813
|
+
"Schedule name (auto-detected from schedule.yaml if omitted)"
|
|
8814
|
+
).option(
|
|
8813
8815
|
"-l, --limit <number>",
|
|
8814
8816
|
"Number of recent runs to show (0 to hide)",
|
|
8815
8817
|
"5"
|
|
8816
|
-
).action(async (
|
|
8818
|
+
).action(async (nameArg, options) => {
|
|
8817
8819
|
try {
|
|
8820
|
+
let name = nameArg;
|
|
8821
|
+
if (!name) {
|
|
8822
|
+
const scheduleResult = loadScheduleName();
|
|
8823
|
+
if (scheduleResult.error) {
|
|
8824
|
+
console.error(chalk32.red(`\u2717 ${scheduleResult.error}`));
|
|
8825
|
+
process.exit(1);
|
|
8826
|
+
}
|
|
8827
|
+
if (!scheduleResult.scheduleName) {
|
|
8828
|
+
console.error(chalk32.red("\u2717 Schedule name required"));
|
|
8829
|
+
console.error(
|
|
8830
|
+
chalk32.dim(
|
|
8831
|
+
" Provide name or run from directory with schedule.yaml"
|
|
8832
|
+
)
|
|
8833
|
+
);
|
|
8834
|
+
process.exit(1);
|
|
8835
|
+
}
|
|
8836
|
+
name = scheduleResult.scheduleName;
|
|
8837
|
+
}
|
|
8818
8838
|
const result = loadAgentName();
|
|
8819
8839
|
if (result.error) {
|
|
8820
|
-
console.error(
|
|
8840
|
+
console.error(chalk32.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
|
|
8821
8841
|
process.exit(1);
|
|
8822
8842
|
}
|
|
8823
8843
|
if (!result.agentName) {
|
|
8824
|
-
console.error(
|
|
8825
|
-
console.error(
|
|
8844
|
+
console.error(chalk32.red("\u2717 No vm0.yaml found in current directory"));
|
|
8845
|
+
console.error(chalk32.dim(" Run this command from the agent directory"));
|
|
8826
8846
|
process.exit(1);
|
|
8827
8847
|
}
|
|
8828
8848
|
const agentName = result.agentName;
|
|
@@ -8831,8 +8851,8 @@ var statusCommand4 = new Command30().name("status").description("Show detailed s
|
|
|
8831
8851
|
const compose = await apiClient.getComposeByName(agentName);
|
|
8832
8852
|
composeId = compose.id;
|
|
8833
8853
|
} catch {
|
|
8834
|
-
console.error(
|
|
8835
|
-
console.error(
|
|
8854
|
+
console.error(chalk32.red(`\u2717 Agent not found: ${agentName}`));
|
|
8855
|
+
console.error(chalk32.dim(" Make sure the agent is pushed first"));
|
|
8836
8856
|
process.exit(1);
|
|
8837
8857
|
}
|
|
8838
8858
|
const response = await apiClient.get(
|
|
@@ -8844,15 +8864,15 @@ var statusCommand4 = new Command30().name("status").description("Show detailed s
|
|
|
8844
8864
|
}
|
|
8845
8865
|
const schedule = await response.json();
|
|
8846
8866
|
console.log();
|
|
8847
|
-
console.log(`Schedule: ${
|
|
8848
|
-
console.log(
|
|
8849
|
-
const statusText = schedule.enabled ?
|
|
8867
|
+
console.log(`Schedule: ${chalk32.cyan(schedule.name)}`);
|
|
8868
|
+
console.log(chalk32.dim("\u2501".repeat(50)));
|
|
8869
|
+
const statusText = schedule.enabled ? chalk32.green("enabled") : chalk32.yellow("disabled");
|
|
8850
8870
|
console.log(`${"Status:".padEnd(16)}${statusText}`);
|
|
8851
8871
|
console.log(
|
|
8852
|
-
`${"Agent:".padEnd(16)}${schedule.composeName} ${
|
|
8872
|
+
`${"Agent:".padEnd(16)}${schedule.composeName} ${chalk32.dim(`(${schedule.scopeSlug})`)}`
|
|
8853
8873
|
);
|
|
8854
8874
|
const promptPreview = schedule.prompt.length > 60 ? schedule.prompt.slice(0, 57) + "..." : schedule.prompt;
|
|
8855
|
-
console.log(`${"Prompt:".padEnd(16)}${
|
|
8875
|
+
console.log(`${"Prompt:".padEnd(16)}${chalk32.dim(promptPreview)}`);
|
|
8856
8876
|
if (schedule.vars && Object.keys(schedule.vars).length > 0) {
|
|
8857
8877
|
console.log(
|
|
8858
8878
|
`${"Variables:".padEnd(16)}${Object.keys(schedule.vars).join(", ")}`
|
|
@@ -8894,7 +8914,7 @@ var statusCommand4 = new Command30().name("status").description("Show detailed s
|
|
|
8894
8914
|
console.log();
|
|
8895
8915
|
console.log("Recent Runs:");
|
|
8896
8916
|
console.log(
|
|
8897
|
-
|
|
8917
|
+
chalk32.dim(
|
|
8898
8918
|
"RUN ID STATUS CREATED"
|
|
8899
8919
|
)
|
|
8900
8920
|
);
|
|
@@ -8907,19 +8927,21 @@ var statusCommand4 = new Command30().name("status").description("Show detailed s
|
|
|
8907
8927
|
}
|
|
8908
8928
|
} else {
|
|
8909
8929
|
console.log();
|
|
8910
|
-
console.log(
|
|
8930
|
+
console.log(chalk32.dim("Recent Runs: (unable to fetch)"));
|
|
8911
8931
|
}
|
|
8912
8932
|
}
|
|
8913
8933
|
console.log();
|
|
8914
8934
|
} catch (error) {
|
|
8915
|
-
console.error(
|
|
8935
|
+
console.error(chalk32.red("\u2717 Failed to get schedule status"));
|
|
8916
8936
|
if (error instanceof Error) {
|
|
8917
8937
|
if (error.message.includes("Not authenticated")) {
|
|
8918
|
-
console.error(
|
|
8938
|
+
console.error(chalk32.dim(" Run: vm0 auth login"));
|
|
8919
8939
|
} else if (error.message.includes("not found") || error.message.includes("Not found")) {
|
|
8920
|
-
console.error(
|
|
8940
|
+
console.error(
|
|
8941
|
+
chalk32.dim(` Schedule "${nameArg ?? "unknown"}" not found`)
|
|
8942
|
+
);
|
|
8921
8943
|
} else {
|
|
8922
|
-
console.error(
|
|
8944
|
+
console.error(chalk32.dim(` ${error.message}`));
|
|
8923
8945
|
}
|
|
8924
8946
|
}
|
|
8925
8947
|
process.exit(1);
|
|
@@ -8928,7 +8950,7 @@ var statusCommand4 = new Command30().name("status").description("Show detailed s
|
|
|
8928
8950
|
|
|
8929
8951
|
// src/commands/schedule/delete.ts
|
|
8930
8952
|
import { Command as Command31 } from "commander";
|
|
8931
|
-
import
|
|
8953
|
+
import chalk33 from "chalk";
|
|
8932
8954
|
import * as readline from "readline";
|
|
8933
8955
|
async function confirm(message) {
|
|
8934
8956
|
const rl = readline.createInterface({
|
|
@@ -8942,16 +8964,37 @@ async function confirm(message) {
|
|
|
8942
8964
|
});
|
|
8943
8965
|
});
|
|
8944
8966
|
}
|
|
8945
|
-
var deleteCommand = new Command31().name("delete").alias("rm").description("Delete a schedule").argument(
|
|
8967
|
+
var deleteCommand = new Command31().name("delete").alias("rm").description("Delete a schedule").argument(
|
|
8968
|
+
"[name]",
|
|
8969
|
+
"Schedule name (auto-detected from schedule.yaml if omitted)"
|
|
8970
|
+
).option("-f, --force", "Skip confirmation prompt").action(async (nameArg, options) => {
|
|
8946
8971
|
try {
|
|
8972
|
+
let name = nameArg;
|
|
8973
|
+
if (!name) {
|
|
8974
|
+
const scheduleResult = loadScheduleName();
|
|
8975
|
+
if (scheduleResult.error) {
|
|
8976
|
+
console.error(chalk33.red(`\u2717 ${scheduleResult.error}`));
|
|
8977
|
+
process.exit(1);
|
|
8978
|
+
}
|
|
8979
|
+
if (!scheduleResult.scheduleName) {
|
|
8980
|
+
console.error(chalk33.red("\u2717 Schedule name required"));
|
|
8981
|
+
console.error(
|
|
8982
|
+
chalk33.dim(
|
|
8983
|
+
" Provide name or run from directory with schedule.yaml"
|
|
8984
|
+
)
|
|
8985
|
+
);
|
|
8986
|
+
process.exit(1);
|
|
8987
|
+
}
|
|
8988
|
+
name = scheduleResult.scheduleName;
|
|
8989
|
+
}
|
|
8947
8990
|
const result = loadAgentName();
|
|
8948
8991
|
if (result.error) {
|
|
8949
|
-
console.error(
|
|
8992
|
+
console.error(chalk33.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
|
|
8950
8993
|
process.exit(1);
|
|
8951
8994
|
}
|
|
8952
8995
|
if (!result.agentName) {
|
|
8953
|
-
console.error(
|
|
8954
|
-
console.error(
|
|
8996
|
+
console.error(chalk33.red("\u2717 No vm0.yaml found in current directory"));
|
|
8997
|
+
console.error(chalk33.dim(" Run this command from the agent directory"));
|
|
8955
8998
|
process.exit(1);
|
|
8956
8999
|
}
|
|
8957
9000
|
const agentName = result.agentName;
|
|
@@ -8960,14 +9003,14 @@ var deleteCommand = new Command31().name("delete").alias("rm").description("Dele
|
|
|
8960
9003
|
const compose = await apiClient.getComposeByName(agentName);
|
|
8961
9004
|
composeId = compose.id;
|
|
8962
9005
|
} catch {
|
|
8963
|
-
console.error(
|
|
8964
|
-
console.error(
|
|
9006
|
+
console.error(chalk33.red(`\u2717 Agent not found: ${agentName}`));
|
|
9007
|
+
console.error(chalk33.dim(" Make sure the agent is pushed first"));
|
|
8965
9008
|
process.exit(1);
|
|
8966
9009
|
}
|
|
8967
9010
|
if (!options.force) {
|
|
8968
|
-
const confirmed = await confirm(`Delete schedule ${
|
|
9011
|
+
const confirmed = await confirm(`Delete schedule ${chalk33.cyan(name)}?`);
|
|
8969
9012
|
if (!confirmed) {
|
|
8970
|
-
console.log(
|
|
9013
|
+
console.log(chalk33.dim("Cancelled"));
|
|
8971
9014
|
return;
|
|
8972
9015
|
}
|
|
8973
9016
|
}
|
|
@@ -8978,14 +9021,14 @@ var deleteCommand = new Command31().name("delete").alias("rm").description("Dele
|
|
|
8978
9021
|
const error = await response.json();
|
|
8979
9022
|
throw new Error(error.error?.message || "Delete failed");
|
|
8980
9023
|
}
|
|
8981
|
-
console.log(
|
|
9024
|
+
console.log(chalk33.green(`\u2713 Deleted schedule ${chalk33.cyan(name)}`));
|
|
8982
9025
|
} catch (error) {
|
|
8983
|
-
console.error(
|
|
9026
|
+
console.error(chalk33.red("\u2717 Failed to delete schedule"));
|
|
8984
9027
|
if (error instanceof Error) {
|
|
8985
9028
|
if (error.message.includes("Not authenticated")) {
|
|
8986
|
-
console.error(
|
|
9029
|
+
console.error(chalk33.dim(" Run: vm0 auth login"));
|
|
8987
9030
|
} else {
|
|
8988
|
-
console.error(
|
|
9031
|
+
console.error(chalk33.dim(` ${error.message}`));
|
|
8989
9032
|
}
|
|
8990
9033
|
}
|
|
8991
9034
|
process.exit(1);
|
|
@@ -8994,17 +9037,38 @@ var deleteCommand = new Command31().name("delete").alias("rm").description("Dele
|
|
|
8994
9037
|
|
|
8995
9038
|
// src/commands/schedule/enable.ts
|
|
8996
9039
|
import { Command as Command32 } from "commander";
|
|
8997
|
-
import
|
|
8998
|
-
var enableCommand = new Command32().name("enable").description("Enable a schedule").argument(
|
|
9040
|
+
import chalk34 from "chalk";
|
|
9041
|
+
var enableCommand = new Command32().name("enable").description("Enable a schedule").argument(
|
|
9042
|
+
"[name]",
|
|
9043
|
+
"Schedule name (auto-detected from schedule.yaml if omitted)"
|
|
9044
|
+
).action(async (nameArg) => {
|
|
8999
9045
|
try {
|
|
9046
|
+
let name = nameArg;
|
|
9047
|
+
if (!name) {
|
|
9048
|
+
const scheduleResult = loadScheduleName();
|
|
9049
|
+
if (scheduleResult.error) {
|
|
9050
|
+
console.error(chalk34.red(`\u2717 ${scheduleResult.error}`));
|
|
9051
|
+
process.exit(1);
|
|
9052
|
+
}
|
|
9053
|
+
if (!scheduleResult.scheduleName) {
|
|
9054
|
+
console.error(chalk34.red("\u2717 Schedule name required"));
|
|
9055
|
+
console.error(
|
|
9056
|
+
chalk34.dim(
|
|
9057
|
+
" Provide name or run from directory with schedule.yaml"
|
|
9058
|
+
)
|
|
9059
|
+
);
|
|
9060
|
+
process.exit(1);
|
|
9061
|
+
}
|
|
9062
|
+
name = scheduleResult.scheduleName;
|
|
9063
|
+
}
|
|
9000
9064
|
const result = loadAgentName();
|
|
9001
9065
|
if (result.error) {
|
|
9002
|
-
console.error(
|
|
9066
|
+
console.error(chalk34.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
|
|
9003
9067
|
process.exit(1);
|
|
9004
9068
|
}
|
|
9005
9069
|
if (!result.agentName) {
|
|
9006
|
-
console.error(
|
|
9007
|
-
console.error(
|
|
9070
|
+
console.error(chalk34.red("\u2717 No vm0.yaml found in current directory"));
|
|
9071
|
+
console.error(chalk34.dim(" Run this command from the agent directory"));
|
|
9008
9072
|
process.exit(1);
|
|
9009
9073
|
}
|
|
9010
9074
|
const agentName = result.agentName;
|
|
@@ -9013,8 +9077,8 @@ var enableCommand = new Command32().name("enable").description("Enable a schedul
|
|
|
9013
9077
|
const compose = await apiClient.getComposeByName(agentName);
|
|
9014
9078
|
composeId = compose.id;
|
|
9015
9079
|
} catch {
|
|
9016
|
-
console.error(
|
|
9017
|
-
console.error(
|
|
9080
|
+
console.error(chalk34.red(`\u2717 Agent not found: ${agentName}`));
|
|
9081
|
+
console.error(chalk34.dim(" Make sure the agent is pushed first"));
|
|
9018
9082
|
process.exit(1);
|
|
9019
9083
|
}
|
|
9020
9084
|
const response = await apiClient.post(
|
|
@@ -9025,14 +9089,14 @@ var enableCommand = new Command32().name("enable").description("Enable a schedul
|
|
|
9025
9089
|
const error = await response.json();
|
|
9026
9090
|
throw new Error(error.error?.message || "Enable failed");
|
|
9027
9091
|
}
|
|
9028
|
-
console.log(
|
|
9092
|
+
console.log(chalk34.green(`\u2713 Enabled schedule ${chalk34.cyan(name)}`));
|
|
9029
9093
|
} catch (error) {
|
|
9030
|
-
console.error(
|
|
9094
|
+
console.error(chalk34.red("\u2717 Failed to enable schedule"));
|
|
9031
9095
|
if (error instanceof Error) {
|
|
9032
9096
|
if (error.message.includes("Not authenticated")) {
|
|
9033
|
-
console.error(
|
|
9097
|
+
console.error(chalk34.dim(" Run: vm0 auth login"));
|
|
9034
9098
|
} else {
|
|
9035
|
-
console.error(
|
|
9099
|
+
console.error(chalk34.dim(` ${error.message}`));
|
|
9036
9100
|
}
|
|
9037
9101
|
}
|
|
9038
9102
|
process.exit(1);
|
|
@@ -9041,17 +9105,38 @@ var enableCommand = new Command32().name("enable").description("Enable a schedul
|
|
|
9041
9105
|
|
|
9042
9106
|
// src/commands/schedule/disable.ts
|
|
9043
9107
|
import { Command as Command33 } from "commander";
|
|
9044
|
-
import
|
|
9045
|
-
var disableCommand = new Command33().name("disable").description("Disable a schedule").argument(
|
|
9108
|
+
import chalk35 from "chalk";
|
|
9109
|
+
var disableCommand = new Command33().name("disable").description("Disable a schedule").argument(
|
|
9110
|
+
"[name]",
|
|
9111
|
+
"Schedule name (auto-detected from schedule.yaml if omitted)"
|
|
9112
|
+
).action(async (nameArg) => {
|
|
9046
9113
|
try {
|
|
9114
|
+
let name = nameArg;
|
|
9115
|
+
if (!name) {
|
|
9116
|
+
const scheduleResult = loadScheduleName();
|
|
9117
|
+
if (scheduleResult.error) {
|
|
9118
|
+
console.error(chalk35.red(`\u2717 ${scheduleResult.error}`));
|
|
9119
|
+
process.exit(1);
|
|
9120
|
+
}
|
|
9121
|
+
if (!scheduleResult.scheduleName) {
|
|
9122
|
+
console.error(chalk35.red("\u2717 Schedule name required"));
|
|
9123
|
+
console.error(
|
|
9124
|
+
chalk35.dim(
|
|
9125
|
+
" Provide name or run from directory with schedule.yaml"
|
|
9126
|
+
)
|
|
9127
|
+
);
|
|
9128
|
+
process.exit(1);
|
|
9129
|
+
}
|
|
9130
|
+
name = scheduleResult.scheduleName;
|
|
9131
|
+
}
|
|
9047
9132
|
const result = loadAgentName();
|
|
9048
9133
|
if (result.error) {
|
|
9049
|
-
console.error(
|
|
9134
|
+
console.error(chalk35.red(`\u2717 Invalid vm0.yaml: ${result.error}`));
|
|
9050
9135
|
process.exit(1);
|
|
9051
9136
|
}
|
|
9052
9137
|
if (!result.agentName) {
|
|
9053
|
-
console.error(
|
|
9054
|
-
console.error(
|
|
9138
|
+
console.error(chalk35.red("\u2717 No vm0.yaml found in current directory"));
|
|
9139
|
+
console.error(chalk35.dim(" Run this command from the agent directory"));
|
|
9055
9140
|
process.exit(1);
|
|
9056
9141
|
}
|
|
9057
9142
|
const agentName = result.agentName;
|
|
@@ -9060,8 +9145,8 @@ var disableCommand = new Command33().name("disable").description("Disable a sche
|
|
|
9060
9145
|
const compose = await apiClient.getComposeByName(agentName);
|
|
9061
9146
|
composeId = compose.id;
|
|
9062
9147
|
} catch {
|
|
9063
|
-
console.error(
|
|
9064
|
-
console.error(
|
|
9148
|
+
console.error(chalk35.red(`\u2717 Agent not found: ${agentName}`));
|
|
9149
|
+
console.error(chalk35.dim(" Make sure the agent is pushed first"));
|
|
9065
9150
|
process.exit(1);
|
|
9066
9151
|
}
|
|
9067
9152
|
const response = await apiClient.post(
|
|
@@ -9072,14 +9157,14 @@ var disableCommand = new Command33().name("disable").description("Disable a sche
|
|
|
9072
9157
|
const error = await response.json();
|
|
9073
9158
|
throw new Error(error.error?.message || "Disable failed");
|
|
9074
9159
|
}
|
|
9075
|
-
console.log(
|
|
9160
|
+
console.log(chalk35.green(`\u2713 Disabled schedule ${chalk35.cyan(name)}`));
|
|
9076
9161
|
} catch (error) {
|
|
9077
|
-
console.error(
|
|
9162
|
+
console.error(chalk35.red("\u2717 Failed to disable schedule"));
|
|
9078
9163
|
if (error instanceof Error) {
|
|
9079
9164
|
if (error.message.includes("Not authenticated")) {
|
|
9080
|
-
console.error(
|
|
9165
|
+
console.error(chalk35.dim(" Run: vm0 auth login"));
|
|
9081
9166
|
} else {
|
|
9082
|
-
console.error(
|
|
9167
|
+
console.error(chalk35.dim(` ${error.message}`));
|
|
9083
9168
|
}
|
|
9084
9169
|
}
|
|
9085
9170
|
process.exit(1);
|
|
@@ -9091,9 +9176,9 @@ var scheduleCommand = new Command34().name("schedule").description("Manage agent
|
|
|
9091
9176
|
|
|
9092
9177
|
// src/index.ts
|
|
9093
9178
|
var program = new Command35();
|
|
9094
|
-
program.name("vm0").description("VM0 CLI - A modern build tool").version("5.
|
|
9179
|
+
program.name("vm0").description("VM0 CLI - A modern build tool").version("5.7.0");
|
|
9095
9180
|
program.command("info").description("Display environment information").action(async () => {
|
|
9096
|
-
console.log(
|
|
9181
|
+
console.log(chalk36.bold("System Information:"));
|
|
9097
9182
|
console.log(`Node Version: ${process.version}`);
|
|
9098
9183
|
console.log(`Platform: ${process.platform}`);
|
|
9099
9184
|
console.log(`Architecture: ${process.arch}`);
|