@vm0/cli 4.7.1 → 4.8.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 +421 -117
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -167,8 +167,9 @@ async function checkAuthStatus() {
|
|
|
167
167
|
// src/commands/compose.ts
|
|
168
168
|
import { Command } from "commander";
|
|
169
169
|
import chalk2 from "chalk";
|
|
170
|
-
import { readFile as
|
|
170
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
171
171
|
import { existsSync as existsSync2 } from "fs";
|
|
172
|
+
import { dirname as dirname2 } from "path";
|
|
172
173
|
import { parse as parseYaml } from "yaml";
|
|
173
174
|
|
|
174
175
|
// src/lib/api-client.ts
|
|
@@ -430,7 +431,7 @@ var ApiClient = class {
|
|
|
430
431
|
/**
|
|
431
432
|
* Generic GET request
|
|
432
433
|
*/
|
|
433
|
-
async get(
|
|
434
|
+
async get(path13) {
|
|
434
435
|
const baseUrl = await this.getBaseUrl();
|
|
435
436
|
const token = await getToken();
|
|
436
437
|
if (!token) {
|
|
@@ -443,7 +444,7 @@ var ApiClient = class {
|
|
|
443
444
|
if (bypassSecret) {
|
|
444
445
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
445
446
|
}
|
|
446
|
-
return fetch(`${baseUrl}${
|
|
447
|
+
return fetch(`${baseUrl}${path13}`, {
|
|
447
448
|
method: "GET",
|
|
448
449
|
headers
|
|
449
450
|
});
|
|
@@ -451,7 +452,7 @@ var ApiClient = class {
|
|
|
451
452
|
/**
|
|
452
453
|
* Generic POST request
|
|
453
454
|
*/
|
|
454
|
-
async post(
|
|
455
|
+
async post(path13, options) {
|
|
455
456
|
const baseUrl = await this.getBaseUrl();
|
|
456
457
|
const token = await getToken();
|
|
457
458
|
if (!token) {
|
|
@@ -467,7 +468,7 @@ var ApiClient = class {
|
|
|
467
468
|
if (bypassSecret) {
|
|
468
469
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
469
470
|
}
|
|
470
|
-
return fetch(`${baseUrl}${
|
|
471
|
+
return fetch(`${baseUrl}${path13}`, {
|
|
471
472
|
method: "POST",
|
|
472
473
|
headers,
|
|
473
474
|
body: options?.body
|
|
@@ -476,7 +477,7 @@ var ApiClient = class {
|
|
|
476
477
|
/**
|
|
477
478
|
* Generic DELETE request
|
|
478
479
|
*/
|
|
479
|
-
async delete(
|
|
480
|
+
async delete(path13) {
|
|
480
481
|
const baseUrl = await this.getBaseUrl();
|
|
481
482
|
const token = await getToken();
|
|
482
483
|
if (!token) {
|
|
@@ -489,7 +490,7 @@ var ApiClient = class {
|
|
|
489
490
|
if (bypassSecret) {
|
|
490
491
|
headers["x-vercel-protection-bypass"] = bypassSecret;
|
|
491
492
|
}
|
|
492
|
-
return fetch(`${baseUrl}${
|
|
493
|
+
return fetch(`${baseUrl}${path13}`, {
|
|
493
494
|
method: "DELETE",
|
|
494
495
|
headers
|
|
495
496
|
});
|
|
@@ -497,11 +498,28 @@ var ApiClient = class {
|
|
|
497
498
|
};
|
|
498
499
|
var apiClient = new ApiClient();
|
|
499
500
|
|
|
501
|
+
// src/lib/provider-config.ts
|
|
502
|
+
var PROVIDER_DEFAULTS = {
|
|
503
|
+
"claude-code": {
|
|
504
|
+
workingDir: "/home/user/workspace"
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
function getProviderDefaults(provider) {
|
|
508
|
+
return PROVIDER_DEFAULTS[provider];
|
|
509
|
+
}
|
|
510
|
+
function isProviderSupported(provider) {
|
|
511
|
+
return provider in PROVIDER_DEFAULTS;
|
|
512
|
+
}
|
|
513
|
+
|
|
500
514
|
// src/lib/yaml-validator.ts
|
|
501
515
|
function validateAgentName(name) {
|
|
502
516
|
const nameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]{1,62}[a-zA-Z0-9])?$/;
|
|
503
517
|
return nameRegex.test(name);
|
|
504
518
|
}
|
|
519
|
+
function validateGitHubTreeUrl(url2) {
|
|
520
|
+
const githubTreeRegex = /^https:\/\/github\.com\/[a-zA-Z0-9_-]+\/[a-zA-Z0-9_.-]+\/tree\/[^/]+\/.+$/;
|
|
521
|
+
return githubTreeRegex.test(url2);
|
|
522
|
+
}
|
|
505
523
|
function validateVolumeConfig(volumeKey, volumeConfig) {
|
|
506
524
|
if (!volumeConfig || typeof volumeConfig !== "object") {
|
|
507
525
|
return `Volume "${volumeKey}" must be an object`;
|
|
@@ -557,24 +575,67 @@ function validateAgentCompose(config2) {
|
|
|
557
575
|
if (!agent || typeof agent !== "object") {
|
|
558
576
|
return { valid: false, error: "Agent definition must be an object" };
|
|
559
577
|
}
|
|
560
|
-
if (!agent.
|
|
578
|
+
if (!agent.provider || typeof agent.provider !== "string") {
|
|
561
579
|
return {
|
|
562
580
|
valid: false,
|
|
563
|
-
error: "Missing or invalid agent.
|
|
581
|
+
error: "Missing or invalid agent.provider (must be a string)"
|
|
564
582
|
};
|
|
565
583
|
}
|
|
584
|
+
const providerIsSupported = isProviderSupported(agent.provider);
|
|
566
585
|
if (!agent.image || typeof agent.image !== "string") {
|
|
567
586
|
return {
|
|
568
587
|
valid: false,
|
|
569
588
|
error: "Missing or invalid agent.image (must be a string)"
|
|
570
589
|
};
|
|
571
590
|
}
|
|
572
|
-
if (
|
|
591
|
+
if (agent.working_dir !== void 0 && typeof agent.working_dir !== "string") {
|
|
573
592
|
return {
|
|
574
593
|
valid: false,
|
|
575
|
-
error: "
|
|
594
|
+
error: "agent.working_dir must be a string if provided"
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
if (!agent.working_dir && !providerIsSupported) {
|
|
598
|
+
return {
|
|
599
|
+
valid: false,
|
|
600
|
+
error: "Missing agent.working_dir (required when provider is not auto-configured)"
|
|
576
601
|
};
|
|
577
602
|
}
|
|
603
|
+
if (agent.beta_system_prompt !== void 0) {
|
|
604
|
+
if (typeof agent.beta_system_prompt !== "string") {
|
|
605
|
+
return {
|
|
606
|
+
valid: false,
|
|
607
|
+
error: "agent.beta_system_prompt must be a string (path to AGENTS.md file)"
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
if (agent.beta_system_prompt.length === 0) {
|
|
611
|
+
return {
|
|
612
|
+
valid: false,
|
|
613
|
+
error: "agent.beta_system_prompt cannot be empty"
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if (agent.beta_system_skills !== void 0) {
|
|
618
|
+
if (!Array.isArray(agent.beta_system_skills)) {
|
|
619
|
+
return {
|
|
620
|
+
valid: false,
|
|
621
|
+
error: "agent.beta_system_skills must be an array of GitHub tree URLs"
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
for (const skillUrl of agent.beta_system_skills) {
|
|
625
|
+
if (typeof skillUrl !== "string") {
|
|
626
|
+
return {
|
|
627
|
+
valid: false,
|
|
628
|
+
error: "Each beta_system_skill must be a string URL"
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
if (!validateGitHubTreeUrl(skillUrl)) {
|
|
632
|
+
return {
|
|
633
|
+
valid: false,
|
|
634
|
+
error: `Invalid beta_system_skill URL: ${skillUrl}. Expected format: https://github.com/{owner}/{repo}/tree/{branch}/{path}`
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
578
639
|
if (agent.environment !== void 0) {
|
|
579
640
|
if (agent.environment === null || typeof agent.environment !== "object" || Array.isArray(agent.environment)) {
|
|
580
641
|
return {
|
|
@@ -632,6 +693,175 @@ function validateAgentCompose(config2) {
|
|
|
632
693
|
return { valid: true };
|
|
633
694
|
}
|
|
634
695
|
|
|
696
|
+
// src/lib/system-storage.ts
|
|
697
|
+
import * as fs2 from "fs/promises";
|
|
698
|
+
import * as path2 from "path";
|
|
699
|
+
import * as os2 from "os";
|
|
700
|
+
import * as tar from "tar";
|
|
701
|
+
|
|
702
|
+
// src/lib/github-skills.ts
|
|
703
|
+
import * as fs from "fs/promises";
|
|
704
|
+
import * as path from "path";
|
|
705
|
+
import * as os from "os";
|
|
706
|
+
import { exec } from "child_process";
|
|
707
|
+
import { promisify } from "util";
|
|
708
|
+
var execAsync = promisify(exec);
|
|
709
|
+
function parseGitHubTreeUrl(url2) {
|
|
710
|
+
const fullPathMatch = url2.match(/^https:\/\/github\.com\/(.+)$/);
|
|
711
|
+
if (!fullPathMatch) {
|
|
712
|
+
throw new Error(
|
|
713
|
+
`Invalid GitHub URL: ${url2}. Expected format: https://github.com/{owner}/{repo}/tree/{branch}/{path}`
|
|
714
|
+
);
|
|
715
|
+
}
|
|
716
|
+
const fullPath = fullPathMatch[1];
|
|
717
|
+
const regex = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)$/;
|
|
718
|
+
const match = url2.match(regex);
|
|
719
|
+
if (!match) {
|
|
720
|
+
throw new Error(
|
|
721
|
+
`Invalid GitHub tree URL: ${url2}. Expected format: https://github.com/{owner}/{repo}/tree/{branch}/{path}`
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
const [, owner, repo, branch, pathPart] = match;
|
|
725
|
+
const pathSegments = pathPart.split("/");
|
|
726
|
+
const skillName = pathSegments[pathSegments.length - 1];
|
|
727
|
+
return {
|
|
728
|
+
owner,
|
|
729
|
+
repo,
|
|
730
|
+
branch,
|
|
731
|
+
path: pathPart,
|
|
732
|
+
skillName,
|
|
733
|
+
fullPath
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function getSkillStorageName(parsed) {
|
|
737
|
+
return `system-skill@${parsed.fullPath}`;
|
|
738
|
+
}
|
|
739
|
+
function getSystemPromptStorageName(composeName) {
|
|
740
|
+
return `system-prompt@${composeName}`;
|
|
741
|
+
}
|
|
742
|
+
async function downloadGitHubSkill(parsed, destDir) {
|
|
743
|
+
const repoUrl = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
|
|
744
|
+
const skillDir = path.join(destDir, parsed.skillName);
|
|
745
|
+
const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "vm0-skill-"));
|
|
746
|
+
try {
|
|
747
|
+
await execAsync(`git init`, { cwd: tempDir });
|
|
748
|
+
await execAsync(`git remote add origin "${repoUrl}"`, { cwd: tempDir });
|
|
749
|
+
await execAsync(`git config core.sparseCheckout true`, { cwd: tempDir });
|
|
750
|
+
const sparseFile = path.join(tempDir, ".git", "info", "sparse-checkout");
|
|
751
|
+
await fs.writeFile(sparseFile, parsed.path + "\n");
|
|
752
|
+
await execAsync(`git fetch --depth 1 origin "${parsed.branch}"`, {
|
|
753
|
+
cwd: tempDir
|
|
754
|
+
});
|
|
755
|
+
await execAsync(`git checkout "${parsed.branch}"`, { cwd: tempDir });
|
|
756
|
+
const fetchedPath = path.join(tempDir, parsed.path);
|
|
757
|
+
await fs.mkdir(path.dirname(skillDir), { recursive: true });
|
|
758
|
+
await fs.rename(fetchedPath, skillDir);
|
|
759
|
+
return skillDir;
|
|
760
|
+
} finally {
|
|
761
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
async function validateSkillDirectory(skillDir) {
|
|
765
|
+
const skillMdPath = path.join(skillDir, "SKILL.md");
|
|
766
|
+
try {
|
|
767
|
+
await fs.access(skillMdPath);
|
|
768
|
+
} catch {
|
|
769
|
+
throw new Error(
|
|
770
|
+
`Skill directory missing required SKILL.md file: ${skillDir}`
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// src/lib/system-storage.ts
|
|
776
|
+
async function uploadSystemPrompt(agentName, promptFilePath, basePath) {
|
|
777
|
+
const storageName = getSystemPromptStorageName(agentName);
|
|
778
|
+
const absolutePath = path2.isAbsolute(promptFilePath) ? promptFilePath : path2.join(basePath, promptFilePath);
|
|
779
|
+
const content = await fs2.readFile(absolutePath, "utf8");
|
|
780
|
+
const tmpDir = await fs2.mkdtemp(path2.join(os2.tmpdir(), "vm0-prompt-"));
|
|
781
|
+
const promptDir = path2.join(tmpDir, "prompt");
|
|
782
|
+
await fs2.mkdir(promptDir);
|
|
783
|
+
await fs2.writeFile(path2.join(promptDir, "CLAUDE.md"), content);
|
|
784
|
+
try {
|
|
785
|
+
const tarPath = path2.join(tmpDir, "prompt.tar.gz");
|
|
786
|
+
await tar.create(
|
|
787
|
+
{
|
|
788
|
+
gzip: true,
|
|
789
|
+
file: tarPath,
|
|
790
|
+
cwd: promptDir
|
|
791
|
+
},
|
|
792
|
+
["."]
|
|
793
|
+
);
|
|
794
|
+
const tarBuffer = await fs2.readFile(tarPath);
|
|
795
|
+
const formData = new FormData();
|
|
796
|
+
formData.append("name", storageName);
|
|
797
|
+
formData.append("type", "volume");
|
|
798
|
+
formData.append(
|
|
799
|
+
"file",
|
|
800
|
+
new Blob([new Uint8Array(tarBuffer)], { type: "application/gzip" }),
|
|
801
|
+
"volume.tar.gz"
|
|
802
|
+
);
|
|
803
|
+
const response = await apiClient.post("/api/storages", {
|
|
804
|
+
body: formData
|
|
805
|
+
});
|
|
806
|
+
if (!response.ok) {
|
|
807
|
+
const errorBody = await response.json();
|
|
808
|
+
const errorMessage = typeof errorBody.error === "string" ? errorBody.error : errorBody.error?.message || "Upload failed";
|
|
809
|
+
throw new Error(errorMessage);
|
|
810
|
+
}
|
|
811
|
+
const result = await response.json();
|
|
812
|
+
return {
|
|
813
|
+
name: storageName,
|
|
814
|
+
versionId: result.versionId,
|
|
815
|
+
action: result.deduplicated ? "deduplicated" : "created"
|
|
816
|
+
};
|
|
817
|
+
} finally {
|
|
818
|
+
await fs2.rm(tmpDir, { recursive: true, force: true });
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
async function uploadSystemSkill(skillUrl) {
|
|
822
|
+
const parsed = parseGitHubTreeUrl(skillUrl);
|
|
823
|
+
const storageName = getSkillStorageName(parsed);
|
|
824
|
+
const tmpDir = await fs2.mkdtemp(path2.join(os2.tmpdir(), "vm0-skill-"));
|
|
825
|
+
try {
|
|
826
|
+
const skillDir = await downloadGitHubSkill(parsed, tmpDir);
|
|
827
|
+
await validateSkillDirectory(skillDir);
|
|
828
|
+
const tarPath = path2.join(tmpDir, "skill.tar.gz");
|
|
829
|
+
await tar.create(
|
|
830
|
+
{
|
|
831
|
+
gzip: true,
|
|
832
|
+
file: tarPath,
|
|
833
|
+
cwd: skillDir
|
|
834
|
+
},
|
|
835
|
+
["."]
|
|
836
|
+
);
|
|
837
|
+
const tarBuffer = await fs2.readFile(tarPath);
|
|
838
|
+
const formData = new FormData();
|
|
839
|
+
formData.append("name", storageName);
|
|
840
|
+
formData.append("type", "volume");
|
|
841
|
+
formData.append(
|
|
842
|
+
"file",
|
|
843
|
+
new Blob([new Uint8Array(tarBuffer)], { type: "application/gzip" }),
|
|
844
|
+
"volume.tar.gz"
|
|
845
|
+
);
|
|
846
|
+
const response = await apiClient.post("/api/storages", {
|
|
847
|
+
body: formData
|
|
848
|
+
});
|
|
849
|
+
if (!response.ok) {
|
|
850
|
+
const errorBody = await response.json();
|
|
851
|
+
const errorMessage = typeof errorBody.error === "string" ? errorBody.error : errorBody.error?.message || "Upload failed";
|
|
852
|
+
throw new Error(errorMessage);
|
|
853
|
+
}
|
|
854
|
+
const result = await response.json();
|
|
855
|
+
return {
|
|
856
|
+
name: storageName,
|
|
857
|
+
versionId: result.versionId,
|
|
858
|
+
action: result.deduplicated ? "deduplicated" : "created"
|
|
859
|
+
};
|
|
860
|
+
} finally {
|
|
861
|
+
await fs2.rm(tmpDir, { recursive: true, force: true });
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
635
865
|
// src/commands/compose.ts
|
|
636
866
|
var composeCommand = new Command().name("compose").description("Create or update agent compose").argument("<config-file>", "Path to config YAML file").action(async (configFile) => {
|
|
637
867
|
try {
|
|
@@ -639,7 +869,7 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
639
869
|
console.error(chalk2.red(`\u2717 Config file not found: ${configFile}`));
|
|
640
870
|
process.exit(1);
|
|
641
871
|
}
|
|
642
|
-
const content = await
|
|
872
|
+
const content = await readFile3(configFile, "utf8");
|
|
643
873
|
let config2;
|
|
644
874
|
try {
|
|
645
875
|
config2 = parseYaml(content);
|
|
@@ -655,6 +885,69 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
655
885
|
console.error(chalk2.red(`\u2717 ${validation.error}`));
|
|
656
886
|
process.exit(1);
|
|
657
887
|
}
|
|
888
|
+
const cfg = config2;
|
|
889
|
+
const agents = cfg.agents;
|
|
890
|
+
const agentName = Object.keys(agents)[0];
|
|
891
|
+
const agent = agents[agentName];
|
|
892
|
+
const basePath = dirname2(configFile);
|
|
893
|
+
if (agent.provider) {
|
|
894
|
+
const defaults = getProviderDefaults(agent.provider);
|
|
895
|
+
if (defaults) {
|
|
896
|
+
if (!agent.working_dir) {
|
|
897
|
+
agent.working_dir = defaults.workingDir;
|
|
898
|
+
console.log(
|
|
899
|
+
chalk2.gray(
|
|
900
|
+
` Auto-configured working_dir: ${defaults.workingDir}`
|
|
901
|
+
)
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
if (agent.beta_system_prompt) {
|
|
907
|
+
const promptPath = agent.beta_system_prompt;
|
|
908
|
+
console.log(chalk2.blue(`Uploading system prompt: ${promptPath}`));
|
|
909
|
+
try {
|
|
910
|
+
const result = await uploadSystemPrompt(
|
|
911
|
+
agentName,
|
|
912
|
+
promptPath,
|
|
913
|
+
basePath
|
|
914
|
+
);
|
|
915
|
+
console.log(
|
|
916
|
+
chalk2.green(
|
|
917
|
+
`\u2713 System prompt ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.versionId.slice(0, 8)}`
|
|
918
|
+
)
|
|
919
|
+
);
|
|
920
|
+
} catch (error43) {
|
|
921
|
+
console.error(chalk2.red(`\u2717 Failed to upload system prompt`));
|
|
922
|
+
if (error43 instanceof Error) {
|
|
923
|
+
console.error(chalk2.gray(` ${error43.message}`));
|
|
924
|
+
}
|
|
925
|
+
process.exit(1);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
if (agent.beta_system_skills && Array.isArray(agent.beta_system_skills)) {
|
|
929
|
+
const skillUrls = agent.beta_system_skills;
|
|
930
|
+
console.log(
|
|
931
|
+
chalk2.blue(`Uploading ${skillUrls.length} system skill(s)...`)
|
|
932
|
+
);
|
|
933
|
+
for (const skillUrl of skillUrls) {
|
|
934
|
+
try {
|
|
935
|
+
console.log(chalk2.gray(` Downloading: ${skillUrl}`));
|
|
936
|
+
const result = await uploadSystemSkill(skillUrl);
|
|
937
|
+
console.log(
|
|
938
|
+
chalk2.green(
|
|
939
|
+
` \u2713 Skill ${result.action === "deduplicated" ? "(unchanged)" : "uploaded"}: ${result.versionId.slice(0, 8)}`
|
|
940
|
+
)
|
|
941
|
+
);
|
|
942
|
+
} catch (error43) {
|
|
943
|
+
console.error(chalk2.red(`\u2717 Failed to upload skill: ${skillUrl}`));
|
|
944
|
+
if (error43 instanceof Error) {
|
|
945
|
+
console.error(chalk2.gray(` ${error43.message}`));
|
|
946
|
+
}
|
|
947
|
+
process.exit(1);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
658
951
|
console.log(chalk2.blue("Uploading compose..."));
|
|
659
952
|
const response = await apiClient.createOrUpdateCompose({
|
|
660
953
|
content: config2
|
|
@@ -695,8 +988,8 @@ var composeCommand = new Command().name("compose").description("Create or update
|
|
|
695
988
|
// src/commands/run.ts
|
|
696
989
|
import { Command as Command2 } from "commander";
|
|
697
990
|
import chalk4 from "chalk";
|
|
698
|
-
import * as
|
|
699
|
-
import * as
|
|
991
|
+
import * as fs3 from "fs";
|
|
992
|
+
import * as path3 from "path";
|
|
700
993
|
import { config as dotenvConfig } from "dotenv";
|
|
701
994
|
|
|
702
995
|
// src/lib/event-parser.ts
|
|
@@ -1777,10 +2070,10 @@ function mergeDefs(...defs) {
|
|
|
1777
2070
|
function cloneDef(schema) {
|
|
1778
2071
|
return mergeDefs(schema._zod.def);
|
|
1779
2072
|
}
|
|
1780
|
-
function getElementAtPath(obj,
|
|
1781
|
-
if (!
|
|
2073
|
+
function getElementAtPath(obj, path13) {
|
|
2074
|
+
if (!path13)
|
|
1782
2075
|
return obj;
|
|
1783
|
-
return
|
|
2076
|
+
return path13.reduce((acc, key) => acc?.[key], obj);
|
|
1784
2077
|
}
|
|
1785
2078
|
function promiseAllObject(promisesObj) {
|
|
1786
2079
|
const keys = Object.keys(promisesObj);
|
|
@@ -2139,11 +2432,11 @@ function aborted(x, startIndex = 0) {
|
|
|
2139
2432
|
}
|
|
2140
2433
|
return false;
|
|
2141
2434
|
}
|
|
2142
|
-
function prefixIssues(
|
|
2435
|
+
function prefixIssues(path13, issues) {
|
|
2143
2436
|
return issues.map((iss) => {
|
|
2144
2437
|
var _a;
|
|
2145
2438
|
(_a = iss).path ?? (_a.path = []);
|
|
2146
|
-
iss.path.unshift(
|
|
2439
|
+
iss.path.unshift(path13);
|
|
2147
2440
|
return iss;
|
|
2148
2441
|
});
|
|
2149
2442
|
}
|
|
@@ -2311,7 +2604,7 @@ function treeifyError(error43, _mapper) {
|
|
|
2311
2604
|
return issue2.message;
|
|
2312
2605
|
};
|
|
2313
2606
|
const result = { errors: [] };
|
|
2314
|
-
const processError = (error44,
|
|
2607
|
+
const processError = (error44, path13 = []) => {
|
|
2315
2608
|
var _a, _b;
|
|
2316
2609
|
for (const issue2 of error44.issues) {
|
|
2317
2610
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -2321,7 +2614,7 @@ function treeifyError(error43, _mapper) {
|
|
|
2321
2614
|
} else if (issue2.code === "invalid_element") {
|
|
2322
2615
|
processError({ issues: issue2.issues }, issue2.path);
|
|
2323
2616
|
} else {
|
|
2324
|
-
const fullpath = [...
|
|
2617
|
+
const fullpath = [...path13, ...issue2.path];
|
|
2325
2618
|
if (fullpath.length === 0) {
|
|
2326
2619
|
result.errors.push(mapper(issue2));
|
|
2327
2620
|
continue;
|
|
@@ -2353,8 +2646,8 @@ function treeifyError(error43, _mapper) {
|
|
|
2353
2646
|
}
|
|
2354
2647
|
function toDotPath(_path) {
|
|
2355
2648
|
const segs = [];
|
|
2356
|
-
const
|
|
2357
|
-
for (const seg of
|
|
2649
|
+
const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
2650
|
+
for (const seg of path13) {
|
|
2358
2651
|
if (typeof seg === "number")
|
|
2359
2652
|
segs.push(`[${seg}]`);
|
|
2360
2653
|
else if (typeof seg === "symbol")
|
|
@@ -13154,7 +13447,8 @@ var agentDefinitionSchema = external_exports.object({
|
|
|
13154
13447
|
image: external_exports.string().min(1, "Image is required"),
|
|
13155
13448
|
provider: external_exports.string().min(1, "Provider is required"),
|
|
13156
13449
|
volumes: external_exports.array(external_exports.string()).optional(),
|
|
13157
|
-
working_dir: external_exports.string().
|
|
13450
|
+
working_dir: external_exports.string().optional(),
|
|
13451
|
+
// Optional when provider supports auto-config
|
|
13158
13452
|
environment: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
13159
13453
|
/**
|
|
13160
13454
|
* Enable network security mode for secrets.
|
|
@@ -13162,7 +13456,17 @@ var agentDefinitionSchema = external_exports.object({
|
|
|
13162
13456
|
* is routed through mitmproxy -> VM0 Proxy for decryption.
|
|
13163
13457
|
* Default: false (plaintext secrets in env vars)
|
|
13164
13458
|
*/
|
|
13165
|
-
beta_network_security: external_exports.boolean().optional().default(false)
|
|
13459
|
+
beta_network_security: external_exports.boolean().optional().default(false),
|
|
13460
|
+
/**
|
|
13461
|
+
* Path to system prompt file (e.g., AGENTS.md).
|
|
13462
|
+
* Auto-uploaded as volume and mounted at /home/user/.config/claude/CLAUDE.md
|
|
13463
|
+
*/
|
|
13464
|
+
beta_system_prompt: external_exports.string().optional(),
|
|
13465
|
+
/**
|
|
13466
|
+
* Array of GitHub tree URLs for system skills.
|
|
13467
|
+
* Each skill is auto-downloaded and mounted at /home/user/.config/claude/skills/{skillName}/
|
|
13468
|
+
*/
|
|
13469
|
+
beta_system_skills: external_exports.array(external_exports.string()).optional()
|
|
13166
13470
|
});
|
|
13167
13471
|
var agentComposeContentSchema = external_exports.object({
|
|
13168
13472
|
version: external_exports.string().min(1, "Version is required"),
|
|
@@ -14214,9 +14518,9 @@ function loadValues(cliValues, configNames) {
|
|
|
14214
14518
|
const result = { ...cliValues };
|
|
14215
14519
|
const missingNames = configNames.filter((name) => !(name in result));
|
|
14216
14520
|
if (missingNames.length > 0) {
|
|
14217
|
-
const envFilePath =
|
|
14521
|
+
const envFilePath = path3.resolve(process.cwd(), ".env");
|
|
14218
14522
|
let dotenvValues = {};
|
|
14219
|
-
if (
|
|
14523
|
+
if (fs3.existsSync(envFilePath)) {
|
|
14220
14524
|
const dotenvResult = dotenvConfig({ path: envFilePath });
|
|
14221
14525
|
if (dotenvResult.parsed) {
|
|
14222
14526
|
dotenvValues = Object.fromEntries(
|
|
@@ -14696,13 +15000,13 @@ import { Command as Command6 } from "commander";
|
|
|
14696
15000
|
// src/commands/volume/init.ts
|
|
14697
15001
|
import { Command as Command3 } from "commander";
|
|
14698
15002
|
import chalk5 from "chalk";
|
|
14699
|
-
import
|
|
15003
|
+
import path5 from "path";
|
|
14700
15004
|
|
|
14701
15005
|
// src/lib/storage-utils.ts
|
|
14702
|
-
import { readFile as
|
|
15006
|
+
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
14703
15007
|
import { existsSync as existsSync4 } from "fs";
|
|
14704
15008
|
import { parse as parseYaml2, stringify as stringifyYaml } from "yaml";
|
|
14705
|
-
import
|
|
15009
|
+
import path4 from "path";
|
|
14706
15010
|
var CONFIG_DIR2 = ".vm0";
|
|
14707
15011
|
var CONFIG_FILE2 = "storage.yaml";
|
|
14708
15012
|
function isValidStorageName(name) {
|
|
@@ -14713,8 +15017,8 @@ function isValidStorageName(name) {
|
|
|
14713
15017
|
return pattern.test(name) && !name.includes("--");
|
|
14714
15018
|
}
|
|
14715
15019
|
async function readStorageConfig(basePath = process.cwd()) {
|
|
14716
|
-
const configPath =
|
|
14717
|
-
const legacyConfigPath =
|
|
15020
|
+
const configPath = path4.join(basePath, CONFIG_DIR2, CONFIG_FILE2);
|
|
15021
|
+
const legacyConfigPath = path4.join(basePath, CONFIG_DIR2, "volume.yaml");
|
|
14718
15022
|
let actualPath = null;
|
|
14719
15023
|
if (existsSync4(configPath)) {
|
|
14720
15024
|
actualPath = configPath;
|
|
@@ -14724,7 +15028,7 @@ async function readStorageConfig(basePath = process.cwd()) {
|
|
|
14724
15028
|
if (!actualPath) {
|
|
14725
15029
|
return null;
|
|
14726
15030
|
}
|
|
14727
|
-
const content = await
|
|
15031
|
+
const content = await readFile4(actualPath, "utf8");
|
|
14728
15032
|
const config2 = parseYaml2(content);
|
|
14729
15033
|
if (!config2.type) {
|
|
14730
15034
|
config2.type = "volume";
|
|
@@ -14732,31 +15036,31 @@ async function readStorageConfig(basePath = process.cwd()) {
|
|
|
14732
15036
|
return config2;
|
|
14733
15037
|
}
|
|
14734
15038
|
async function writeStorageConfig(storageName, basePath = process.cwd(), type = "volume") {
|
|
14735
|
-
const configDir =
|
|
14736
|
-
const configPath =
|
|
15039
|
+
const configDir = path4.join(basePath, CONFIG_DIR2);
|
|
15040
|
+
const configPath = path4.join(configDir, CONFIG_FILE2);
|
|
14737
15041
|
if (!existsSync4(configDir)) {
|
|
14738
|
-
await
|
|
15042
|
+
await mkdir4(configDir, { recursive: true });
|
|
14739
15043
|
}
|
|
14740
15044
|
const config2 = {
|
|
14741
15045
|
name: storageName,
|
|
14742
15046
|
type
|
|
14743
15047
|
};
|
|
14744
15048
|
const yamlContent = stringifyYaml(config2);
|
|
14745
|
-
await
|
|
15049
|
+
await writeFile4(configPath, yamlContent, "utf8");
|
|
14746
15050
|
}
|
|
14747
15051
|
|
|
14748
15052
|
// src/commands/volume/init.ts
|
|
14749
15053
|
var initCommand = new Command3().name("init").description("Initialize a volume in the current directory").action(async () => {
|
|
14750
15054
|
try {
|
|
14751
15055
|
const cwd = process.cwd();
|
|
14752
|
-
const dirName =
|
|
15056
|
+
const dirName = path5.basename(cwd);
|
|
14753
15057
|
const existingConfig = await readStorageConfig(cwd);
|
|
14754
15058
|
if (existingConfig) {
|
|
14755
15059
|
console.log(
|
|
14756
15060
|
chalk5.yellow(`Volume already initialized: ${existingConfig.name}`)
|
|
14757
15061
|
);
|
|
14758
15062
|
console.log(
|
|
14759
|
-
chalk5.gray(`Config file: ${
|
|
15063
|
+
chalk5.gray(`Config file: ${path5.join(cwd, ".vm0", "storage.yaml")}`)
|
|
14760
15064
|
);
|
|
14761
15065
|
return;
|
|
14762
15066
|
}
|
|
@@ -14777,7 +15081,7 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
14777
15081
|
console.log(chalk5.green(`\u2713 Initialized volume: ${volumeName}`));
|
|
14778
15082
|
console.log(
|
|
14779
15083
|
chalk5.gray(
|
|
14780
|
-
`\u2713 Config saved to ${
|
|
15084
|
+
`\u2713 Config saved to ${path5.join(cwd, ".vm0", "storage.yaml")}`
|
|
14781
15085
|
)
|
|
14782
15086
|
);
|
|
14783
15087
|
} catch (error43) {
|
|
@@ -14792,15 +15096,15 @@ var initCommand = new Command3().name("init").description("Initialize a volume i
|
|
|
14792
15096
|
// src/commands/volume/push.ts
|
|
14793
15097
|
import { Command as Command4 } from "commander";
|
|
14794
15098
|
import chalk6 from "chalk";
|
|
14795
|
-
import
|
|
14796
|
-
import * as
|
|
14797
|
-
import * as
|
|
14798
|
-
import * as
|
|
15099
|
+
import path7 from "path";
|
|
15100
|
+
import * as fs5 from "fs";
|
|
15101
|
+
import * as os3 from "os";
|
|
15102
|
+
import * as tar3 from "tar";
|
|
14799
15103
|
|
|
14800
15104
|
// src/lib/file-utils.ts
|
|
14801
|
-
import * as
|
|
14802
|
-
import * as
|
|
14803
|
-
import * as
|
|
15105
|
+
import * as fs4 from "fs";
|
|
15106
|
+
import * as path6 from "path";
|
|
15107
|
+
import * as tar2 from "tar";
|
|
14804
15108
|
function excludeVm0Filter(filePath) {
|
|
14805
15109
|
const shouldExclude = filePath === ".vm0" || filePath.startsWith(".vm0/") || filePath.startsWith("./.vm0");
|
|
14806
15110
|
return !shouldExclude;
|
|
@@ -14808,7 +15112,7 @@ function excludeVm0Filter(filePath) {
|
|
|
14808
15112
|
function listTarFiles(tarPath) {
|
|
14809
15113
|
return new Promise((resolve2, reject) => {
|
|
14810
15114
|
const files = [];
|
|
14811
|
-
|
|
15115
|
+
tar2.list({
|
|
14812
15116
|
file: tarPath,
|
|
14813
15117
|
onReadEntry: (entry) => {
|
|
14814
15118
|
if (entry.type === "File") {
|
|
@@ -14821,14 +15125,14 @@ function listTarFiles(tarPath) {
|
|
|
14821
15125
|
async function listLocalFiles(dir, excludeDirs = [".vm0"]) {
|
|
14822
15126
|
const files = [];
|
|
14823
15127
|
async function walkDir(currentDir, relativePath = "") {
|
|
14824
|
-
const entries = await
|
|
15128
|
+
const entries = await fs4.promises.readdir(currentDir, {
|
|
14825
15129
|
withFileTypes: true
|
|
14826
15130
|
});
|
|
14827
15131
|
for (const entry of entries) {
|
|
14828
|
-
const entryRelativePath = relativePath ?
|
|
15132
|
+
const entryRelativePath = relativePath ? path6.join(relativePath, entry.name) : entry.name;
|
|
14829
15133
|
if (entry.isDirectory()) {
|
|
14830
15134
|
if (!excludeDirs.includes(entry.name)) {
|
|
14831
|
-
await walkDir(
|
|
15135
|
+
await walkDir(path6.join(currentDir, entry.name), entryRelativePath);
|
|
14832
15136
|
}
|
|
14833
15137
|
} else {
|
|
14834
15138
|
files.push(entryRelativePath);
|
|
@@ -14844,8 +15148,8 @@ async function removeExtraFiles(dir, remoteFiles, excludeDirs = [".vm0"]) {
|
|
|
14844
15148
|
for (const localFile of localFiles) {
|
|
14845
15149
|
const normalizedPath = localFile.replace(/\\/g, "/");
|
|
14846
15150
|
if (!remoteFiles.has(normalizedPath)) {
|
|
14847
|
-
const fullPath =
|
|
14848
|
-
await
|
|
15151
|
+
const fullPath = path6.join(dir, localFile);
|
|
15152
|
+
await fs4.promises.unlink(fullPath);
|
|
14849
15153
|
removedCount++;
|
|
14850
15154
|
}
|
|
14851
15155
|
}
|
|
@@ -14853,17 +15157,17 @@ async function removeExtraFiles(dir, remoteFiles, excludeDirs = [".vm0"]) {
|
|
|
14853
15157
|
return removedCount;
|
|
14854
15158
|
}
|
|
14855
15159
|
async function removeEmptyDirs(dir, excludeDirs = [".vm0"]) {
|
|
14856
|
-
const entries = await
|
|
15160
|
+
const entries = await fs4.promises.readdir(dir, { withFileTypes: true });
|
|
14857
15161
|
let isEmpty = true;
|
|
14858
15162
|
for (const entry of entries) {
|
|
14859
|
-
const fullPath =
|
|
15163
|
+
const fullPath = path6.join(dir, entry.name);
|
|
14860
15164
|
if (entry.isDirectory()) {
|
|
14861
15165
|
if (excludeDirs.includes(entry.name)) {
|
|
14862
15166
|
isEmpty = false;
|
|
14863
15167
|
} else {
|
|
14864
15168
|
const subDirEmpty = await removeEmptyDirs(fullPath, excludeDirs);
|
|
14865
15169
|
if (subDirEmpty) {
|
|
14866
|
-
await
|
|
15170
|
+
await fs4.promises.rmdir(fullPath);
|
|
14867
15171
|
} else {
|
|
14868
15172
|
isEmpty = false;
|
|
14869
15173
|
}
|
|
@@ -14878,10 +15182,10 @@ async function removeEmptyDirs(dir, excludeDirs = [".vm0"]) {
|
|
|
14878
15182
|
// src/commands/volume/push.ts
|
|
14879
15183
|
async function getAllFiles(dirPath, baseDir = dirPath) {
|
|
14880
15184
|
const files = [];
|
|
14881
|
-
const entries = await
|
|
15185
|
+
const entries = await fs5.promises.readdir(dirPath, { withFileTypes: true });
|
|
14882
15186
|
for (const entry of entries) {
|
|
14883
|
-
const fullPath =
|
|
14884
|
-
const relativePath =
|
|
15187
|
+
const fullPath = path7.join(dirPath, entry.name);
|
|
15188
|
+
const relativePath = path7.relative(baseDir, fullPath);
|
|
14885
15189
|
if (relativePath.startsWith(".vm0")) {
|
|
14886
15190
|
continue;
|
|
14887
15191
|
}
|
|
@@ -14918,7 +15222,7 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
14918
15222
|
const files = await getAllFiles(cwd);
|
|
14919
15223
|
let totalSize = 0;
|
|
14920
15224
|
for (const file2 of files) {
|
|
14921
|
-
const stats = await
|
|
15225
|
+
const stats = await fs5.promises.stat(file2);
|
|
14922
15226
|
totalSize += stats.size;
|
|
14923
15227
|
}
|
|
14924
15228
|
if (files.length === 0) {
|
|
@@ -14929,11 +15233,11 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
14929
15233
|
);
|
|
14930
15234
|
}
|
|
14931
15235
|
console.log(chalk6.gray("Compressing files..."));
|
|
14932
|
-
const tmpDir =
|
|
14933
|
-
const tarPath =
|
|
14934
|
-
const relativePaths = files.map((file2) =>
|
|
15236
|
+
const tmpDir = fs5.mkdtempSync(path7.join(os3.tmpdir(), "vm0-"));
|
|
15237
|
+
const tarPath = path7.join(tmpDir, "volume.tar.gz");
|
|
15238
|
+
const relativePaths = files.map((file2) => path7.relative(cwd, file2));
|
|
14935
15239
|
if (relativePaths.length > 0) {
|
|
14936
|
-
await
|
|
15240
|
+
await tar3.create(
|
|
14937
15241
|
{
|
|
14938
15242
|
gzip: true,
|
|
14939
15243
|
file: tarPath,
|
|
@@ -14942,7 +15246,7 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
14942
15246
|
relativePaths
|
|
14943
15247
|
);
|
|
14944
15248
|
} else {
|
|
14945
|
-
await
|
|
15249
|
+
await tar3.create(
|
|
14946
15250
|
{
|
|
14947
15251
|
gzip: true,
|
|
14948
15252
|
file: tarPath,
|
|
@@ -14952,9 +15256,9 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
14952
15256
|
["."]
|
|
14953
15257
|
);
|
|
14954
15258
|
}
|
|
14955
|
-
const tarBuffer = await
|
|
14956
|
-
await
|
|
14957
|
-
await
|
|
15259
|
+
const tarBuffer = await fs5.promises.readFile(tarPath);
|
|
15260
|
+
await fs5.promises.unlink(tarPath);
|
|
15261
|
+
await fs5.promises.rmdir(tmpDir);
|
|
14958
15262
|
console.log(
|
|
14959
15263
|
chalk6.green(`\u2713 Compressed to ${formatBytes(tarBuffer.length)}`)
|
|
14960
15264
|
);
|
|
@@ -15000,10 +15304,10 @@ var pushCommand = new Command4().name("push").description("Push local files to c
|
|
|
15000
15304
|
// src/commands/volume/pull.ts
|
|
15001
15305
|
import { Command as Command5 } from "commander";
|
|
15002
15306
|
import chalk7 from "chalk";
|
|
15003
|
-
import
|
|
15004
|
-
import * as
|
|
15005
|
-
import * as
|
|
15006
|
-
import * as
|
|
15307
|
+
import path8 from "path";
|
|
15308
|
+
import * as fs6 from "fs";
|
|
15309
|
+
import * as os4 from "os";
|
|
15310
|
+
import * as tar4 from "tar";
|
|
15007
15311
|
function formatBytes2(bytes) {
|
|
15008
15312
|
if (bytes === 0) return "0 B";
|
|
15009
15313
|
const k = 1024;
|
|
@@ -15053,9 +15357,9 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
15053
15357
|
const arrayBuffer = await response.arrayBuffer();
|
|
15054
15358
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
15055
15359
|
console.log(chalk7.green(`\u2713 Downloaded ${formatBytes2(tarBuffer.length)}`));
|
|
15056
|
-
const tmpDir =
|
|
15057
|
-
const tarPath =
|
|
15058
|
-
await
|
|
15360
|
+
const tmpDir = fs6.mkdtempSync(path8.join(os4.tmpdir(), "vm0-"));
|
|
15361
|
+
const tarPath = path8.join(tmpDir, "volume.tar.gz");
|
|
15362
|
+
await fs6.promises.writeFile(tarPath, tarBuffer);
|
|
15059
15363
|
console.log(chalk7.gray("Syncing local files..."));
|
|
15060
15364
|
const remoteFiles = await listTarFiles(tarPath);
|
|
15061
15365
|
const remoteFilesSet = new Set(
|
|
@@ -15068,13 +15372,13 @@ var pullCommand = new Command5().name("pull").description("Pull cloud files to l
|
|
|
15068
15372
|
);
|
|
15069
15373
|
}
|
|
15070
15374
|
console.log(chalk7.gray("Extracting files..."));
|
|
15071
|
-
await
|
|
15375
|
+
await tar4.extract({
|
|
15072
15376
|
file: tarPath,
|
|
15073
15377
|
cwd,
|
|
15074
15378
|
gzip: true
|
|
15075
15379
|
});
|
|
15076
|
-
await
|
|
15077
|
-
await
|
|
15380
|
+
await fs6.promises.unlink(tarPath);
|
|
15381
|
+
await fs6.promises.rmdir(tmpDir);
|
|
15078
15382
|
console.log(chalk7.green(`\u2713 Extracted ${remoteFiles.length} files`));
|
|
15079
15383
|
} catch (error43) {
|
|
15080
15384
|
console.error(chalk7.red("\u2717 Pull failed"));
|
|
@@ -15094,11 +15398,11 @@ import { Command as Command10 } from "commander";
|
|
|
15094
15398
|
// src/commands/artifact/init.ts
|
|
15095
15399
|
import { Command as Command7 } from "commander";
|
|
15096
15400
|
import chalk8 from "chalk";
|
|
15097
|
-
import
|
|
15401
|
+
import path9 from "path";
|
|
15098
15402
|
var initCommand2 = new Command7().name("init").description("Initialize an artifact in the current directory").action(async () => {
|
|
15099
15403
|
try {
|
|
15100
15404
|
const cwd = process.cwd();
|
|
15101
|
-
const dirName =
|
|
15405
|
+
const dirName = path9.basename(cwd);
|
|
15102
15406
|
const existingConfig = await readStorageConfig(cwd);
|
|
15103
15407
|
if (existingConfig) {
|
|
15104
15408
|
if (existingConfig.type === "artifact") {
|
|
@@ -15120,7 +15424,7 @@ var initCommand2 = new Command7().name("init").description("Initialize an artifa
|
|
|
15120
15424
|
);
|
|
15121
15425
|
}
|
|
15122
15426
|
console.log(
|
|
15123
|
-
chalk8.gray(`Config file: ${
|
|
15427
|
+
chalk8.gray(`Config file: ${path9.join(cwd, ".vm0", "storage.yaml")}`)
|
|
15124
15428
|
);
|
|
15125
15429
|
return;
|
|
15126
15430
|
}
|
|
@@ -15141,7 +15445,7 @@ var initCommand2 = new Command7().name("init").description("Initialize an artifa
|
|
|
15141
15445
|
console.log(chalk8.green(`\u2713 Initialized artifact: ${artifactName}`));
|
|
15142
15446
|
console.log(
|
|
15143
15447
|
chalk8.gray(
|
|
15144
|
-
`\u2713 Config saved to ${
|
|
15448
|
+
`\u2713 Config saved to ${path9.join(cwd, ".vm0", "storage.yaml")}`
|
|
15145
15449
|
)
|
|
15146
15450
|
);
|
|
15147
15451
|
} catch (error43) {
|
|
@@ -15156,16 +15460,16 @@ var initCommand2 = new Command7().name("init").description("Initialize an artifa
|
|
|
15156
15460
|
// src/commands/artifact/push.ts
|
|
15157
15461
|
import { Command as Command8 } from "commander";
|
|
15158
15462
|
import chalk9 from "chalk";
|
|
15159
|
-
import
|
|
15160
|
-
import * as
|
|
15161
|
-
import * as
|
|
15162
|
-
import * as
|
|
15463
|
+
import path10 from "path";
|
|
15464
|
+
import * as fs7 from "fs";
|
|
15465
|
+
import * as os5 from "os";
|
|
15466
|
+
import * as tar5 from "tar";
|
|
15163
15467
|
async function getAllFiles2(dirPath, baseDir = dirPath) {
|
|
15164
15468
|
const files = [];
|
|
15165
|
-
const entries = await
|
|
15469
|
+
const entries = await fs7.promises.readdir(dirPath, { withFileTypes: true });
|
|
15166
15470
|
for (const entry of entries) {
|
|
15167
|
-
const fullPath =
|
|
15168
|
-
const relativePath =
|
|
15471
|
+
const fullPath = path10.join(dirPath, entry.name);
|
|
15472
|
+
const relativePath = path10.relative(baseDir, fullPath);
|
|
15169
15473
|
if (relativePath.startsWith(".vm0")) {
|
|
15170
15474
|
continue;
|
|
15171
15475
|
}
|
|
@@ -15211,7 +15515,7 @@ var pushCommand2 = new Command8().name("push").description("Push local files to
|
|
|
15211
15515
|
const files = await getAllFiles2(cwd);
|
|
15212
15516
|
let totalSize = 0;
|
|
15213
15517
|
for (const file2 of files) {
|
|
15214
|
-
const stats = await
|
|
15518
|
+
const stats = await fs7.promises.stat(file2);
|
|
15215
15519
|
totalSize += stats.size;
|
|
15216
15520
|
}
|
|
15217
15521
|
if (files.length === 0) {
|
|
@@ -15222,11 +15526,11 @@ var pushCommand2 = new Command8().name("push").description("Push local files to
|
|
|
15222
15526
|
);
|
|
15223
15527
|
}
|
|
15224
15528
|
console.log(chalk9.gray("Compressing files..."));
|
|
15225
|
-
const tmpDir =
|
|
15226
|
-
const tarPath =
|
|
15227
|
-
const relativePaths = files.map((file2) =>
|
|
15529
|
+
const tmpDir = fs7.mkdtempSync(path10.join(os5.tmpdir(), "vm0-"));
|
|
15530
|
+
const tarPath = path10.join(tmpDir, "artifact.tar.gz");
|
|
15531
|
+
const relativePaths = files.map((file2) => path10.relative(cwd, file2));
|
|
15228
15532
|
if (relativePaths.length > 0) {
|
|
15229
|
-
await
|
|
15533
|
+
await tar5.create(
|
|
15230
15534
|
{
|
|
15231
15535
|
gzip: true,
|
|
15232
15536
|
file: tarPath,
|
|
@@ -15235,7 +15539,7 @@ var pushCommand2 = new Command8().name("push").description("Push local files to
|
|
|
15235
15539
|
relativePaths
|
|
15236
15540
|
);
|
|
15237
15541
|
} else {
|
|
15238
|
-
await
|
|
15542
|
+
await tar5.create(
|
|
15239
15543
|
{
|
|
15240
15544
|
gzip: true,
|
|
15241
15545
|
file: tarPath,
|
|
@@ -15245,9 +15549,9 @@ var pushCommand2 = new Command8().name("push").description("Push local files to
|
|
|
15245
15549
|
["."]
|
|
15246
15550
|
);
|
|
15247
15551
|
}
|
|
15248
|
-
const tarBuffer = await
|
|
15249
|
-
await
|
|
15250
|
-
await
|
|
15552
|
+
const tarBuffer = await fs7.promises.readFile(tarPath);
|
|
15553
|
+
await fs7.promises.unlink(tarPath);
|
|
15554
|
+
await fs7.promises.rmdir(tmpDir);
|
|
15251
15555
|
console.log(
|
|
15252
15556
|
chalk9.green(`\u2713 Compressed to ${formatBytes3(tarBuffer.length)}`)
|
|
15253
15557
|
);
|
|
@@ -15292,10 +15596,10 @@ var pushCommand2 = new Command8().name("push").description("Push local files to
|
|
|
15292
15596
|
// src/commands/artifact/pull.ts
|
|
15293
15597
|
import { Command as Command9 } from "commander";
|
|
15294
15598
|
import chalk10 from "chalk";
|
|
15295
|
-
import
|
|
15296
|
-
import * as
|
|
15297
|
-
import * as
|
|
15298
|
-
import * as
|
|
15599
|
+
import path11 from "path";
|
|
15600
|
+
import * as fs8 from "fs";
|
|
15601
|
+
import * as os6 from "os";
|
|
15602
|
+
import * as tar6 from "tar";
|
|
15299
15603
|
function formatBytes4(bytes) {
|
|
15300
15604
|
if (bytes === 0) return "0 B";
|
|
15301
15605
|
const k = 1024;
|
|
@@ -15356,9 +15660,9 @@ var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact
|
|
|
15356
15660
|
const arrayBuffer = await response.arrayBuffer();
|
|
15357
15661
|
const tarBuffer = Buffer.from(arrayBuffer);
|
|
15358
15662
|
console.log(chalk10.green(`\u2713 Downloaded ${formatBytes4(tarBuffer.length)}`));
|
|
15359
|
-
const tmpDir =
|
|
15360
|
-
const tarPath =
|
|
15361
|
-
await
|
|
15663
|
+
const tmpDir = fs8.mkdtempSync(path11.join(os6.tmpdir(), "vm0-"));
|
|
15664
|
+
const tarPath = path11.join(tmpDir, "artifact.tar.gz");
|
|
15665
|
+
await fs8.promises.writeFile(tarPath, tarBuffer);
|
|
15362
15666
|
console.log(chalk10.gray("Syncing local files..."));
|
|
15363
15667
|
const remoteFiles = await listTarFiles(tarPath);
|
|
15364
15668
|
const remoteFilesSet = new Set(
|
|
@@ -15371,13 +15675,13 @@ var pullCommand2 = new Command9().name("pull").description("Pull cloud artifact
|
|
|
15371
15675
|
);
|
|
15372
15676
|
}
|
|
15373
15677
|
console.log(chalk10.gray("Extracting files..."));
|
|
15374
|
-
await
|
|
15678
|
+
await tar6.extract({
|
|
15375
15679
|
file: tarPath,
|
|
15376
15680
|
cwd,
|
|
15377
15681
|
gzip: true
|
|
15378
15682
|
});
|
|
15379
|
-
await
|
|
15380
|
-
await
|
|
15683
|
+
await fs8.promises.unlink(tarPath);
|
|
15684
|
+
await fs8.promises.rmdir(tmpDir);
|
|
15381
15685
|
console.log(chalk10.green(`\u2713 Extracted ${remoteFiles.length} files`));
|
|
15382
15686
|
} catch (error43) {
|
|
15383
15687
|
console.error(chalk10.red("\u2717 Pull failed"));
|
|
@@ -15394,9 +15698,9 @@ var artifactCommand = new Command10().name("artifact").description("Manage cloud
|
|
|
15394
15698
|
// src/commands/cook.ts
|
|
15395
15699
|
import { Command as Command11 } from "commander";
|
|
15396
15700
|
import chalk11 from "chalk";
|
|
15397
|
-
import { readFile as
|
|
15701
|
+
import { readFile as readFile5, mkdir as mkdir5 } from "fs/promises";
|
|
15398
15702
|
import { existsSync as existsSync5 } from "fs";
|
|
15399
|
-
import
|
|
15703
|
+
import path12 from "path";
|
|
15400
15704
|
import { spawn } from "child_process";
|
|
15401
15705
|
import { parse as parseYaml3 } from "yaml";
|
|
15402
15706
|
var CONFIG_FILE3 = "vm0.yaml";
|
|
@@ -15485,7 +15789,7 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
15485
15789
|
}
|
|
15486
15790
|
let config2;
|
|
15487
15791
|
try {
|
|
15488
|
-
const content = await
|
|
15792
|
+
const content = await readFile5(CONFIG_FILE3, "utf8");
|
|
15489
15793
|
config2 = parseYaml3(content);
|
|
15490
15794
|
} catch (error43) {
|
|
15491
15795
|
console.error(chalk11.red("\u2717 Invalid YAML format"));
|
|
@@ -15509,7 +15813,7 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
15509
15813
|
console.log();
|
|
15510
15814
|
console.log(chalk11.blue("Processing volumes..."));
|
|
15511
15815
|
for (const volumeConfig of Object.values(config2.volumes)) {
|
|
15512
|
-
const volumeDir =
|
|
15816
|
+
const volumeDir = path12.join(cwd, volumeConfig.name);
|
|
15513
15817
|
console.log(chalk11.gray(` ${volumeConfig.name}/`));
|
|
15514
15818
|
if (!existsSync5(volumeDir)) {
|
|
15515
15819
|
console.error(
|
|
@@ -15544,11 +15848,11 @@ var cookCommand = new Command11().name("cook").description("One-click agent prep
|
|
|
15544
15848
|
}
|
|
15545
15849
|
console.log();
|
|
15546
15850
|
console.log(chalk11.blue("Processing artifact..."));
|
|
15547
|
-
const artifactDir =
|
|
15851
|
+
const artifactDir = path12.join(cwd, ARTIFACT_DIR);
|
|
15548
15852
|
console.log(chalk11.gray(` ${ARTIFACT_DIR}/`));
|
|
15549
15853
|
try {
|
|
15550
15854
|
if (!existsSync5(artifactDir)) {
|
|
15551
|
-
await
|
|
15855
|
+
await mkdir5(artifactDir, { recursive: true });
|
|
15552
15856
|
console.log(chalk11.green(` \u2713 Created directory`));
|
|
15553
15857
|
}
|
|
15554
15858
|
const existingConfig = await readStorageConfig(artifactDir);
|
|
@@ -15640,7 +15944,7 @@ import { Command as Command15 } from "commander";
|
|
|
15640
15944
|
// src/commands/image/build.ts
|
|
15641
15945
|
import { Command as Command12 } from "commander";
|
|
15642
15946
|
import chalk12 from "chalk";
|
|
15643
|
-
import { readFile as
|
|
15947
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
15644
15948
|
import { existsSync as existsSync6 } from "fs";
|
|
15645
15949
|
var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
15646
15950
|
var buildCommand = new Command12().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(
|
|
@@ -15668,7 +15972,7 @@ var buildCommand = new Command12().name("build").description("Build a custom ima
|
|
|
15668
15972
|
process.exit(1);
|
|
15669
15973
|
}
|
|
15670
15974
|
try {
|
|
15671
|
-
const dockerfile = await
|
|
15975
|
+
const dockerfile = await readFile6(file2, "utf8");
|
|
15672
15976
|
console.log(chalk12.blue(`Building image: ${name}`));
|
|
15673
15977
|
console.log(chalk12.gray(` Dockerfile: ${file2}`));
|
|
15674
15978
|
console.log();
|
|
@@ -16092,7 +16396,7 @@ function handleError(error43, runId) {
|
|
|
16092
16396
|
|
|
16093
16397
|
// src/index.ts
|
|
16094
16398
|
var program = new Command17();
|
|
16095
|
-
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.
|
|
16399
|
+
program.name("vm0").description("VM0 CLI - A modern build tool").version("4.8.0");
|
|
16096
16400
|
program.command("info").description("Display environment information").action(async () => {
|
|
16097
16401
|
console.log(chalk16.cyan("System Information:"));
|
|
16098
16402
|
console.log(`Node Version: ${process.version}`);
|