@vm0/cli 4.13.1 → 4.14.1
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 +323 -188
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -6,8 +6,8 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
-
import { Command as
|
|
10
|
-
import
|
|
9
|
+
import { Command as Command19 } from "commander";
|
|
10
|
+
import chalk20 from "chalk";
|
|
11
11
|
|
|
12
12
|
// src/lib/auth.ts
|
|
13
13
|
import chalk from "chalk";
|
|
@@ -1011,7 +1011,6 @@ async function directUpload(storageName, storageType, cwd, options) {
|
|
|
1011
1011
|
const files = await getAllFiles(cwd);
|
|
1012
1012
|
onProgress?.("Computing file hashes...");
|
|
1013
1013
|
const fileEntries = await collectFileMetadata(cwd, files, onProgress);
|
|
1014
|
-
const totalSize = fileEntries.reduce((sum, f) => sum + f.size, 0);
|
|
1015
1014
|
onProgress?.("Preparing upload...");
|
|
1016
1015
|
const prepareResponse = await apiClient.post("/api/storages/prepare", {
|
|
1017
1016
|
body: JSON.stringify({
|
|
@@ -1027,12 +1026,26 @@ async function directUpload(storageName, storageType, cwd, options) {
|
|
|
1027
1026
|
}
|
|
1028
1027
|
const prepareResult = await prepareResponse.json();
|
|
1029
1028
|
if (prepareResult.existing) {
|
|
1029
|
+
onProgress?.("Version exists, updating HEAD...");
|
|
1030
|
+
const commitResponse2 = await apiClient.post("/api/storages/commit", {
|
|
1031
|
+
body: JSON.stringify({
|
|
1032
|
+
storageName,
|
|
1033
|
+
storageType,
|
|
1034
|
+
versionId: prepareResult.versionId,
|
|
1035
|
+
files: fileEntries
|
|
1036
|
+
})
|
|
1037
|
+
});
|
|
1038
|
+
if (!commitResponse2.ok) {
|
|
1039
|
+
const error43 = await commitResponse2.json();
|
|
1040
|
+
throw new Error(error43.error?.message || "Commit failed");
|
|
1041
|
+
}
|
|
1042
|
+
const commitResult2 = await commitResponse2.json();
|
|
1030
1043
|
return {
|
|
1031
|
-
versionId:
|
|
1032
|
-
size:
|
|
1033
|
-
fileCount:
|
|
1044
|
+
versionId: commitResult2.versionId,
|
|
1045
|
+
size: commitResult2.size,
|
|
1046
|
+
fileCount: commitResult2.fileCount,
|
|
1034
1047
|
deduplicated: true,
|
|
1035
|
-
empty:
|
|
1048
|
+
empty: commitResult2.fileCount === 0
|
|
1036
1049
|
};
|
|
1037
1050
|
}
|
|
1038
1051
|
if (files.length > 0) {
|
|
@@ -15258,7 +15271,7 @@ runCmd.command("continue").description(
|
|
|
15258
15271
|
var runCommand = runCmd;
|
|
15259
15272
|
|
|
15260
15273
|
// src/commands/volume/index.ts
|
|
15261
|
-
import { Command as
|
|
15274
|
+
import { Command as Command7 } from "commander";
|
|
15262
15275
|
|
|
15263
15276
|
// src/commands/volume/init.ts
|
|
15264
15277
|
import { Command as Command3 } from "commander";
|
|
@@ -15520,17 +15533,78 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
15520
15533
|
}
|
|
15521
15534
|
});
|
|
15522
15535
|
|
|
15536
|
+
// src/commands/volume/status.ts
|
|
15537
|
+
import { Command as Command6 } from "commander";
|
|
15538
|
+
import chalk9 from "chalk";
|
|
15539
|
+
function formatBytes3(bytes) {
|
|
15540
|
+
if (bytes === 0) return "0 B";
|
|
15541
|
+
const k = 1024;
|
|
15542
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
15543
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
15544
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
15545
|
+
}
|
|
15546
|
+
var statusCommand = new Command6().name("status").description("Show status of cloud volume").action(async () => {
|
|
15547
|
+
try {
|
|
15548
|
+
const cwd = process.cwd();
|
|
15549
|
+
const config2 = await readStorageConfig(cwd);
|
|
15550
|
+
if (!config2) {
|
|
15551
|
+
console.error(chalk9.red("\u2717 No volume initialized in this directory"));
|
|
15552
|
+
console.error(chalk9.gray(" Run: vm0 volume init"));
|
|
15553
|
+
process.exit(1);
|
|
15554
|
+
}
|
|
15555
|
+
if (config2.type !== "volume") {
|
|
15556
|
+
console.error(
|
|
15557
|
+
chalk9.red(
|
|
15558
|
+
"\u2717 This directory is initialized as an artifact, not a volume"
|
|
15559
|
+
)
|
|
15560
|
+
);
|
|
15561
|
+
console.error(chalk9.gray(" Use: vm0 artifact status"));
|
|
15562
|
+
process.exit(1);
|
|
15563
|
+
}
|
|
15564
|
+
console.log(chalk9.cyan(`Checking volume: ${config2.name}`));
|
|
15565
|
+
const url2 = `/api/storages/download?name=${encodeURIComponent(config2.name)}&type=volume`;
|
|
15566
|
+
const response = await apiClient.get(url2);
|
|
15567
|
+
if (!response.ok) {
|
|
15568
|
+
if (response.status === 404) {
|
|
15569
|
+
console.error(chalk9.red("\u2717 Not found on remote"));
|
|
15570
|
+
console.error(chalk9.gray(" Run: vm0 volume push"));
|
|
15571
|
+
} else {
|
|
15572
|
+
const error43 = await response.json();
|
|
15573
|
+
throw new Error(error43.error?.message || "Status check failed");
|
|
15574
|
+
}
|
|
15575
|
+
process.exit(1);
|
|
15576
|
+
}
|
|
15577
|
+
const info = await response.json();
|
|
15578
|
+
const shortVersion = info.versionId.slice(0, 8);
|
|
15579
|
+
if (info.empty) {
|
|
15580
|
+
console.log(chalk9.green("\u2713 Found (empty)"));
|
|
15581
|
+
console.log(chalk9.gray(` Version: ${shortVersion}`));
|
|
15582
|
+
} else {
|
|
15583
|
+
console.log(chalk9.green("\u2713 Found"));
|
|
15584
|
+
console.log(chalk9.gray(` Version: ${shortVersion}`));
|
|
15585
|
+
console.log(chalk9.gray(` Files: ${info.fileCount.toLocaleString()}`));
|
|
15586
|
+
console.log(chalk9.gray(` Size: ${formatBytes3(info.size)}`));
|
|
15587
|
+
}
|
|
15588
|
+
} catch (error43) {
|
|
15589
|
+
console.error(chalk9.red("\u2717 Status check failed"));
|
|
15590
|
+
if (error43 instanceof Error) {
|
|
15591
|
+
console.error(chalk9.gray(` ${error43.message}`));
|
|
15592
|
+
}
|
|
15593
|
+
process.exit(1);
|
|
15594
|
+
}
|
|
15595
|
+
});
|
|
15596
|
+
|
|
15523
15597
|
// src/commands/volume/index.ts
|
|
15524
|
-
var volumeCommand = new
|
|
15598
|
+
var volumeCommand = new Command7().name("volume").description("Manage cloud volumes").addCommand(initCommand).addCommand(pushCommand).addCommand(pullCommand).addCommand(statusCommand);
|
|
15525
15599
|
|
|
15526
15600
|
// src/commands/artifact/index.ts
|
|
15527
|
-
import { Command as
|
|
15601
|
+
import { Command as Command12 } from "commander";
|
|
15528
15602
|
|
|
15529
15603
|
// src/commands/artifact/init.ts
|
|
15530
|
-
import { Command as
|
|
15531
|
-
import
|
|
15604
|
+
import { Command as Command8 } from "commander";
|
|
15605
|
+
import chalk10 from "chalk";
|
|
15532
15606
|
import path9 from "path";
|
|
15533
|
-
var initCommand2 = new
|
|
15607
|
+
var initCommand2 = new Command8().name("init").description("Initialize an artifact in the current directory").action(async () => {
|
|
15534
15608
|
try {
|
|
15535
15609
|
const cwd = process.cwd();
|
|
15536
15610
|
const dirName = path9.basename(cwd);
|
|
@@ -15538,67 +15612,67 @@ var initCommand2 = new Command7().name("init").description("Initialize an artifa
|
|
|
15538
15612
|
if (existingConfig) {
|
|
15539
15613
|
if (existingConfig.type === "artifact") {
|
|
15540
15614
|
console.log(
|
|
15541
|
-
|
|
15615
|
+
chalk10.yellow(
|
|
15542
15616
|
`Artifact already initialized: ${existingConfig.name}`
|
|
15543
15617
|
)
|
|
15544
15618
|
);
|
|
15545
15619
|
} else {
|
|
15546
15620
|
console.log(
|
|
15547
|
-
|
|
15621
|
+
chalk10.yellow(
|
|
15548
15622
|
`Directory already initialized as volume: ${existingConfig.name}`
|
|
15549
15623
|
)
|
|
15550
15624
|
);
|
|
15551
15625
|
console.log(
|
|
15552
|
-
|
|
15626
|
+
chalk10.gray(
|
|
15553
15627
|
" To change type, delete .vm0/storage.yaml and reinitialize"
|
|
15554
15628
|
)
|
|
15555
15629
|
);
|
|
15556
15630
|
}
|
|
15557
15631
|
console.log(
|
|
15558
|
-
|
|
15632
|
+
chalk10.gray(`Config file: ${path9.join(cwd, ".vm0", "storage.yaml")}`)
|
|
15559
15633
|
);
|
|
15560
15634
|
return;
|
|
15561
15635
|
}
|
|
15562
15636
|
const artifactName = dirName;
|
|
15563
15637
|
if (!isValidStorageName(artifactName)) {
|
|
15564
|
-
console.error(
|
|
15638
|
+
console.error(chalk10.red(`\u2717 Invalid artifact name: "${dirName}"`));
|
|
15565
15639
|
console.error(
|
|
15566
|
-
|
|
15640
|
+
chalk10.gray(
|
|
15567
15641
|
" Artifact names must be 3-64 characters, lowercase alphanumeric with hyphens"
|
|
15568
15642
|
)
|
|
15569
15643
|
);
|
|
15570
15644
|
console.error(
|
|
15571
|
-
|
|
15645
|
+
chalk10.gray(" Example: my-project, user-workspace, code-artifact")
|
|
15572
15646
|
);
|
|
15573
15647
|
process.exit(1);
|
|
15574
15648
|
}
|
|
15575
15649
|
await writeStorageConfig(artifactName, cwd, "artifact");
|
|
15576
|
-
console.log(
|
|
15650
|
+
console.log(chalk10.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
15577
15651
|
console.log(
|
|
15578
|
-
|
|
15652
|
+
chalk10.gray(
|
|
15579
15653
|
`\u2713 Config saved to ${path9.join(cwd, ".vm0", "storage.yaml")}`
|
|
15580
15654
|
)
|
|
15581
15655
|
);
|
|
15582
15656
|
} catch (error43) {
|
|
15583
|
-
console.error(
|
|
15657
|
+
console.error(chalk10.red("\u2717 Failed to initialize artifact"));
|
|
15584
15658
|
if (error43 instanceof Error) {
|
|
15585
|
-
console.error(
|
|
15659
|
+
console.error(chalk10.gray(` ${error43.message}`));
|
|
15586
15660
|
}
|
|
15587
15661
|
process.exit(1);
|
|
15588
15662
|
}
|
|
15589
15663
|
});
|
|
15590
15664
|
|
|
15591
15665
|
// src/commands/artifact/push.ts
|
|
15592
|
-
import { Command as
|
|
15593
|
-
import
|
|
15594
|
-
function
|
|
15666
|
+
import { Command as Command9 } from "commander";
|
|
15667
|
+
import chalk11 from "chalk";
|
|
15668
|
+
function formatBytes4(bytes) {
|
|
15595
15669
|
if (bytes === 0) return "0 B";
|
|
15596
15670
|
const k = 1024;
|
|
15597
15671
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
15598
15672
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
15599
15673
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
15600
15674
|
}
|
|
15601
|
-
var pushCommand2 = new
|
|
15675
|
+
var pushCommand2 = new Command9().name("push").description("Push local files to cloud artifact").option(
|
|
15602
15676
|
"-f, --force",
|
|
15603
15677
|
"Force upload even if content unchanged (recreate archive)"
|
|
15604
15678
|
).action(async (options) => {
|
|
@@ -15606,88 +15680,88 @@ var pushCommand2 = new Command8().name("push").description("Push local files to
|
|
|
15606
15680
|
const cwd = process.cwd();
|
|
15607
15681
|
const config2 = await readStorageConfig(cwd);
|
|
15608
15682
|
if (!config2) {
|
|
15609
|
-
console.error(
|
|
15610
|
-
console.error(
|
|
15683
|
+
console.error(chalk11.red("\u2717 No artifact initialized in this directory"));
|
|
15684
|
+
console.error(chalk11.gray(" Run: vm0 artifact init"));
|
|
15611
15685
|
process.exit(1);
|
|
15612
15686
|
}
|
|
15613
15687
|
if (config2.type !== "artifact") {
|
|
15614
15688
|
console.error(
|
|
15615
|
-
|
|
15689
|
+
chalk11.red(
|
|
15616
15690
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
15617
15691
|
)
|
|
15618
15692
|
);
|
|
15619
|
-
console.error(
|
|
15693
|
+
console.error(chalk11.gray(" Use: vm0 volume push"));
|
|
15620
15694
|
process.exit(1);
|
|
15621
15695
|
}
|
|
15622
|
-
console.log(
|
|
15696
|
+
console.log(chalk11.cyan(`Pushing artifact: ${config2.name}`));
|
|
15623
15697
|
const result = await directUpload(config2.name, "artifact", cwd, {
|
|
15624
15698
|
onProgress: (message) => {
|
|
15625
|
-
console.log(
|
|
15699
|
+
console.log(chalk11.gray(message));
|
|
15626
15700
|
},
|
|
15627
15701
|
force: options.force
|
|
15628
15702
|
});
|
|
15629
15703
|
const shortVersion = result.versionId.slice(0, 8);
|
|
15630
15704
|
if (result.empty) {
|
|
15631
|
-
console.log(
|
|
15705
|
+
console.log(chalk11.yellow("No files found (empty artifact)"));
|
|
15632
15706
|
} else if (result.deduplicated) {
|
|
15633
|
-
console.log(
|
|
15707
|
+
console.log(chalk11.green("\u2713 Content unchanged (deduplicated)"));
|
|
15634
15708
|
} else {
|
|
15635
|
-
console.log(
|
|
15709
|
+
console.log(chalk11.green("\u2713 Upload complete"));
|
|
15636
15710
|
}
|
|
15637
|
-
console.log(
|
|
15638
|
-
console.log(
|
|
15639
|
-
console.log(
|
|
15711
|
+
console.log(chalk11.gray(` Version: ${shortVersion}`));
|
|
15712
|
+
console.log(chalk11.gray(` Files: ${result.fileCount.toLocaleString()}`));
|
|
15713
|
+
console.log(chalk11.gray(` Size: ${formatBytes4(result.size)}`));
|
|
15640
15714
|
} catch (error43) {
|
|
15641
|
-
console.error(
|
|
15715
|
+
console.error(chalk11.red("\u2717 Push failed"));
|
|
15642
15716
|
if (error43 instanceof Error) {
|
|
15643
|
-
console.error(
|
|
15717
|
+
console.error(chalk11.gray(` ${error43.message}`));
|
|
15644
15718
|
}
|
|
15645
15719
|
process.exit(1);
|
|
15646
15720
|
}
|
|
15647
15721
|
});
|
|
15648
15722
|
|
|
15649
15723
|
// src/commands/artifact/pull.ts
|
|
15650
|
-
import { Command as
|
|
15651
|
-
import
|
|
15724
|
+
import { Command as Command10 } from "commander";
|
|
15725
|
+
import chalk12 from "chalk";
|
|
15652
15726
|
import path10 from "path";
|
|
15653
15727
|
import * as fs7 from "fs";
|
|
15654
15728
|
import * as os5 from "os";
|
|
15655
15729
|
import * as tar4 from "tar";
|
|
15656
|
-
function
|
|
15730
|
+
function formatBytes5(bytes) {
|
|
15657
15731
|
if (bytes === 0) return "0 B";
|
|
15658
15732
|
const k = 1024;
|
|
15659
15733
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
15660
15734
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
15661
15735
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
15662
15736
|
}
|
|
15663
|
-
var pullCommand2 = new
|
|
15737
|
+
var pullCommand2 = new Command10().name("pull").description("Pull cloud artifact to local directory").argument("[versionId]", "Version ID to pull (default: latest)").action(async (versionId) => {
|
|
15664
15738
|
try {
|
|
15665
15739
|
const cwd = process.cwd();
|
|
15666
15740
|
const config2 = await readStorageConfig(cwd);
|
|
15667
15741
|
if (!config2) {
|
|
15668
|
-
console.error(
|
|
15669
|
-
console.error(
|
|
15742
|
+
console.error(chalk12.red("\u2717 No artifact initialized in this directory"));
|
|
15743
|
+
console.error(chalk12.gray(" Run: vm0 artifact init"));
|
|
15670
15744
|
process.exit(1);
|
|
15671
15745
|
}
|
|
15672
15746
|
if (config2.type !== "artifact") {
|
|
15673
15747
|
console.error(
|
|
15674
|
-
|
|
15748
|
+
chalk12.red(
|
|
15675
15749
|
`\u2717 This directory is initialized as a volume, not an artifact`
|
|
15676
15750
|
)
|
|
15677
15751
|
);
|
|
15678
|
-
console.error(
|
|
15752
|
+
console.error(chalk12.gray(" Use: vm0 volume pull"));
|
|
15679
15753
|
process.exit(1);
|
|
15680
15754
|
}
|
|
15681
15755
|
if (versionId) {
|
|
15682
15756
|
console.log(
|
|
15683
|
-
|
|
15757
|
+
chalk12.cyan(
|
|
15684
15758
|
`Pulling artifact: ${config2.name} (version: ${versionId})`
|
|
15685
15759
|
)
|
|
15686
15760
|
);
|
|
15687
15761
|
} else {
|
|
15688
|
-
console.log(
|
|
15762
|
+
console.log(chalk12.cyan(`Pulling artifact: ${config2.name}`));
|
|
15689
15763
|
}
|
|
15690
|
-
console.log(
|
|
15764
|
+
console.log(chalk12.gray("Getting download URL..."));
|
|
15691
15765
|
let url2 = `/api/storages/download?name=${encodeURIComponent(config2.name)}&type=artifact`;
|
|
15692
15766
|
if (versionId) {
|
|
15693
15767
|
url2 += `&version=${encodeURIComponent(versionId)}`;
|
|
@@ -15695,14 +15769,14 @@ var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact
|
|
|
15695
15769
|
const response = await apiClient.get(url2);
|
|
15696
15770
|
if (!response.ok) {
|
|
15697
15771
|
if (response.status === 404) {
|
|
15698
|
-
console.error(
|
|
15772
|
+
console.error(chalk12.red(`\u2717 Artifact "${config2.name}" not found`));
|
|
15699
15773
|
console.error(
|
|
15700
|
-
|
|
15774
|
+
chalk12.gray(
|
|
15701
15775
|
" Make sure the artifact name is correct in .vm0/storage.yaml"
|
|
15702
15776
|
)
|
|
15703
15777
|
);
|
|
15704
15778
|
console.error(
|
|
15705
|
-
|
|
15779
|
+
chalk12.gray(" Or push the artifact first with: vm0 artifact push")
|
|
15706
15780
|
);
|
|
15707
15781
|
} else {
|
|
15708
15782
|
const error43 = await response.json();
|
|
@@ -15718,18 +15792,18 @@ var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact
|
|
|
15718
15792
|
if (!downloadInfo.url) {
|
|
15719
15793
|
throw new Error("No download URL returned");
|
|
15720
15794
|
}
|
|
15721
|
-
console.log(
|
|
15795
|
+
console.log(chalk12.gray("Downloading from S3..."));
|
|
15722
15796
|
const s3Response = await fetch(downloadInfo.url);
|
|
15723
15797
|
if (!s3Response.ok) {
|
|
15724
15798
|
throw new Error(`S3 download failed: ${s3Response.status}`);
|
|
15725
15799
|
}
|
|
15726
15800
|
const arrayBuffer = await s3Response.arrayBuffer();
|
|
15727
15801
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
15728
|
-
console.log(
|
|
15802
|
+
console.log(chalk12.green(`\u2713 Downloaded ${formatBytes5(tarBuffer.length)}`));
|
|
15729
15803
|
const tmpDir = fs7.mkdtempSync(path10.join(os5.tmpdir(), "vm0-"));
|
|
15730
15804
|
const tarPath = path10.join(tmpDir, "artifact.tar.gz");
|
|
15731
15805
|
await fs7.promises.writeFile(tarPath, tarBuffer);
|
|
15732
|
-
console.log(
|
|
15806
|
+
console.log(chalk12.gray("Syncing local files..."));
|
|
15733
15807
|
const remoteFiles = await listTarFiles(tarPath);
|
|
15734
15808
|
const remoteFilesSet = new Set(
|
|
15735
15809
|
remoteFiles.map((f) => f.replace(/\\/g, "/"))
|
|
@@ -15737,10 +15811,10 @@ var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact
|
|
|
15737
15811
|
const removedCount = await removeExtraFiles(cwd, remoteFilesSet);
|
|
15738
15812
|
if (removedCount > 0) {
|
|
15739
15813
|
console.log(
|
|
15740
|
-
|
|
15814
|
+
chalk12.green(`\u2713 Removed ${removedCount} files not in remote`)
|
|
15741
15815
|
);
|
|
15742
15816
|
}
|
|
15743
|
-
console.log(
|
|
15817
|
+
console.log(chalk12.gray("Extracting files..."));
|
|
15744
15818
|
await tar4.extract({
|
|
15745
15819
|
file: tarPath,
|
|
15746
15820
|
cwd,
|
|
@@ -15748,22 +15822,83 @@ var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact
|
|
|
15748
15822
|
});
|
|
15749
15823
|
await fs7.promises.unlink(tarPath);
|
|
15750
15824
|
await fs7.promises.rmdir(tmpDir);
|
|
15751
|
-
console.log(
|
|
15825
|
+
console.log(chalk12.green(`\u2713 Extracted ${remoteFiles.length} files`));
|
|
15752
15826
|
} catch (error43) {
|
|
15753
|
-
console.error(
|
|
15827
|
+
console.error(chalk12.red("\u2717 Pull failed"));
|
|
15754
15828
|
if (error43 instanceof Error) {
|
|
15755
|
-
console.error(
|
|
15829
|
+
console.error(chalk12.gray(` ${error43.message}`));
|
|
15830
|
+
}
|
|
15831
|
+
process.exit(1);
|
|
15832
|
+
}
|
|
15833
|
+
});
|
|
15834
|
+
|
|
15835
|
+
// src/commands/artifact/status.ts
|
|
15836
|
+
import { Command as Command11 } from "commander";
|
|
15837
|
+
import chalk13 from "chalk";
|
|
15838
|
+
function formatBytes6(bytes) {
|
|
15839
|
+
if (bytes === 0) return "0 B";
|
|
15840
|
+
const k = 1024;
|
|
15841
|
+
const sizes = ["B", "KB", "MB", "GB"];
|
|
15842
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
15843
|
+
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
15844
|
+
}
|
|
15845
|
+
var statusCommand2 = new Command11().name("status").description("Show status of cloud artifact").action(async () => {
|
|
15846
|
+
try {
|
|
15847
|
+
const cwd = process.cwd();
|
|
15848
|
+
const config2 = await readStorageConfig(cwd);
|
|
15849
|
+
if (!config2) {
|
|
15850
|
+
console.error(chalk13.red("\u2717 No artifact initialized in this directory"));
|
|
15851
|
+
console.error(chalk13.gray(" Run: vm0 artifact init"));
|
|
15852
|
+
process.exit(1);
|
|
15853
|
+
}
|
|
15854
|
+
if (config2.type !== "artifact") {
|
|
15855
|
+
console.error(
|
|
15856
|
+
chalk13.red(
|
|
15857
|
+
"\u2717 This directory is initialized as a volume, not an artifact"
|
|
15858
|
+
)
|
|
15859
|
+
);
|
|
15860
|
+
console.error(chalk13.gray(" Use: vm0 volume status"));
|
|
15861
|
+
process.exit(1);
|
|
15862
|
+
}
|
|
15863
|
+
console.log(chalk13.cyan(`Checking artifact: ${config2.name}`));
|
|
15864
|
+
const url2 = `/api/storages/download?name=${encodeURIComponent(config2.name)}&type=artifact`;
|
|
15865
|
+
const response = await apiClient.get(url2);
|
|
15866
|
+
if (!response.ok) {
|
|
15867
|
+
if (response.status === 404) {
|
|
15868
|
+
console.error(chalk13.red("\u2717 Not found on remote"));
|
|
15869
|
+
console.error(chalk13.gray(" Run: vm0 artifact push"));
|
|
15870
|
+
} else {
|
|
15871
|
+
const error43 = await response.json();
|
|
15872
|
+
throw new Error(error43.error?.message || "Status check failed");
|
|
15873
|
+
}
|
|
15874
|
+
process.exit(1);
|
|
15875
|
+
}
|
|
15876
|
+
const info = await response.json();
|
|
15877
|
+
const shortVersion = info.versionId.slice(0, 8);
|
|
15878
|
+
if (info.empty) {
|
|
15879
|
+
console.log(chalk13.green("\u2713 Found (empty)"));
|
|
15880
|
+
console.log(chalk13.gray(` Version: ${shortVersion}`));
|
|
15881
|
+
} else {
|
|
15882
|
+
console.log(chalk13.green("\u2713 Found"));
|
|
15883
|
+
console.log(chalk13.gray(` Version: ${shortVersion}`));
|
|
15884
|
+
console.log(chalk13.gray(` Files: ${info.fileCount.toLocaleString()}`));
|
|
15885
|
+
console.log(chalk13.gray(` Size: ${formatBytes6(info.size)}`));
|
|
15886
|
+
}
|
|
15887
|
+
} catch (error43) {
|
|
15888
|
+
console.error(chalk13.red("\u2717 Status check failed"));
|
|
15889
|
+
if (error43 instanceof Error) {
|
|
15890
|
+
console.error(chalk13.gray(` ${error43.message}`));
|
|
15756
15891
|
}
|
|
15757
15892
|
process.exit(1);
|
|
15758
15893
|
}
|
|
15759
15894
|
});
|
|
15760
15895
|
|
|
15761
15896
|
// src/commands/artifact/index.ts
|
|
15762
|
-
var artifactCommand = new
|
|
15897
|
+
var artifactCommand = new Command12().name("artifact").description("Manage cloud artifacts (work products)").addCommand(initCommand2).addCommand(pushCommand2).addCommand(pullCommand2).addCommand(statusCommand2);
|
|
15763
15898
|
|
|
15764
15899
|
// src/commands/cook.ts
|
|
15765
|
-
import { Command as
|
|
15766
|
-
import
|
|
15900
|
+
import { Command as Command13 } from "commander";
|
|
15901
|
+
import chalk15 from "chalk";
|
|
15767
15902
|
import { readFile as readFile5, mkdir as mkdir5, writeFile as writeFile5, appendFile } from "fs/promises";
|
|
15768
15903
|
import { existsSync as existsSync6, readFileSync } from "fs";
|
|
15769
15904
|
import path11 from "path";
|
|
@@ -15774,7 +15909,7 @@ import { config as dotenvConfig2 } from "dotenv";
|
|
|
15774
15909
|
// src/lib/update-checker.ts
|
|
15775
15910
|
import https from "https";
|
|
15776
15911
|
import { spawn } from "child_process";
|
|
15777
|
-
import
|
|
15912
|
+
import chalk14 from "chalk";
|
|
15778
15913
|
var PACKAGE_NAME = "@vm0/cli";
|
|
15779
15914
|
var NPM_REGISTRY_URL = `https://registry.npmjs.org/${encodeURIComponent(PACKAGE_NAME)}/latest`;
|
|
15780
15915
|
var TIMEOUT_MS = 5e3;
|
|
@@ -15839,21 +15974,21 @@ function performUpgrade(packageManager) {
|
|
|
15839
15974
|
async function checkAndUpgrade(currentVersion, prompt) {
|
|
15840
15975
|
const latestVersion = await getLatestVersion();
|
|
15841
15976
|
if (latestVersion === null) {
|
|
15842
|
-
console.log(
|
|
15977
|
+
console.log(chalk14.yellow("Warning: Could not check for updates"));
|
|
15843
15978
|
console.log();
|
|
15844
15979
|
return false;
|
|
15845
15980
|
}
|
|
15846
15981
|
if (latestVersion === currentVersion) {
|
|
15847
15982
|
return false;
|
|
15848
15983
|
}
|
|
15849
|
-
console.log(
|
|
15984
|
+
console.log(chalk14.yellow("vm0 is currently in Early Access (EA)."));
|
|
15850
15985
|
console.log(
|
|
15851
|
-
|
|
15986
|
+
chalk14.yellow(
|
|
15852
15987
|
`Current version: ${currentVersion} -> Latest version: ${latestVersion}`
|
|
15853
15988
|
)
|
|
15854
15989
|
);
|
|
15855
15990
|
console.log(
|
|
15856
|
-
|
|
15991
|
+
chalk14.yellow(
|
|
15857
15992
|
"Please always use the latest version for best compatibility."
|
|
15858
15993
|
)
|
|
15859
15994
|
);
|
|
@@ -15862,20 +15997,20 @@ async function checkAndUpgrade(currentVersion, prompt) {
|
|
|
15862
15997
|
console.log(`Upgrading via ${packageManager}...`);
|
|
15863
15998
|
const success2 = await performUpgrade(packageManager);
|
|
15864
15999
|
if (success2) {
|
|
15865
|
-
console.log(
|
|
16000
|
+
console.log(chalk14.green(`Upgraded to ${latestVersion}`));
|
|
15866
16001
|
console.log();
|
|
15867
16002
|
console.log("To continue, run:");
|
|
15868
|
-
console.log(
|
|
16003
|
+
console.log(chalk14.cyan(` ${buildRerunCommand(prompt)}`));
|
|
15869
16004
|
return true;
|
|
15870
16005
|
}
|
|
15871
16006
|
console.log();
|
|
15872
|
-
console.log(
|
|
15873
|
-
console.log(
|
|
15874
|
-
console.log(
|
|
15875
|
-
console.log(
|
|
16007
|
+
console.log(chalk14.red("Upgrade failed. Please run manually:"));
|
|
16008
|
+
console.log(chalk14.cyan(` npm install -g ${PACKAGE_NAME}@latest`));
|
|
16009
|
+
console.log(chalk14.gray(" # or"));
|
|
16010
|
+
console.log(chalk14.cyan(` pnpm add -g ${PACKAGE_NAME}@latest`));
|
|
15876
16011
|
console.log();
|
|
15877
16012
|
console.log("Then re-run:");
|
|
15878
|
-
console.log(
|
|
16013
|
+
console.log(chalk14.cyan(` ${buildRerunCommand(prompt)}`));
|
|
15879
16014
|
return true;
|
|
15880
16015
|
}
|
|
15881
16016
|
|
|
@@ -15995,15 +16130,15 @@ async function generateEnvPlaceholders(missingVars, envFilePath) {
|
|
|
15995
16130
|
`);
|
|
15996
16131
|
}
|
|
15997
16132
|
}
|
|
15998
|
-
var cookCommand = new
|
|
15999
|
-
const shouldExit = await checkAndUpgrade("4.
|
|
16133
|
+
var cookCommand = new Command13().name("cook").description("One-click agent preparation and execution from vm0.yaml").argument("[prompt]", "Prompt for the agent").action(async (prompt) => {
|
|
16134
|
+
const shouldExit = await checkAndUpgrade("4.14.1", prompt);
|
|
16000
16135
|
if (shouldExit) {
|
|
16001
16136
|
process.exit(0);
|
|
16002
16137
|
}
|
|
16003
16138
|
const cwd = process.cwd();
|
|
16004
|
-
console.log(
|
|
16139
|
+
console.log(chalk15.blue(`Reading config: ${CONFIG_FILE3}`));
|
|
16005
16140
|
if (!existsSync6(CONFIG_FILE3)) {
|
|
16006
|
-
console.error(
|
|
16141
|
+
console.error(chalk15.red(`\u2717 Config file not found: ${CONFIG_FILE3}`));
|
|
16007
16142
|
process.exit(1);
|
|
16008
16143
|
}
|
|
16009
16144
|
let config2;
|
|
@@ -16011,22 +16146,22 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
16011
16146
|
const content = await readFile5(CONFIG_FILE3, "utf8");
|
|
16012
16147
|
config2 = parseYaml3(content);
|
|
16013
16148
|
} catch (error43) {
|
|
16014
|
-
console.error(
|
|
16149
|
+
console.error(chalk15.red("\u2717 Invalid YAML format"));
|
|
16015
16150
|
if (error43 instanceof Error) {
|
|
16016
|
-
console.error(
|
|
16151
|
+
console.error(chalk15.gray(` ${error43.message}`));
|
|
16017
16152
|
}
|
|
16018
16153
|
process.exit(1);
|
|
16019
16154
|
}
|
|
16020
16155
|
const validation = validateAgentCompose(config2);
|
|
16021
16156
|
if (!validation.valid) {
|
|
16022
|
-
console.error(
|
|
16157
|
+
console.error(chalk15.red(`\u2717 ${validation.error}`));
|
|
16023
16158
|
process.exit(1);
|
|
16024
16159
|
}
|
|
16025
16160
|
const agentNames = Object.keys(config2.agents);
|
|
16026
16161
|
const agentName = agentNames[0];
|
|
16027
16162
|
const volumeCount = config2.volumes ? Object.keys(config2.volumes).length : 0;
|
|
16028
16163
|
console.log(
|
|
16029
|
-
|
|
16164
|
+
chalk15.green(`\u2713 Config validated: 1 agent, ${volumeCount} volume(s)`)
|
|
16030
16165
|
);
|
|
16031
16166
|
const requiredVarNames = extractRequiredVarNames(config2);
|
|
16032
16167
|
if (requiredVarNames.length > 0) {
|
|
@@ -16036,25 +16171,25 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
16036
16171
|
await generateEnvPlaceholders(missingVars, envFilePath);
|
|
16037
16172
|
console.log();
|
|
16038
16173
|
console.log(
|
|
16039
|
-
|
|
16174
|
+
chalk15.yellow(
|
|
16040
16175
|
`\u26A0 Missing environment variables. Please fill in values in .env file:`
|
|
16041
16176
|
)
|
|
16042
16177
|
);
|
|
16043
16178
|
for (const varName of missingVars) {
|
|
16044
|
-
console.log(
|
|
16179
|
+
console.log(chalk15.yellow(` ${varName}`));
|
|
16045
16180
|
}
|
|
16046
16181
|
process.exit(1);
|
|
16047
16182
|
}
|
|
16048
16183
|
}
|
|
16049
16184
|
if (config2.volumes && Object.keys(config2.volumes).length > 0) {
|
|
16050
16185
|
console.log();
|
|
16051
|
-
console.log(
|
|
16186
|
+
console.log(chalk15.blue("Processing volumes..."));
|
|
16052
16187
|
for (const volumeConfig of Object.values(config2.volumes)) {
|
|
16053
16188
|
const volumeDir = path11.join(cwd, volumeConfig.name);
|
|
16054
|
-
console.log(
|
|
16189
|
+
console.log(chalk15.gray(` ${volumeConfig.name}/`));
|
|
16055
16190
|
if (!existsSync6(volumeDir)) {
|
|
16056
16191
|
console.error(
|
|
16057
|
-
|
|
16192
|
+
chalk15.red(
|
|
16058
16193
|
` \u2717 Directory not found. Create the directory and add files first.`
|
|
16059
16194
|
)
|
|
16060
16195
|
);
|
|
@@ -16067,30 +16202,30 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
16067
16202
|
cwd: volumeDir,
|
|
16068
16203
|
silent: true
|
|
16069
16204
|
});
|
|
16070
|
-
console.log(
|
|
16205
|
+
console.log(chalk15.green(` \u2713 Initialized`));
|
|
16071
16206
|
}
|
|
16072
16207
|
await execVm0Command(["volume", "push"], {
|
|
16073
16208
|
cwd: volumeDir,
|
|
16074
16209
|
silent: true
|
|
16075
16210
|
});
|
|
16076
|
-
console.log(
|
|
16211
|
+
console.log(chalk15.green(` \u2713 Pushed`));
|
|
16077
16212
|
} catch (error43) {
|
|
16078
|
-
console.error(
|
|
16213
|
+
console.error(chalk15.red(` \u2717 Failed`));
|
|
16079
16214
|
if (error43 instanceof Error) {
|
|
16080
|
-
console.error(
|
|
16215
|
+
console.error(chalk15.gray(` ${error43.message}`));
|
|
16081
16216
|
}
|
|
16082
16217
|
process.exit(1);
|
|
16083
16218
|
}
|
|
16084
16219
|
}
|
|
16085
16220
|
}
|
|
16086
16221
|
console.log();
|
|
16087
|
-
console.log(
|
|
16222
|
+
console.log(chalk15.blue("Processing artifact..."));
|
|
16088
16223
|
const artifactDir = path11.join(cwd, ARTIFACT_DIR);
|
|
16089
|
-
console.log(
|
|
16224
|
+
console.log(chalk15.gray(` ${ARTIFACT_DIR}/`));
|
|
16090
16225
|
try {
|
|
16091
16226
|
if (!existsSync6(artifactDir)) {
|
|
16092
16227
|
await mkdir5(artifactDir, { recursive: true });
|
|
16093
|
-
console.log(
|
|
16228
|
+
console.log(chalk15.green(` \u2713 Created directory`));
|
|
16094
16229
|
}
|
|
16095
16230
|
const existingConfig = await readStorageConfig(artifactDir);
|
|
16096
16231
|
if (!existingConfig) {
|
|
@@ -16098,38 +16233,38 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
16098
16233
|
cwd: artifactDir,
|
|
16099
16234
|
silent: true
|
|
16100
16235
|
});
|
|
16101
|
-
console.log(
|
|
16236
|
+
console.log(chalk15.green(` \u2713 Initialized`));
|
|
16102
16237
|
}
|
|
16103
16238
|
await execVm0Command(["artifact", "push"], {
|
|
16104
16239
|
cwd: artifactDir,
|
|
16105
16240
|
silent: true
|
|
16106
16241
|
});
|
|
16107
|
-
console.log(
|
|
16242
|
+
console.log(chalk15.green(` \u2713 Pushed`));
|
|
16108
16243
|
} catch (error43) {
|
|
16109
|
-
console.error(
|
|
16244
|
+
console.error(chalk15.red(` \u2717 Failed`));
|
|
16110
16245
|
if (error43 instanceof Error) {
|
|
16111
|
-
console.error(
|
|
16246
|
+
console.error(chalk15.gray(` ${error43.message}`));
|
|
16112
16247
|
}
|
|
16113
16248
|
process.exit(1);
|
|
16114
16249
|
}
|
|
16115
16250
|
console.log();
|
|
16116
|
-
console.log(
|
|
16251
|
+
console.log(chalk15.blue("Uploading compose..."));
|
|
16117
16252
|
try {
|
|
16118
16253
|
await execVm0Command(["compose", CONFIG_FILE3], {
|
|
16119
16254
|
cwd,
|
|
16120
16255
|
silent: true
|
|
16121
16256
|
});
|
|
16122
|
-
console.log(
|
|
16257
|
+
console.log(chalk15.green(`\u2713 Compose uploaded: ${agentName}`));
|
|
16123
16258
|
} catch (error43) {
|
|
16124
|
-
console.error(
|
|
16259
|
+
console.error(chalk15.red(`\u2717 Compose failed`));
|
|
16125
16260
|
if (error43 instanceof Error) {
|
|
16126
|
-
console.error(
|
|
16261
|
+
console.error(chalk15.gray(` ${error43.message}`));
|
|
16127
16262
|
}
|
|
16128
16263
|
process.exit(1);
|
|
16129
16264
|
}
|
|
16130
16265
|
if (prompt) {
|
|
16131
16266
|
console.log();
|
|
16132
|
-
console.log(
|
|
16267
|
+
console.log(chalk15.blue(`Running agent: ${agentName}`));
|
|
16133
16268
|
console.log();
|
|
16134
16269
|
let runOutput;
|
|
16135
16270
|
try {
|
|
@@ -16150,17 +16285,17 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
16150
16285
|
);
|
|
16151
16286
|
if (serverVersion) {
|
|
16152
16287
|
console.log();
|
|
16153
|
-
console.log(
|
|
16288
|
+
console.log(chalk15.blue("Pulling updated artifact..."));
|
|
16154
16289
|
try {
|
|
16155
16290
|
await execVm0Command(["artifact", "pull"], {
|
|
16156
16291
|
cwd: artifactDir,
|
|
16157
16292
|
silent: true
|
|
16158
16293
|
});
|
|
16159
|
-
console.log(
|
|
16294
|
+
console.log(chalk15.green(`\u2713 Artifact pulled (${serverVersion})`));
|
|
16160
16295
|
} catch (error43) {
|
|
16161
|
-
console.error(
|
|
16296
|
+
console.error(chalk15.red(`\u2717 Artifact pull failed`));
|
|
16162
16297
|
if (error43 instanceof Error) {
|
|
16163
|
-
console.error(
|
|
16298
|
+
console.error(chalk15.gray(` ${error43.message}`));
|
|
16164
16299
|
}
|
|
16165
16300
|
}
|
|
16166
16301
|
}
|
|
@@ -16168,7 +16303,7 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
16168
16303
|
console.log();
|
|
16169
16304
|
console.log(" Run your agent:");
|
|
16170
16305
|
console.log(
|
|
16171
|
-
|
|
16306
|
+
chalk15.cyan(
|
|
16172
16307
|
` vm0 run ${agentName} --artifact-name ${ARTIFACT_DIR} "your prompt"`
|
|
16173
16308
|
)
|
|
16174
16309
|
);
|
|
@@ -16176,25 +16311,25 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
16176
16311
|
});
|
|
16177
16312
|
|
|
16178
16313
|
// src/commands/image/index.ts
|
|
16179
|
-
import { Command as
|
|
16314
|
+
import { Command as Command17 } from "commander";
|
|
16180
16315
|
|
|
16181
16316
|
// src/commands/image/build.ts
|
|
16182
|
-
import { Command as
|
|
16183
|
-
import
|
|
16317
|
+
import { Command as Command14 } from "commander";
|
|
16318
|
+
import chalk16 from "chalk";
|
|
16184
16319
|
import { readFile as readFile6 } from "fs/promises";
|
|
16185
16320
|
import { existsSync as existsSync7 } from "fs";
|
|
16186
16321
|
var sleep2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
16187
|
-
var buildCommand = new
|
|
16322
|
+
var buildCommand = new Command14().name("build").description("Build a custom image from a Dockerfile").requiredOption("-f, --file <path>", "Path to Dockerfile").requiredOption("-n, --name <name>", "Name for the image").option("--delete-existing", "Delete existing image before building").action(
|
|
16188
16323
|
async (options) => {
|
|
16189
16324
|
const { file: file2, name, deleteExisting } = options;
|
|
16190
16325
|
if (!existsSync7(file2)) {
|
|
16191
|
-
console.error(
|
|
16326
|
+
console.error(chalk16.red(`\u2717 Dockerfile not found: ${file2}`));
|
|
16192
16327
|
process.exit(1);
|
|
16193
16328
|
}
|
|
16194
16329
|
const nameRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{1,62}[a-zA-Z0-9]$/;
|
|
16195
16330
|
if (!nameRegex.test(name)) {
|
|
16196
16331
|
console.error(
|
|
16197
|
-
|
|
16332
|
+
chalk16.red(
|
|
16198
16333
|
"\u2717 Invalid name format. Must be 3-64 characters, letters, numbers, and hyphens only."
|
|
16199
16334
|
)
|
|
16200
16335
|
);
|
|
@@ -16202,7 +16337,7 @@ var buildCommand = new Command12().name("build").description("Build a custom ima
|
|
|
16202
16337
|
}
|
|
16203
16338
|
if (name.startsWith("vm0-")) {
|
|
16204
16339
|
console.error(
|
|
16205
|
-
|
|
16340
|
+
chalk16.red(
|
|
16206
16341
|
'\u2717 Invalid name. Cannot start with "vm0-" (reserved prefix).'
|
|
16207
16342
|
)
|
|
16208
16343
|
);
|
|
@@ -16210,8 +16345,8 @@ var buildCommand = new Command12().name("build").description("Build a custom ima
|
|
|
16210
16345
|
}
|
|
16211
16346
|
try {
|
|
16212
16347
|
const dockerfile = await readFile6(file2, "utf8");
|
|
16213
|
-
console.log(
|
|
16214
|
-
console.log(
|
|
16348
|
+
console.log(chalk16.blue(`Building image: ${name}`));
|
|
16349
|
+
console.log(chalk16.gray(` Dockerfile: ${file2}`));
|
|
16215
16350
|
console.log();
|
|
16216
16351
|
const buildInfo = await apiClient.createImage({
|
|
16217
16352
|
dockerfile,
|
|
@@ -16219,7 +16354,7 @@ var buildCommand = new Command12().name("build").description("Build a custom ima
|
|
|
16219
16354
|
deleteExisting
|
|
16220
16355
|
});
|
|
16221
16356
|
const { imageId, buildId } = buildInfo;
|
|
16222
|
-
console.log(
|
|
16357
|
+
console.log(chalk16.gray(` Build ID: ${buildId}`));
|
|
16223
16358
|
console.log();
|
|
16224
16359
|
let logsOffset = 0;
|
|
16225
16360
|
let status = "building";
|
|
@@ -16235,7 +16370,7 @@ var buildCommand = new Command12().name("build").description("Build a custom ima
|
|
|
16235
16370
|
}
|
|
16236
16371
|
const statusData = await statusResponse.json();
|
|
16237
16372
|
for (const log of statusData.logs) {
|
|
16238
|
-
console.log(
|
|
16373
|
+
console.log(chalk16.gray(` ${log}`));
|
|
16239
16374
|
}
|
|
16240
16375
|
logsOffset = statusData.logsOffset;
|
|
16241
16376
|
status = statusData.status;
|
|
@@ -16245,27 +16380,27 @@ var buildCommand = new Command12().name("build").description("Build a custom ima
|
|
|
16245
16380
|
}
|
|
16246
16381
|
console.log();
|
|
16247
16382
|
if (status === "ready") {
|
|
16248
|
-
console.log(
|
|
16383
|
+
console.log(chalk16.green(`\u2713 Image built: ${name}`));
|
|
16249
16384
|
console.log();
|
|
16250
16385
|
console.log("Use in vm0.yaml:");
|
|
16251
|
-
console.log(
|
|
16252
|
-
console.log(
|
|
16253
|
-
console.log(
|
|
16386
|
+
console.log(chalk16.cyan(` agents:`));
|
|
16387
|
+
console.log(chalk16.cyan(` your-agent:`));
|
|
16388
|
+
console.log(chalk16.cyan(` image: "${name}"`));
|
|
16254
16389
|
} else {
|
|
16255
|
-
console.error(
|
|
16390
|
+
console.error(chalk16.red(`\u2717 Build failed`));
|
|
16256
16391
|
process.exit(1);
|
|
16257
16392
|
}
|
|
16258
16393
|
} catch (error43) {
|
|
16259
16394
|
if (error43 instanceof Error) {
|
|
16260
16395
|
if (error43.message.includes("Not authenticated")) {
|
|
16261
16396
|
console.error(
|
|
16262
|
-
|
|
16397
|
+
chalk16.red("\u2717 Not authenticated. Run: vm0 auth login")
|
|
16263
16398
|
);
|
|
16264
16399
|
} else {
|
|
16265
|
-
console.error(
|
|
16400
|
+
console.error(chalk16.red(`\u2717 ${error43.message}`));
|
|
16266
16401
|
}
|
|
16267
16402
|
} else {
|
|
16268
|
-
console.error(
|
|
16403
|
+
console.error(chalk16.red("\u2717 An unexpected error occurred"));
|
|
16269
16404
|
}
|
|
16270
16405
|
process.exit(1);
|
|
16271
16406
|
}
|
|
@@ -16273,9 +16408,9 @@ var buildCommand = new Command12().name("build").description("Build a custom ima
|
|
|
16273
16408
|
);
|
|
16274
16409
|
|
|
16275
16410
|
// src/commands/image/list.ts
|
|
16276
|
-
import { Command as
|
|
16277
|
-
import
|
|
16278
|
-
var listCommand = new
|
|
16411
|
+
import { Command as Command15 } from "commander";
|
|
16412
|
+
import chalk17 from "chalk";
|
|
16413
|
+
var listCommand = new Command15().name("list").alias("ls").description("List your custom images").action(async () => {
|
|
16279
16414
|
try {
|
|
16280
16415
|
const response = await apiClient.get("/api/images");
|
|
16281
16416
|
if (!response.ok) {
|
|
@@ -16287,53 +16422,53 @@ var listCommand = new Command13().name("list").alias("ls").description("List you
|
|
|
16287
16422
|
const data = await response.json();
|
|
16288
16423
|
const { images } = data;
|
|
16289
16424
|
if (images.length === 0) {
|
|
16290
|
-
console.log(
|
|
16425
|
+
console.log(chalk17.gray("No images found."));
|
|
16291
16426
|
console.log();
|
|
16292
16427
|
console.log("Build your first image:");
|
|
16293
16428
|
console.log(
|
|
16294
|
-
|
|
16429
|
+
chalk17.cyan(" vm0 image build --file Dockerfile --name my-image")
|
|
16295
16430
|
);
|
|
16296
16431
|
return;
|
|
16297
16432
|
}
|
|
16298
|
-
console.log(
|
|
16433
|
+
console.log(chalk17.bold("Your images:"));
|
|
16299
16434
|
console.log();
|
|
16300
16435
|
console.log(
|
|
16301
|
-
|
|
16436
|
+
chalk17.gray(
|
|
16302
16437
|
`${"NAME".padEnd(30)} ${"STATUS".padEnd(12)} ${"CREATED".padEnd(20)}`
|
|
16303
16438
|
)
|
|
16304
16439
|
);
|
|
16305
|
-
console.log(
|
|
16440
|
+
console.log(chalk17.gray("-".repeat(62)));
|
|
16306
16441
|
for (const image of images) {
|
|
16307
|
-
const statusColor = image.status === "ready" ?
|
|
16442
|
+
const statusColor = image.status === "ready" ? chalk17.green : image.status === "building" ? chalk17.yellow : chalk17.red;
|
|
16308
16443
|
const createdAt = new Date(image.createdAt).toLocaleString();
|
|
16309
16444
|
console.log(
|
|
16310
16445
|
`${image.alias.padEnd(30)} ${statusColor(image.status.padEnd(12))} ${createdAt.padEnd(20)}`
|
|
16311
16446
|
);
|
|
16312
16447
|
if (image.status === "error" && image.errorMessage) {
|
|
16313
|
-
console.log(
|
|
16448
|
+
console.log(chalk17.red(` Error: ${image.errorMessage}`));
|
|
16314
16449
|
}
|
|
16315
16450
|
}
|
|
16316
16451
|
console.log();
|
|
16317
|
-
console.log(
|
|
16452
|
+
console.log(chalk17.gray(`Total: ${images.length} image(s)`));
|
|
16318
16453
|
} catch (error43) {
|
|
16319
16454
|
if (error43 instanceof Error) {
|
|
16320
16455
|
if (error43.message.includes("Not authenticated")) {
|
|
16321
|
-
console.error(
|
|
16456
|
+
console.error(chalk17.red("Not authenticated. Run: vm0 auth login"));
|
|
16322
16457
|
} else {
|
|
16323
|
-
console.error(
|
|
16458
|
+
console.error(chalk17.red(`Error: ${error43.message}`));
|
|
16324
16459
|
}
|
|
16325
16460
|
} else {
|
|
16326
|
-
console.error(
|
|
16461
|
+
console.error(chalk17.red("An unexpected error occurred"));
|
|
16327
16462
|
}
|
|
16328
16463
|
process.exit(1);
|
|
16329
16464
|
}
|
|
16330
16465
|
});
|
|
16331
16466
|
|
|
16332
16467
|
// src/commands/image/delete.ts
|
|
16333
|
-
import { Command as
|
|
16334
|
-
import
|
|
16468
|
+
import { Command as Command16 } from "commander";
|
|
16469
|
+
import chalk18 from "chalk";
|
|
16335
16470
|
import * as readline from "readline";
|
|
16336
|
-
var deleteCommand = new
|
|
16471
|
+
var deleteCommand = new Command16().name("delete").alias("rm").description("Delete a custom image").argument("<name>", "Name of the image to delete").option("-f, --force", "Skip confirmation prompt").action(async (name, options) => {
|
|
16337
16472
|
try {
|
|
16338
16473
|
const listResponse = await apiClient.get("/api/images");
|
|
16339
16474
|
if (!listResponse.ok) {
|
|
@@ -16345,7 +16480,7 @@ var deleteCommand = new Command14().name("delete").alias("rm").description("Dele
|
|
|
16345
16480
|
const data = await listResponse.json();
|
|
16346
16481
|
const image = data.images.find((img) => img.alias === name);
|
|
16347
16482
|
if (!image) {
|
|
16348
|
-
console.error(
|
|
16483
|
+
console.error(chalk18.red(`Image not found: ${name}`));
|
|
16349
16484
|
process.exit(1);
|
|
16350
16485
|
}
|
|
16351
16486
|
if (!options.force) {
|
|
@@ -16355,7 +16490,7 @@ var deleteCommand = new Command14().name("delete").alias("rm").description("Dele
|
|
|
16355
16490
|
});
|
|
16356
16491
|
const answer = await new Promise((resolve2) => {
|
|
16357
16492
|
rl.question(
|
|
16358
|
-
|
|
16493
|
+
chalk18.yellow(`Delete image "${name}"? [y/N] `),
|
|
16359
16494
|
(answer2) => {
|
|
16360
16495
|
rl.close();
|
|
16361
16496
|
resolve2(answer2);
|
|
@@ -16363,7 +16498,7 @@ var deleteCommand = new Command14().name("delete").alias("rm").description("Dele
|
|
|
16363
16498
|
);
|
|
16364
16499
|
});
|
|
16365
16500
|
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
16366
|
-
console.log(
|
|
16501
|
+
console.log(chalk18.gray("Cancelled."));
|
|
16367
16502
|
return;
|
|
16368
16503
|
}
|
|
16369
16504
|
}
|
|
@@ -16374,27 +16509,27 @@ var deleteCommand = new Command14().name("delete").alias("rm").description("Dele
|
|
|
16374
16509
|
error43.error?.message || "Failed to delete image"
|
|
16375
16510
|
);
|
|
16376
16511
|
}
|
|
16377
|
-
console.log(
|
|
16512
|
+
console.log(chalk18.green(`Deleted image: ${name}`));
|
|
16378
16513
|
} catch (error43) {
|
|
16379
16514
|
if (error43 instanceof Error) {
|
|
16380
16515
|
if (error43.message.includes("Not authenticated")) {
|
|
16381
|
-
console.error(
|
|
16516
|
+
console.error(chalk18.red("Not authenticated. Run: vm0 auth login"));
|
|
16382
16517
|
} else {
|
|
16383
|
-
console.error(
|
|
16518
|
+
console.error(chalk18.red(`Error: ${error43.message}`));
|
|
16384
16519
|
}
|
|
16385
16520
|
} else {
|
|
16386
|
-
console.error(
|
|
16521
|
+
console.error(chalk18.red("An unexpected error occurred"));
|
|
16387
16522
|
}
|
|
16388
16523
|
process.exit(1);
|
|
16389
16524
|
}
|
|
16390
16525
|
});
|
|
16391
16526
|
|
|
16392
16527
|
// src/commands/image/index.ts
|
|
16393
|
-
var imageCommand = new
|
|
16528
|
+
var imageCommand = new Command17().name("image").description("Manage custom images").addCommand(buildCommand).addCommand(listCommand).addCommand(deleteCommand);
|
|
16394
16529
|
|
|
16395
16530
|
// src/commands/logs/index.ts
|
|
16396
|
-
import { Command as
|
|
16397
|
-
import
|
|
16531
|
+
import { Command as Command18 } from "commander";
|
|
16532
|
+
import chalk19 from "chalk";
|
|
16398
16533
|
|
|
16399
16534
|
// src/lib/time-parser.ts
|
|
16400
16535
|
function parseTime(timeStr) {
|
|
@@ -16441,7 +16576,7 @@ function parseRelativeTime(value, unit) {
|
|
|
16441
16576
|
}
|
|
16442
16577
|
|
|
16443
16578
|
// src/commands/logs/index.ts
|
|
16444
|
-
function
|
|
16579
|
+
function formatBytes7(bytes) {
|
|
16445
16580
|
if (bytes === 0) return "0 B";
|
|
16446
16581
|
const k = 1024;
|
|
16447
16582
|
const sizes = ["B", "KB", "MB", "GB"];
|
|
@@ -16451,28 +16586,28 @@ function formatBytes5(bytes) {
|
|
|
16451
16586
|
function formatMetric(metric) {
|
|
16452
16587
|
const memPercent = (metric.mem_used / metric.mem_total * 100).toFixed(1);
|
|
16453
16588
|
const diskPercent = (metric.disk_used / metric.disk_total * 100).toFixed(1);
|
|
16454
|
-
return `[${metric.ts}] CPU: ${metric.cpu.toFixed(1)}% | Mem: ${
|
|
16589
|
+
return `[${metric.ts}] CPU: ${metric.cpu.toFixed(1)}% | Mem: ${formatBytes7(metric.mem_used)}/${formatBytes7(metric.mem_total)} (${memPercent}%) | Disk: ${formatBytes7(metric.disk_used)}/${formatBytes7(metric.disk_total)} (${diskPercent}%)`;
|
|
16455
16590
|
}
|
|
16456
16591
|
function formatNetworkLog(entry) {
|
|
16457
16592
|
let statusColor;
|
|
16458
16593
|
if (entry.status >= 200 && entry.status < 300) {
|
|
16459
|
-
statusColor =
|
|
16594
|
+
statusColor = chalk19.green;
|
|
16460
16595
|
} else if (entry.status >= 300 && entry.status < 400) {
|
|
16461
|
-
statusColor =
|
|
16596
|
+
statusColor = chalk19.yellow;
|
|
16462
16597
|
} else if (entry.status >= 400) {
|
|
16463
|
-
statusColor =
|
|
16598
|
+
statusColor = chalk19.red;
|
|
16464
16599
|
} else {
|
|
16465
|
-
statusColor =
|
|
16600
|
+
statusColor = chalk19.gray;
|
|
16466
16601
|
}
|
|
16467
16602
|
let latencyColor;
|
|
16468
16603
|
if (entry.latency_ms < 500) {
|
|
16469
|
-
latencyColor =
|
|
16604
|
+
latencyColor = chalk19.green;
|
|
16470
16605
|
} else if (entry.latency_ms < 2e3) {
|
|
16471
|
-
latencyColor =
|
|
16606
|
+
latencyColor = chalk19.yellow;
|
|
16472
16607
|
} else {
|
|
16473
|
-
latencyColor =
|
|
16608
|
+
latencyColor = chalk19.red;
|
|
16474
16609
|
}
|
|
16475
|
-
return `[${entry.timestamp}] ${
|
|
16610
|
+
return `[${entry.timestamp}] ${chalk19.cyan(entry.method.padEnd(6))} ${statusColor(entry.status)} ${latencyColor(entry.latency_ms + "ms")} ${formatBytes7(entry.request_size)}/${formatBytes7(entry.response_size)} ${chalk19.gray(entry.url)}`;
|
|
16476
16611
|
}
|
|
16477
16612
|
function renderAgentEvent(event) {
|
|
16478
16613
|
const parsed = ClaudeEventParser.parse(
|
|
@@ -16492,7 +16627,7 @@ function getLogType(options) {
|
|
|
16492
16627
|
].filter(Boolean).length;
|
|
16493
16628
|
if (selected > 1) {
|
|
16494
16629
|
console.error(
|
|
16495
|
-
|
|
16630
|
+
chalk19.red(
|
|
16496
16631
|
"Options --agent, --system, --metrics, and --network are mutually exclusive"
|
|
16497
16632
|
)
|
|
16498
16633
|
);
|
|
@@ -16503,7 +16638,7 @@ function getLogType(options) {
|
|
|
16503
16638
|
if (options.network) return "network";
|
|
16504
16639
|
return "agent";
|
|
16505
16640
|
}
|
|
16506
|
-
var logsCommand = new
|
|
16641
|
+
var logsCommand = new Command18().name("logs").description("View logs for an agent run").argument("<runId>", "Run ID to fetch logs for").option("-a, --agent", "Show agent events (default)").option("-s, --system", "Show system log").option("-m, --metrics", "Show metrics").option("-n, --network", "Show network logs (proxy traffic)").option(
|
|
16507
16642
|
"--since <time>",
|
|
16508
16643
|
"Show logs since timestamp (e.g., 5m, 2h, 1d, 2024-01-15T10:30:00Z, 1705312200)"
|
|
16509
16644
|
).option(
|
|
@@ -16545,7 +16680,7 @@ var logsCommand = new Command16().name("logs").description("View logs for an age
|
|
|
16545
16680
|
async function showAgentEvents(runId, options) {
|
|
16546
16681
|
const response = await apiClient.getAgentEvents(runId, options);
|
|
16547
16682
|
if (response.events.length === 0) {
|
|
16548
|
-
console.log(
|
|
16683
|
+
console.log(chalk19.yellow("No agent events found for this run."));
|
|
16549
16684
|
return;
|
|
16550
16685
|
}
|
|
16551
16686
|
for (const event of response.events) {
|
|
@@ -16554,7 +16689,7 @@ async function showAgentEvents(runId, options) {
|
|
|
16554
16689
|
if (response.hasMore) {
|
|
16555
16690
|
console.log();
|
|
16556
16691
|
console.log(
|
|
16557
|
-
|
|
16692
|
+
chalk19.gray(
|
|
16558
16693
|
`Showing ${response.events.length} events. Use --limit to see more.`
|
|
16559
16694
|
)
|
|
16560
16695
|
);
|
|
@@ -16563,21 +16698,21 @@ async function showAgentEvents(runId, options) {
|
|
|
16563
16698
|
async function showSystemLog(runId, options) {
|
|
16564
16699
|
const response = await apiClient.getSystemLog(runId, options);
|
|
16565
16700
|
if (!response.systemLog) {
|
|
16566
|
-
console.log(
|
|
16701
|
+
console.log(chalk19.yellow("No system log found for this run."));
|
|
16567
16702
|
return;
|
|
16568
16703
|
}
|
|
16569
16704
|
console.log(response.systemLog);
|
|
16570
16705
|
if (response.hasMore) {
|
|
16571
16706
|
console.log();
|
|
16572
16707
|
console.log(
|
|
16573
|
-
|
|
16708
|
+
chalk19.gray("More log entries available. Use --limit to see more.")
|
|
16574
16709
|
);
|
|
16575
16710
|
}
|
|
16576
16711
|
}
|
|
16577
16712
|
async function showMetrics(runId, options) {
|
|
16578
16713
|
const response = await apiClient.getMetrics(runId, options);
|
|
16579
16714
|
if (response.metrics.length === 0) {
|
|
16580
|
-
console.log(
|
|
16715
|
+
console.log(chalk19.yellow("No metrics found for this run."));
|
|
16581
16716
|
return;
|
|
16582
16717
|
}
|
|
16583
16718
|
for (const metric of response.metrics) {
|
|
@@ -16586,7 +16721,7 @@ async function showMetrics(runId, options) {
|
|
|
16586
16721
|
if (response.hasMore) {
|
|
16587
16722
|
console.log();
|
|
16588
16723
|
console.log(
|
|
16589
|
-
|
|
16724
|
+
chalk19.gray(
|
|
16590
16725
|
`Showing ${response.metrics.length} metrics. Use --limit to see more.`
|
|
16591
16726
|
)
|
|
16592
16727
|
);
|
|
@@ -16596,7 +16731,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
16596
16731
|
const response = await apiClient.getNetworkLogs(runId, options);
|
|
16597
16732
|
if (response.networkLogs.length === 0) {
|
|
16598
16733
|
console.log(
|
|
16599
|
-
|
|
16734
|
+
chalk19.yellow(
|
|
16600
16735
|
"No network logs found for this run. Network logs are only captured when beta_network_security is enabled."
|
|
16601
16736
|
)
|
|
16602
16737
|
);
|
|
@@ -16608,7 +16743,7 @@ async function showNetworkLogs(runId, options) {
|
|
|
16608
16743
|
if (response.hasMore) {
|
|
16609
16744
|
console.log();
|
|
16610
16745
|
console.log(
|
|
16611
|
-
|
|
16746
|
+
chalk19.gray(
|
|
16612
16747
|
`Showing ${response.networkLogs.length} network logs. Use --limit to see more.`
|
|
16613
16748
|
)
|
|
16614
16749
|
);
|
|
@@ -16617,25 +16752,25 @@ async function showNetworkLogs(runId, options) {
|
|
|
16617
16752
|
function handleError(error43, runId) {
|
|
16618
16753
|
if (error43 instanceof Error) {
|
|
16619
16754
|
if (error43.message.includes("Not authenticated")) {
|
|
16620
|
-
console.error(
|
|
16755
|
+
console.error(chalk19.red("Not authenticated. Run: vm0 auth login"));
|
|
16621
16756
|
} else if (error43.message.includes("not found")) {
|
|
16622
|
-
console.error(
|
|
16757
|
+
console.error(chalk19.red(`Run not found: ${runId}`));
|
|
16623
16758
|
} else if (error43.message.includes("Invalid time format")) {
|
|
16624
|
-
console.error(
|
|
16759
|
+
console.error(chalk19.red(error43.message));
|
|
16625
16760
|
} else {
|
|
16626
|
-
console.error(
|
|
16627
|
-
console.error(
|
|
16761
|
+
console.error(chalk19.red("Failed to fetch logs"));
|
|
16762
|
+
console.error(chalk19.gray(` ${error43.message}`));
|
|
16628
16763
|
}
|
|
16629
16764
|
} else {
|
|
16630
|
-
console.error(
|
|
16765
|
+
console.error(chalk19.red("An unexpected error occurred"));
|
|
16631
16766
|
}
|
|
16632
16767
|
}
|
|
16633
16768
|
|
|
16634
16769
|
// src/index.ts
|
|
16635
|
-
var program = new
|
|
16636
|
-
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.
|
|
16770
|
+
var program = new Command19();
|
|
16771
|
+
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.14.1");
|
|
16637
16772
|
program.command("info").description("Display environment information").action(async () => {
|
|
16638
|
-
console.log(
|
|
16773
|
+
console.log(chalk20.cyan("System Information:"));
|
|
16639
16774
|
console.log(`Node Version: ${process.version}`);
|
|
16640
16775
|
console.log(`Platform: ${process.platform}`);
|
|
16641
16776
|
console.log(`Architecture: ${process.arch}`);
|