vmlive 1.0.12 → 1.0.14
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/package.json +1 -1
- package/src/cli.js +113 -19
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -683,19 +683,18 @@ const runLogin = async () => {
|
|
|
683
683
|
const runUpdate = async () => {
|
|
684
684
|
console.log('\x1b[36mUpdating vmlive to the latest version...\x1b[0m');
|
|
685
685
|
const { spawn } = await import('child_process');
|
|
686
|
-
|
|
686
|
+
|
|
687
687
|
const updateProcess = spawn('npm', ['install', 'vmlive@latest'], {
|
|
688
|
-
|
|
688
|
+
stdio: 'inherit'
|
|
689
689
|
});
|
|
690
690
|
|
|
691
691
|
updateProcess.on('exit', (code) => {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
});
|
|
692
|
+
if (code === 0) {
|
|
693
|
+
console.log('\n\x1b[32m✔ vmlive updated successfully!\x1b[0m');
|
|
694
|
+
} else {
|
|
695
|
+
console.error(`\n\x1b[31m❌ Update failed with exit code ${code}\x1b[0m`);
|
|
696
|
+
}
|
|
697
|
+
process.exit(code || 0);
|
|
699
698
|
});
|
|
700
699
|
};
|
|
701
700
|
|
|
@@ -703,20 +702,112 @@ const runLlm = async () => {
|
|
|
703
702
|
const GATEKEEPER_URL = process.env.GATEKEEPER_URL || 'https://api.vm.live';
|
|
704
703
|
console.log('\x1b[36mDownloading AI Context Guide...\x1b[0m');
|
|
705
704
|
try {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
705
|
+
const res = await fetch(`${GATEKEEPER_URL}/vmlive-ai-rules.md`);
|
|
706
|
+
if (!res.ok) {
|
|
707
|
+
console.error('\x1b[31m❌ Failed to download AI rules:\x1b[0m', res.status);
|
|
708
|
+
process.exit(1);
|
|
709
|
+
}
|
|
710
|
+
const markdown = await res.text();
|
|
711
|
+
fs.writeFileSync(path.join(process.cwd(), 'vmlive-ai-rules.md'), markdown);
|
|
712
|
+
console.log('\x1b[32m✔ Successfully wrote vmlive-ai-rules.md to current directory.\x1b[0m');
|
|
713
|
+
console.log('\x1b[90m(Add this to your prompt context so your AI perfectly architect endpoints for you!)\x1b[0m');
|
|
715
714
|
} catch (err) {
|
|
716
|
-
|
|
715
|
+
console.error('\x1b[31m❌ Connection Failed:\x1b[0m', err.message);
|
|
716
|
+
process.exit(1);
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
const runDb = async () => {
|
|
720
|
+
const subcommand = process.argv[3];
|
|
721
|
+
const envArg = process.argv[4];
|
|
722
|
+
|
|
723
|
+
if (subcommand !== 'push') {
|
|
724
|
+
console.error('\x1b[31m❌ Unknown DB command:\x1b[0m Must be `vmlive db push local` or `vmlive db push remote`');
|
|
725
|
+
process.exit(1);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (envArg !== 'local' && envArg !== 'remote') {
|
|
729
|
+
console.error('\x1b[31m❌ Missing Target:\x1b[0m Please specify environment `local` or `remote`');
|
|
730
|
+
process.exit(1);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (!fs.existsSync(CONFIG_PATH)) {
|
|
734
|
+
console.error('\x1b[31m❌ Project Not Found:\x1b[0m You must be inside a vmlive project folder.');
|
|
735
|
+
process.exit(1);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const vmConf = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
|
|
739
|
+
const migrationsDir = path.resolve('migrations');
|
|
740
|
+
|
|
741
|
+
if (!fs.existsSync(migrationsDir)) {
|
|
742
|
+
console.log('\x1b[33m⚠ No migrations folder found.\x1b[0m Skipping.');
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
const files = fs.readdirSync(migrationsDir)
|
|
747
|
+
.filter(f => f.endsWith('.sql'))
|
|
748
|
+
.sort();
|
|
749
|
+
|
|
750
|
+
if (files.length === 0) {
|
|
751
|
+
console.log('\x1b[32m✔ No pending migrations found.\x1b[0m');
|
|
752
|
+
return;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
console.log(`\x1b[36mFound ${files.length} migration files. Pushing to [${envArg.toUpperCase()}]...\x1b[0m`);
|
|
756
|
+
|
|
757
|
+
let combinedSql = '';
|
|
758
|
+
for (const file of files) {
|
|
759
|
+
combinedSql += fs.readFileSync(path.join(migrationsDir, file), 'utf-8') + '\n';
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (envArg === 'local') {
|
|
763
|
+
console.log('\x1b[90mSyncing Local V8 Emulator D1...\x1b[0m');
|
|
764
|
+
const mf = new Emulator({
|
|
765
|
+
modules: true,
|
|
766
|
+
script: 'export default { fetch: () => new Response("ok") }',
|
|
767
|
+
d1Databases: ["DB"]
|
|
768
|
+
});
|
|
769
|
+
try {
|
|
770
|
+
const db = await mf.getD1Database("DB");
|
|
771
|
+
await db.exec(combinedSql);
|
|
772
|
+
console.log('\x1b[32m✔ Local Database push successful.\x1b[0m');
|
|
773
|
+
} catch(e) {
|
|
774
|
+
console.error('\n\x1b[31m❌ Local execute failed:\x1b[0m', e.message);
|
|
775
|
+
}
|
|
776
|
+
await mf.dispose();
|
|
777
|
+
} else {
|
|
778
|
+
const GATEKEEPER_URL = process.env.GATEKEEPER_URL || 'https://api.vm.live';
|
|
779
|
+
const configPath = path.join(os.homedir(), '.vm-config.json');
|
|
780
|
+
let jwtToken = process.env.VM_API_TOKEN;
|
|
781
|
+
if (!jwtToken && fs.existsSync(configPath)) {
|
|
782
|
+
jwtToken = JSON.parse(fs.readFileSync(configPath, 'utf-8')).token;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
if (!jwtToken) {
|
|
786
|
+
console.error('\x1b[31m❌ Unauthorized.\x1b[0m Please run `vmlive login` first.');
|
|
717
787
|
process.exit(1);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const { projectId } = vmConf;
|
|
791
|
+
console.log(`\x1b[90mSyncing Cloudflare Edge D1 [${projectId}]...\x1b[0m`);
|
|
792
|
+
|
|
793
|
+
try {
|
|
794
|
+
const res = await fetch(`${GATEKEEPER_URL}/api/projects/${projectId}/database/migrate`, {
|
|
795
|
+
method: 'POST',
|
|
796
|
+
headers: { 'Authorization': `Bearer ${jwtToken}`, 'Content-Type': 'application/json' },
|
|
797
|
+
body: JSON.stringify({ sql: combinedSql })
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
if (res.ok) {
|
|
801
|
+
console.log('\n\x1b[32m✔ Cloudflare D1 Remote Pipeline successfully upgraded.\x1b[0m');
|
|
802
|
+
} else {
|
|
803
|
+
console.error('\n\x1b[31m❌ Remote Migration Error:\x1b[0m', res.status, await res.text());
|
|
804
|
+
}
|
|
805
|
+
} catch (err) {
|
|
806
|
+
console.error('\n\x1b[31m❌ Network Failure:\x1b[0m', err.message);
|
|
807
|
+
}
|
|
718
808
|
}
|
|
719
809
|
};
|
|
810
|
+
|
|
720
811
|
const main = async () => {
|
|
721
812
|
const command = process.argv[2];
|
|
722
813
|
if (command === 'init') {
|
|
@@ -733,6 +824,8 @@ const main = async () => {
|
|
|
733
824
|
await runUpdate();
|
|
734
825
|
} else if (command === 'llm') {
|
|
735
826
|
await runLlm();
|
|
827
|
+
} else if (command === 'db') {
|
|
828
|
+
await runDb();
|
|
736
829
|
} else if (command === 'help' || !command) {
|
|
737
830
|
console.log('\n\x1b[1m\x1b[36mvm.live\x1b[0m - Serverless Edge Compute Engine');
|
|
738
831
|
console.log('Usage: vmlive <command>\n');
|
|
@@ -742,6 +835,7 @@ const main = async () => {
|
|
|
742
835
|
console.log(' \x1b[32mdev\x1b[0m Start the local emulator and dashboard over localhost');
|
|
743
836
|
console.log(' \x1b[32mlogin\x1b[0m Authenticate your local environment securely via Stripe/OAuth');
|
|
744
837
|
console.log(' \x1b[32mdeploy\x1b[0m Upload your footprint to the vm.live edge platform');
|
|
838
|
+
console.log(' \x1b[32mdb\x1b[0m Manage Cloudflare D1 schema migrations (`db push local|remote`)');
|
|
745
839
|
console.log(' \x1b[32mllm\x1b[0m Download the official AI Context Rules for agentic workflows');
|
|
746
840
|
console.log(' \x1b[32mupdate\x1b[0m Upgrade this CLI engine to the latest published version');
|
|
747
841
|
console.log(' \x1b[32mwhich\x1b[0m Display the currently active CLI version');
|