bvm-core 1.1.16 → 1.1.18
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/README.md +7 -7
- package/README.zh-CN.md +7 -7
- package/bin/bvm-npm.js +46 -0
- package/dist/index.js +1 -1
- package/install.ps1 +2 -2
- package/install.sh +1 -1
- package/package.json +6 -5
- package/scripts/postinstall.js +149 -245
package/README.md
CHANGED
|
@@ -37,21 +37,21 @@
|
|
|
37
37
|
|
|
38
38
|
BVM uses a smart installation script that automatically detects your OS and network environment (selecting the fastest registry for China/Global users).
|
|
39
39
|
|
|
40
|
-
### Method 1:
|
|
41
|
-
```bash
|
|
42
|
-
npm install -g bvm-core@latest
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Method 2: Shell Script (macOS / Linux)
|
|
40
|
+
### Method 1: Shell Script (Recommended - macOS / Linux)
|
|
46
41
|
```bash
|
|
47
42
|
curl -fsSL https://bvm-core.pages.dev/install | bash
|
|
48
43
|
```
|
|
49
44
|
|
|
50
|
-
### Method
|
|
45
|
+
### Method 2: PowerShell (Recommended - Windows)
|
|
51
46
|
```powershell
|
|
52
47
|
irm https://bvm-core.pages.dev/install | iex
|
|
53
48
|
```
|
|
54
49
|
|
|
50
|
+
### Method 3: NPM (Optional)
|
|
51
|
+
```bash
|
|
52
|
+
npm install -g bvm-core@latest
|
|
53
|
+
```
|
|
54
|
+
|
|
55
55
|
---
|
|
56
56
|
|
|
57
57
|
## Key Features
|
package/README.zh-CN.md
CHANGED
|
@@ -37,21 +37,21 @@
|
|
|
37
37
|
|
|
38
38
|
BVM 提供了智能安装脚本,**自动检测您的网络环境**。中国用户会自动切换至淘宝镜像源,海外用户使用官方源,无需手动配置。
|
|
39
39
|
|
|
40
|
-
### 方式 1:
|
|
41
|
-
```bash
|
|
42
|
-
npm install -g bvm-core@latest
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### 方式 2: Shell 脚本 (macOS / Linux)
|
|
40
|
+
### 方式 1: Shell 脚本 (推荐 - macOS / Linux)
|
|
46
41
|
```bash
|
|
47
42
|
curl -fsSL https://bvm-core.pages.dev/install | bash
|
|
48
43
|
```
|
|
49
44
|
|
|
50
|
-
### 方式
|
|
45
|
+
### 方式 2: PowerShell (推荐 - Windows)
|
|
51
46
|
```powershell
|
|
52
47
|
irm https://bvm-core.pages.dev/install | iex
|
|
53
48
|
```
|
|
54
49
|
|
|
50
|
+
### 方式 3: NPM (可选)
|
|
51
|
+
```bash
|
|
52
|
+
npm install -g bvm-core@latest
|
|
53
|
+
```
|
|
54
|
+
|
|
55
55
|
---
|
|
56
56
|
|
|
57
57
|
## 核心特性
|
package/bin/bvm-npm.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* BVM NPM Smart Entry Point
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { spawnSync } = require('child_process');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
|
|
12
|
+
const IS_WINDOWS = os.platform() === 'win32';
|
|
13
|
+
const HOME = process.env.HOME || os.homedir();
|
|
14
|
+
const BVM_DIR = process.env.BVM_DIR || path.join(HOME, '.bvm');
|
|
15
|
+
const BVM_SRC = path.join(BVM_DIR, 'src', 'index.js');
|
|
16
|
+
const BUN_RUNTIME = path.join(BVM_DIR, 'runtime', 'current', 'bin', IS_WINDOWS ? 'bun.exe' : 'bun');
|
|
17
|
+
|
|
18
|
+
function run(bin, args) {
|
|
19
|
+
return spawnSync(bin, args, {
|
|
20
|
+
stdio: 'inherit',
|
|
21
|
+
env: Object.assign({}, process.env, { BVM_DIR }),
|
|
22
|
+
shell: IS_WINDOWS && bin.indexOf(' ') !== -1
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// 1. 优先尝试 BVM 内部的地堡运行时
|
|
27
|
+
if (fs.existsSync(BUN_RUNTIME)) {
|
|
28
|
+
const result = run(BUN_RUNTIME, [BVM_SRC, ...process.argv.slice(2)]);
|
|
29
|
+
process.exit(result.status || 0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 2. 其次尝试使用 Node 寻找系统中的 bun (比如通过 npm install -g bun 安装的)
|
|
33
|
+
try {
|
|
34
|
+
// 简单通过 spawn 检查 bun 是否在 PATH 中
|
|
35
|
+
const check = spawnSync(IS_WINDOWS ? 'bun.exe' : 'bun', ['--version'], { stdio: 'ignore' });
|
|
36
|
+
if (check.status === 0) {
|
|
37
|
+
const result = run(IS_WINDOWS ? 'bun.exe' : 'bun', [BVM_SRC, ...process.argv.slice(2)]);
|
|
38
|
+
process.exit(result.status || 0);
|
|
39
|
+
}
|
|
40
|
+
} catch (e) {}
|
|
41
|
+
|
|
42
|
+
// 3. 如果都没有,给出清晰的指引(或者在未来版本支持自动下载)
|
|
43
|
+
console.error('\x1b[31m[bvm] Error: No Bun runtime found.\x1b[0m');
|
|
44
|
+
console.error('BVM requires Bun to function. Since you installed via npm, please run:');
|
|
45
|
+
console.error('\x1b[36m bvm setup\x1b[0m (if available) or install Bun manually.');
|
|
46
|
+
process.exit(1);
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
var t1=Object.create;var{getPrototypeOf:n1,defineProperty:B$,getOwnPropertyNames:o1}=Object;var i1=Object.prototype.hasOwnProperty;var U$=($,q,Q)=>{Q=$!=null?t1(n1($)):{};let J=q||!$||!$.__esModule?B$(Q,"default",{value:$,enumerable:!0}):Q;for(let Y of o1($))if(!i1.call(J,Y))B$(J,Y,{get:()=>$[Y],enumerable:!0});return J};var i$=($,q)=>{for(var Q in q)B$($,Q,{get:q[Q],enumerable:!0,configurable:!0,set:(J)=>q[Q]=()=>J})};var y$=($,q)=>()=>($&&(q=$($=0)),q);var O$=import.meta.require;var s$={};i$(s$,{getBvmDir:()=>a$,getBunAssetName:()=>f$,USER_AGENT:()=>X$,TEST_REMOTE_VERSIONS:()=>Z$,REPO_FOR_BVM_CLI:()=>$6,OS_PLATFORM:()=>B,IS_TEST_MODE:()=>D,EXECUTABLE_NAME:()=>j,CPU_ARCH:()=>z$,BVM_VERSIONS_DIR:()=>L,BVM_SRC_DIR:()=>r1,BVM_SHIMS_DIR:()=>S,BVM_FINGERPRINTS_FILE:()=>M$,BVM_DIR:()=>O,BVM_CURRENT_DIR:()=>b$,BVM_COMPONENTS:()=>J6,BVM_CDN_ROOT:()=>Q6,BVM_CACHE_DIR:()=>_,BVM_BIN_DIR:()=>M,BVM_ALIAS_DIR:()=>x,BUN_GITHUB_RELEASES_API:()=>e1,ASSET_NAME_FOR_BVM:()=>q6});import{homedir as s1}from"os";import{join as o}from"path";function a$(){let $=process.env.HOME||s1();return o($,".bvm")}function f$($){return`bun-${B==="win32"?"windows":B}-${z$==="arm64"?"aarch64":"x64"}.zip`}var B,z$,D,Z$,O,r1,L,M,S,b$,x,_,M$,j,e1="https://api.github.com/repos/oven-sh/bun/releases",$6="EricLLLLLL/bvm",q6,X$="bvm (Bun Version Manager)",Q6,J6;var F=y$(()=>{B=process.platform,z$=process.arch,D=process.env.BVM_TEST_MODE==="true",Z$=["v1.3.4","v1.2.23","v1.0.0","bun-v1.4.0-canary"];O=a$(),r1=o(O,"src"),L=o(O,"versions"),M=o(O,"bin"),S=o(O,"shims"),b$=o(O,"current"),x=o(O,"aliases"),_=o(O,"cache"),M$=o(O,"fingerprints.json"),j=B==="win32"?"bun.exe":"bun",q6=B==="win32"?"bvm.exe":"bvm",Q6=process.env.BVM_CDN_URL||"https://cdn.jsdelivr.net/gh/EricLLLLLL/bvm",J6=[{name:"CLI Core",remotePath:"index.js",localPath:"src/index.js"},{name:"Windows Shim",remotePath:"bvm-shim.js",localPath:"bin/bvm-shim.js",platform:"win32"},{name:"Unix Shim",remotePath:"bvm-shim.sh",localPath:"bin/bvm-shim.sh",platform:"posix"}]});function m($){if(!$)return null;return $.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/)?$:null}function r$($){let q=m($);return q?q.replace(/^v/,""):null}function J$($){if(!$)return null;let q=$.replace(/^v/,""),J=q.split(/[-+]/)[0].split(".").map(Number);if(J.length===0||J.some((K)=>isNaN(K)))return null;let Y=q.includes("-")?q.split("-")[1].split("+")[0]:void 0;return{major:J[0],minor:J[1],patch:J[2],pre:Y}}function T$($,q){if(!$||!q)return 0;if($.major!==q.major)return $.major-q.major;if($.minor!==q.minor)return $.minor-q.minor;if($.patch!==q.patch)return $.patch-q.patch;if($.pre&&!q.pre)return-1;if(!$.pre&&q.pre)return 1;if($.pre&&q.pre)return $.pre.localeCompare(q.pre);return 0}function e$($,q){let Q=J$($),J=J$(q);return T$(Q,J)}function K$($,q){return e$(q,$)}function k$($,q){return e$($,q)>0}function $1($,q){if(q==="*"||q===""||q==="latest")return!0;let Q=J$($);if(!Q)return!1;let J=q;if(q.startsWith("v"))J=q.substring(1);if(r$($)===r$(q))return!0;let Y=J.split(".");if(Y.length===1){let K=Number(Y[0]);if(Q.major===K)return!0}else if(Y.length===2){let K=Number(Y[0]),b=Number(Y[1]);if(Q.major===K&&Q.minor===b)return!0}if(q.startsWith("~")){let K=J$(q.substring(1));if(!K)return!1;let b=K.patch??0;return Q.major===K.major&&Q.minor===K.minor&&Q.patch>=b}if(q.startsWith("^")){let K=J$(q.substring(1));if(!K)return!1;let b=K.patch??0,X=K.minor??0;if(K.major===0){if(Q.major!==0)return!1;if(Q.minor!==X)return!1;return Q.patch>=b}if(Q.major!==K.major)return!1;if(Q.minor<X)return!1;if(Q.minor===X&&Q.patch<b)return!1;return!0}return!1}import{readdir as Y6,mkdir as Z6,stat as b6,symlink as X6,unlink as q1,rm as Q1,readlink as G6}from"fs/promises";import{join as C$,dirname as H6,basename as W6}from"path";async function N($){await Z6($,{recursive:!0})}async function G($){try{return await b6($),!0}catch(q){if(q.code==="ENOENT")return!1;throw q}}async function J1($,q){try{await q1(q)}catch(J){try{await Q1(q,{recursive:!0,force:!0})}catch(Y){}}let Q=process.platform==="win32"?"junction":"dir";await X6($,q,Q)}async function K1($){try{return await G6($)}catch(q){if(q.code==="ENOENT"||q.code==="EINVAL")return null;throw q}}async function G$($){await Q1($,{recursive:!0,force:!0})}async function p($){try{return await Y6($)}catch(q){if(q.code==="ENOENT")return[];throw q}}async function f($){return await Bun.file($).text()}async function V($,q){await Bun.write($,q)}async function L$($,q,Q={}){let{backup:J=!0}=Q,Y=H6($);await N(Y);let K=`${$}.tmp-${Date.now()}`,b=`${$}.bak`;try{if(await V(K,q),J&&await G($))try{let{rename:H,unlink:z}=await import("fs/promises");if(await G(b))await z(b).catch(()=>{});await H($,b)}catch(H){}let{rename:X}=await import("fs/promises");try{await X(K,$)}catch(H){await Bun.write($,q),await q1(K).catch(()=>{})}}catch(X){let{unlink:H}=await import("fs/promises");throw await H(K).catch(()=>{}),X}}function U($){let q=$.trim();if(q.startsWith("bun-v"))q=q.substring(4);if(!q.startsWith("v")&&/^\d/.test(q))q=`v${q}`;return q}async function P(){return await N(L),(await p(L)).filter((q)=>m(U(q))).sort(K$)}async function l(){if(process.env.BVM_ACTIVE_VERSION)return{version:U(process.env.BVM_ACTIVE_VERSION),source:"env"};let $=C$(process.cwd(),".bvmrc");if(await G($)){let b=(await f($)).trim();return{version:U(b),source:".bvmrc"}}let{getBvmDir:q}=await Promise.resolve().then(() => (F(),s$)),Q=q(),J=C$(Q,"current"),Y=C$(Q,"aliases");if(await G(J)){let{realpath:b}=await import("fs/promises");try{let X=await b(J);return{version:U(W6(X)),source:"current"}}catch(X){}}let K=C$(Y,"default");if(await G(K)){let b=(await f(K)).trim();return{version:U(b),source:"default"}}return{version:null,source:null}}function r($,q){if(!$||q.length===0)return null;let Q=U($);if(q.includes(Q))return Q;if($.toLowerCase()==="latest")return q[0];if(/^\d+\.\d+\.\d+$/.test($.replace(/^v/,"")))return null;if(!/^[v\d]/.test($))return null;let Y=$.startsWith("v")?`~${$.substring(1)}`:`~${$}`,K=q.filter((b)=>$1(b,Y));if(K.length>0)return K.sort(K$)[0];return null}var w=y$(()=>{F()});class R${timer=null;frames=process.platform==="win32"?["-"]:["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"];frameIndex=0;text;isWindows=process.platform==="win32";constructor($){this.text=$}start($){if($)this.text=$;if(this.timer)return;if(this.isWindows){process.stdout.write(`${Z.cyan(">")} ${this.text}
|
|
4
4
|
`);return}this.timer=setInterval(()=>{process.stdout.write(`\r\x1B[K${Z.cyan(this.frames[this.frameIndex])} ${this.text}`),this.frameIndex=(this.frameIndex+1)%this.frames.length},80)}stop(){if(this.isWindows)return;if(this.timer)clearInterval(this.timer),this.timer=null,process.stdout.write("\r\x1B[K");process.stdout.write("\x1B[?25h")}succeed($){this.stop(),console.log(`${Z.green(" \u2713")} ${$||this.text}`)}fail($){this.stop(),console.log(`${Z.red(" \u2716")} ${$||this.text}`)}info($){this.stop(),console.log(`${Z.blue(" \u2139")} ${$||this.text}`)}update($){if(this.text=$,this.isWindows)console.log(Z.dim(` ... ${this.text}`))}}class D${total;current=0;width=20;constructor($){this.total=$}start(){process.stdout.write("\x1B[?25l"),this.render()}update($,q){this.current=$,this.render(q)}stop(){process.stdout.write(`\x1B[?25h
|
|
5
|
-
`)}render($){let q=Math.min(1,this.current/this.total),Q=Math.round(this.width*q),J=this.width-Q,Y=process.platform==="win32",K=Y?"=":"\u2588",b=Y?"-":"\u2591",X=Z.green(K.repeat(Q))+Z.gray(b.repeat(J)),H=(q*100).toFixed(0).padStart(3," "),z=(this.current/1048576).toFixed(1),C=(this.total/1048576).toFixed(1),W=$?` ${$.speed}KB/s`:"";process.stdout.write(`\r\x1B[2K ${X} ${H}% | ${z}/${C}MB${W}`)}}var U6,y6=($)=>$.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=($,q,Q=$)=>(J)=>U6?$+J.replace(new RegExp(y6(q),"g"),Q)+q:J,Z;var k=y$(()=>{U6=!process.env.NO_COLOR,Z={red:i("\x1B[1;31m","\x1B[39m"),green:i("\x1B[1;32m","\x1B[39m"),yellow:i("\x1B[1;33m","\x1B[39m"),blue:i("\x1B[1;34m","\x1B[39m"),magenta:i("\x1B[1;35m","\x1B[39m"),cyan:i("\x1B[1;36m","\x1B[39m"),gray:i("\x1B[90m","\x1B[39m"),bold:i("\x1B[1m","\x1B[22m","\x1B[22m\x1B[1m"),dim:i("\x1B[2m","\x1B[22m","\x1B[22m\x1B[2m")}});async function y($,q,Q){if(process.platform==="win32"){console.log(Z.cyan(`> ${$}`));let K={start:(b)=>{if(b)console.log(Z.cyan(`> ${b}`))},stop:()=>{},succeed:(b)=>console.log(Z.green(` \u2713 ${b}`)),fail:(b)=>console.log(Z.red(` \u2716 ${b}`)),info:(b)=>console.log(Z.cyan(` \u2139 ${b}`)),update:(b)=>console.log(Z.dim(` ... ${b}`)),isSpinning:!1};try{return await q(K)}catch(b){let X=y1(b,Q?.failMessage);if(console.log(Z.red(` \u2716 ${X}`)),process.env.BVM_DEBUG,console.log(Z.dim(` Details: ${b.message}`)),b.code)console.log(Z.dim(` Code: ${b.code}`));throw b.reported=!0,b}}let Y=new R$($);Y.start();try{let K=await q(Y);return Y.stop(),K}catch(K){let b=y1(K,Q?.failMessage);throw Y.fail(Z.red(b)),K.reported=!0,K}}function y1($,q){let Q=$ instanceof Error?$.message:String($);if(!q)return Q;if(typeof q==="function")return q($);return`${q}: ${Q}`}var R=y$(()=>{k()});var O1={};i$(O1,{resolveLocalVersion:()=>g,displayVersion:()=>d$});import{join as P6}from"path";async function g($){if($==="current"){let{version:Y}=await l();return Y}if($==="latest"){let Y=await P();if(Y.length>0)return Y[0];return null}let q=P6(x,$);if(await G(q))try{let Y=(await f(q)).trim();return U(Y)}catch{return null}let Q=U($),J=await P();return r($,J)}async function d$($){await y(`Resolving version '${$}'...`,async()=>{let q=await g($);if(q)console.log(q);else throw Error("N/A")},{failMessage:`Failed to resolve version '${$}'`})}var q$=y$(()=>{F();w();R()});import{parseArgs as Y4}from"util";var Y$={name:"bvm-core",version:"1.1.
|
|
5
|
+
`)}render($){let q=Math.min(1,this.current/this.total),Q=Math.round(this.width*q),J=this.width-Q,Y=process.platform==="win32",K=Y?"=":"\u2588",b=Y?"-":"\u2591",X=Z.green(K.repeat(Q))+Z.gray(b.repeat(J)),H=(q*100).toFixed(0).padStart(3," "),z=(this.current/1048576).toFixed(1),C=(this.total/1048576).toFixed(1),W=$?` ${$.speed}KB/s`:"";process.stdout.write(`\r\x1B[2K ${X} ${H}% | ${z}/${C}MB${W}`)}}var U6,y6=($)=>$.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),i=($,q,Q=$)=>(J)=>U6?$+J.replace(new RegExp(y6(q),"g"),Q)+q:J,Z;var k=y$(()=>{U6=!process.env.NO_COLOR,Z={red:i("\x1B[1;31m","\x1B[39m"),green:i("\x1B[1;32m","\x1B[39m"),yellow:i("\x1B[1;33m","\x1B[39m"),blue:i("\x1B[1;34m","\x1B[39m"),magenta:i("\x1B[1;35m","\x1B[39m"),cyan:i("\x1B[1;36m","\x1B[39m"),gray:i("\x1B[90m","\x1B[39m"),bold:i("\x1B[1m","\x1B[22m","\x1B[22m\x1B[1m"),dim:i("\x1B[2m","\x1B[22m","\x1B[22m\x1B[2m")}});async function y($,q,Q){if(process.platform==="win32"){console.log(Z.cyan(`> ${$}`));let K={start:(b)=>{if(b)console.log(Z.cyan(`> ${b}`))},stop:()=>{},succeed:(b)=>console.log(Z.green(` \u2713 ${b}`)),fail:(b)=>console.log(Z.red(` \u2716 ${b}`)),info:(b)=>console.log(Z.cyan(` \u2139 ${b}`)),update:(b)=>console.log(Z.dim(` ... ${b}`)),isSpinning:!1};try{return await q(K)}catch(b){let X=y1(b,Q?.failMessage);if(console.log(Z.red(` \u2716 ${X}`)),process.env.BVM_DEBUG,console.log(Z.dim(` Details: ${b.message}`)),b.code)console.log(Z.dim(` Code: ${b.code}`));throw b.reported=!0,b}}let Y=new R$($);Y.start();try{let K=await q(Y);return Y.stop(),K}catch(K){let b=y1(K,Q?.failMessage);throw Y.fail(Z.red(b)),K.reported=!0,K}}function y1($,q){let Q=$ instanceof Error?$.message:String($);if(!q)return Q;if(typeof q==="function")return q($);return`${q}: ${Q}`}var R=y$(()=>{k()});var O1={};i$(O1,{resolveLocalVersion:()=>g,displayVersion:()=>d$});import{join as P6}from"path";async function g($){if($==="current"){let{version:Y}=await l();return Y}if($==="latest"){let Y=await P();if(Y.length>0)return Y[0];return null}let q=P6(x,$);if(await G(q))try{let Y=(await f(q)).trim();return U(Y)}catch{return null}let Q=U($),J=await P();return r($,J)}async function d$($){await y(`Resolving version '${$}'...`,async()=>{let q=await g($);if(q)console.log(q);else throw Error("N/A")},{failMessage:`Failed to resolve version '${$}'`})}var q$=y$(()=>{F();w();R()});import{parseArgs as Y4}from"util";var Y$={name:"bvm-core",version:"1.1.18",description:"The native version manager for Bun. Cross-platform, shell-agnostic, and zero-dependency.",main:"dist/index.js",bin:{bvm:"bin/bvm-npm.js"},publishConfig:{access:"public"},scripts:{dev:"bun run src/index.ts",build:"bun build src/index.ts --target=bun --outfile dist/index.js --minify && bun run scripts/sync-runtime.ts",test:"bun test",bvm:"bun run src/index.ts","bvm:sandbox":'mkdir -p "$PWD/.sandbox-home" && HOME="$PWD/.sandbox-home" bun run src/index.ts',release:"bun run scripts/release.ts","test:e2e:npm":"bun run scripts/verify-e2e-npm.ts","sync-runtime":"bun run scripts/sync-runtime.ts",postinstall:"node scripts/postinstall.js"},repository:{type:"git",url:"git+https://github.com/EricLLLLLL/bvm.git"},keywords:["bun","version-manager","cli","bvm","nvm","nvm-windows","fnm","nodenv","bun-nvm","version-switching"],files:["dist/index.js","dist/bvm-shim.sh","dist/bvm-shim.js","bin/bvm-npm.js","scripts/postinstall.js","install.sh","install.ps1","README.md"],author:"EricLLLLLL",license:"MIT",type:"commonjs",dependencies:{"cli-progress":"^3.12.0"},optionalDependencies:{"@oven/bun-darwin-aarch64":"^1.3.6","@oven/bun-darwin-x64":"^1.3.6","@oven/bun-linux-aarch64":"^1.3.6","@oven/bun-linux-x64":"^1.3.6","@oven/bun-windows-x64":"^1.3.6"},devDependencies:{"@types/bun":"^1.3.4","@types/cli-progress":"^3.11.6","@types/node":"^24.10.2",bun:"^1.3.6",esbuild:"^0.27.2",execa:"^9.6.1",typescript:"^5"},peerDependencies:{typescript:"^5"}};F();w();import{join as n,basename as g6,dirname as m6}from"path";F();w();k();import{join as L6}from"path";function Y1($,q){if($==="darwin"){if(q==="arm64")return"@oven/bun-darwin-aarch64";if(q==="x64")return"@oven/bun-darwin-x64"}if($==="linux"){if(q==="arm64")return"@oven/bun-linux-aarch64";if(q==="x64")return"@oven/bun-linux-x64"}if($==="win32"){if(q==="x64")return"@oven/bun-windows-x64"}return null}function Z1($,q,Q){let J=Q;if(!J.endsWith("/"))J+="/";let Y=$.startsWith("@"),K=$;if(Y){let X=$.split("/");if(X.length===2)K=X[1]}let b=`${K}-${q}.tgz`;return`${J}${$}/-/${b}`}k();async function d($,q={}){let{cwd:Q,env:J,prependPath:Y,stdin:K="inherit",stdout:b="inherit",stderr:X="inherit"}=q,H={...process.env,...J};if(Y){let W=H.PATH||"",A=process.platform==="win32"?";":":";H.PATH=`${Y}${A}${W}`}let C=await Bun.spawn({cmd:$,cwd:Q,env:H,stdin:K,stdout:b,stderr:X}).exited;if((C??0)!==0)throw Error(`${Z.red("Command failed")}: ${$.join(" ")} (code ${C})`);return C??0}async function a($,q={}){let{timeout:Q=5000,...J}=q,Y=new AbortController,K=setTimeout(()=>Y.abort(),Q);try{let b=await fetch($,{...J,signal:Y.signal});return clearTimeout(K),b}catch(b){if(clearTimeout(K),b.name==="AbortError")throw Error(`Request to ${$} timed out after ${Q}ms`);throw b}}async function O6($,q=2000){if($.length===0)throw Error("No URLs to race");if($.length===1)return $[0];return new Promise((Q,J)=>{let Y=0,K=!1;$.forEach((b)=>{a(b,{method:"HEAD",timeout:q}).then((X)=>{if(X.ok&&!K)K=!0,Q(b);else if(!K){if(Y++,Y===$.length)J(Error("All requests failed"))}}).catch(()=>{if(!K){if(Y++,Y===$.length)J(Error("All requests failed"))}})})})}async function z6(){try{let $=await a("https://1.1.1.1/cdn-cgi/trace",{timeout:500});if(!$.ok)return null;let Q=(await $.text()).match(/loc=([A-Z]{2})/);return Q?Q[1]:null}catch($){return null}}var I$=null,w$={NPM:"https://registry.npmjs.org",TAOBAO:"https://registry.npmmirror.com",TENCENT:"https://mirrors.cloud.tencent.com/npm/"};async function e(){if(I$)return I$;let $=await z6(),q=[];if($==="CN")q=[w$.TAOBAO,w$.TENCENT,w$.NPM];else q=[w$.NPM,w$.TAOBAO];try{let Q=await O6(q,2000);return I$=Q,Q}catch(Q){return q[0]}}w();var w6="bun-versions.json",x6=3600000;async function k6(){if(D)return[...Z$];let $=L6(_,w6);try{if(await G($)){let Y=await f($),K=JSON.parse(Y);if(Date.now()-K.timestamp<x6&&Array.isArray(K.versions))return K.versions}}catch(Y){}let q=await e(),Q=[q];if(q!=="https://registry.npmjs.org")Q.push("https://registry.npmjs.org");let J=null;for(let Y of Q){let K=`${Y.replace(/\/$/,"")}/bun`;try{let b=await a(K,{headers:{"User-Agent":X$,Accept:"application/vnd.npm.install-v1+json"},timeout:1e4});if(!b.ok)throw Error(`Status ${b.status}`);let X=await b.json();if(!X.versions)throw Error("Invalid response (no versions)");let H=Object.keys(X.versions);try{await N(_),await V($,JSON.stringify({timestamp:Date.now(),versions:H}))}catch(z){}return H}catch(b){J=b}}throw J||Error("Failed to fetch versions from any registry.")}async function C6(){if(D)return[...Z$];return new Promise(($,q)=>{let Q=[];try{let J=Bun.spawn(["git","ls-remote","--tags","https://github.com/oven-sh/bun.git"],{stdout:"pipe",stderr:"pipe"}),Y=setTimeout(()=>{J.kill(),q(Error("Git operation timed out"))},1e4);new Response(J.stdout).text().then((b)=>{clearTimeout(Y);let X=b.split(`
|
|
6
6
|
`);for(let H of X){let z=H.match(/refs\/tags\/bun-v?(\d+\.\d+\.\d+.*)$/);if(z)Q.push(z[1])}$(Q)}).catch((b)=>{clearTimeout(Y),q(b)})}catch(J){q(Error(`Failed to run git: ${J.message}`))}})}async function b1(){if(D)return[...Z$];try{let q=(await k6()).filter((Q)=>m(Q)).map((Q)=>({v:Q,parsed:J$(Q)}));return q.sort((Q,J)=>T$(J.parsed,Q.parsed)),q.map((Q)=>Q.v)}catch($){try{let q=await C6();if(q.length>0)return Array.from(new Set(q.filter((J)=>m(J)))).sort(K$);throw Error("No versions found via Git")}catch(q){throw Error(`Failed to fetch versions. NPM: ${$.message}. Git: ${q.message}`)}}}async function X1($){if(D)return Z$.includes($)||$==="latest";let q=await e(),Q=$.replace(/^v/,""),J=`${q}/bun/${Q}`,Y=B==="win32"?"curl.exe":"curl",K=async()=>{try{return await d([Y,"-I","-f","-m","5","-s",J],{stdout:"ignore",stderr:"ignore"}),!0}catch(X){return!1}},b=new Promise((X)=>setTimeout(()=>X(!1),1e4));return Promise.race([K(),b])}async function G1(){if(D)return{latest:"1.1.20"};let q=`${await e()}/-/package/bun/dist-tags`;try{let Q=await a(q,{headers:{"User-Agent":X$},timeout:5000});if(Q.ok)return await Q.json()}catch(Q){}return{}}async function H1($){let q=U($);if(!m(q))return console.error(Z.red(`Invalid version provided to findBunDownloadUrl: ${$}`)),null;if(D)return{url:`https://example.com/${f$(q)}`,foundVersion:q};let Y=Y1(B==="win32"?"win32":B,z$==="arm64"?"arm64":"x64");if(!Y)throw Error(`Unsupported platform/arch for NPM download: ${B}-${z$}`);let K="";if(process.env.BVM_REGISTRY)K=process.env.BVM_REGISTRY;else if(process.env.BVM_DOWNLOAD_MIRROR)K=process.env.BVM_DOWNLOAD_MIRROR;else K=await e();let b=q.replace(/^v/,"");return{url:Z1(Y,b,K),foundVersion:q}}async function F$(){try{let q=(await e()).replace(/\/$/,""),Q=await a(`${q}/-/package/bvm-core/dist-tags`,{headers:{"User-Agent":X$},timeout:5000});if(!Q.ok)return null;let Y=(await Q.json()).latest;if(!Y)return null;let K=await a(`${q}/bvm-core/${Y}`,{headers:{"User-Agent":X$},timeout:5000});if(K.ok){let b=await K.json();return{version:Y,tarball:b.dist.tarball,integrity:b.dist.integrity,shasum:b.dist.shasum}}}catch($){}return null}k();F();import{spawn as F6}from"child_process";async function W1($,q){if($.endsWith(".zip"))if(B==="win32")await d(["powershell","-Command",`Expand-Archive -Path "${$}" -DestinationPath "${q}" -Force`],{stdout:"ignore",stderr:"inherit"});else await d(["unzip","-o","-q",$,"-d",q],{stdout:"ignore",stderr:"inherit"});else if($.endsWith(".tar.gz")||$.endsWith(".tgz"))await new Promise((Q,J)=>{let Y=F6("tar",["-xzf",$,"-C",q],{stdio:"inherit",shell:!1});Y.on("close",(K)=>{if(K===0)Q();else J(Error(`tar exited with code ${K}`))}),Y.on("error",(K)=>J(K))});else throw Error(`Unsupported archive format: ${$}`)}import{chmod as m$}from"fs/promises";w();F();k();import{join as T,dirname as R6,delimiter as D6}from"path";import{homedir as $$}from"os";import{chmod as x$}from"fs/promises";var E$=`#!/bin/bash
|
|
7
7
|
|
|
8
8
|
# bvm-init.sh: Initializes bvm default version on shell startup
|
package/install.ps1
CHANGED
|
@@ -46,7 +46,7 @@ function Detect-NetworkZone {
|
|
|
46
46
|
$BVM_REGION = Detect-NetworkZone
|
|
47
47
|
$REGISTRY = if ($BVM_REGION -eq "cn") { "registry.npmmirror.com" } else { "registry.npmjs.org" }
|
|
48
48
|
|
|
49
|
-
$DEFAULT_BVM_VER = "v1.1.
|
|
49
|
+
$DEFAULT_BVM_VER = "v1.1.18"
|
|
50
50
|
$BVM_VER = if ($env:BVM_INSTALL_VERSION) { $env:BVM_INSTALL_VERSION } else { "" }
|
|
51
51
|
if (-not $BVM_VER) {
|
|
52
52
|
try {
|
|
@@ -165,7 +165,7 @@ foreach ($name in $CMD_NAMES) {
|
|
|
165
165
|
$RawPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
166
166
|
$PathList = if ($RawPath) { $RawPath.Split(';') } else { @() }
|
|
167
167
|
$NewPathList = @()
|
|
168
|
-
foreach ($p in $PathList) { if ($p -notlike "*\.bvm\shims*" -and $p -notlike "*\.bvm\bin*" -and [string]::
|
|
168
|
+
foreach ($p in $PathList) { if ($p -notlike "*\.bvm\shims*" -and $p -notlike "*\.bvm\bin*" -and -not [string]::IsNullOrEmpty($p)) { $NewPathList += $p } }
|
|
169
169
|
$FinalPath = "$BVM_SHIMS_DIR;$BVM_BIN_DIR;" + ($NewPathList -join ';')
|
|
170
170
|
[Environment]::SetEnvironmentVariable("Path", $FinalPath, "User")
|
|
171
171
|
$env:Path = "$BVM_SHIMS_DIR;$BVM_BIN_DIR;$env:Path"
|
package/install.sh
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bvm-core",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.18",
|
|
4
4
|
"description": "The native version manager for Bun. Cross-platform, shell-agnostic, and zero-dependency.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"bvm": "
|
|
7
|
+
"bvm": "bin/bvm-npm.js"
|
|
8
8
|
},
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"dist/index.js",
|
|
41
41
|
"dist/bvm-shim.sh",
|
|
42
42
|
"dist/bvm-shim.js",
|
|
43
|
+
"bin/bvm-npm.js",
|
|
43
44
|
"scripts/postinstall.js",
|
|
44
45
|
"install.sh",
|
|
45
46
|
"install.ps1",
|
|
@@ -71,10 +72,10 @@
|
|
|
71
72
|
"typescript": "^5"
|
|
72
73
|
},
|
|
73
74
|
"bvm_fingerprints": {
|
|
74
|
-
"cli": "
|
|
75
|
+
"cli": "302bb3dee56d88ad9c506d2d3638c07c",
|
|
75
76
|
"shim_win": "c6f43afddfb205e130633fe00ee860d8",
|
|
76
77
|
"shim_unix": "8aa89a0324b52c9c81b96c0c03afe36c",
|
|
77
|
-
"install_sh": "
|
|
78
|
-
"install_ps1": "
|
|
78
|
+
"install_sh": "2f4a13e4e0837640678c6d5178eae4ed",
|
|
79
|
+
"install_ps1": "b9df4fa27f183bcfbb1342bc1f530ded"
|
|
79
80
|
}
|
|
80
81
|
}
|
package/scripts/postinstall.js
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* BVM Post-install Script
|
|
5
|
-
*
|
|
6
|
-
* 1. Init & Deploy Assets
|
|
7
|
-
* 2. Detect System Bun
|
|
8
|
-
* 3. Smoke Test System Bun
|
|
9
|
-
* 4. Configure Runtime (Reuse or Download)
|
|
10
|
-
* 5. Setup Shell Environment
|
|
4
|
+
* BVM Post-install Script (Smart Edition)
|
|
5
|
+
* Optimized for Speed: Priority given to npmmirror (China) and npmjs (Official).
|
|
11
6
|
*/
|
|
12
7
|
|
|
13
8
|
const fs = require('fs');
|
|
@@ -15,285 +10,194 @@ const path = require('path');
|
|
|
15
10
|
const { spawnSync } = require('child_process');
|
|
16
11
|
const os = require('os');
|
|
17
12
|
|
|
18
|
-
|
|
19
|
-
const ASCII_LOGO = `
|
|
20
|
-
\x1b[36m
|
|
21
|
-
__________
|
|
22
|
-
\______ \__ _______
|
|
23
|
-
| | _| \/ / \
|
|
24
|
-
| | \\ / Y Y \
|
|
25
|
-
|______ / \_/|__|_| /
|
|
26
|
-
\/ \/
|
|
27
|
-
\x1b[0m`;
|
|
28
|
-
|
|
13
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
29
14
|
const HOME = process.env.HOME || os.homedir();
|
|
30
15
|
const BVM_DIR = process.env.BVM_DIR || path.join(HOME, '.bvm');
|
|
31
16
|
const BVM_SRC_DIR = path.join(BVM_DIR, 'src');
|
|
32
17
|
const BVM_BIN_DIR = path.join(BVM_DIR, 'bin');
|
|
33
18
|
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
34
19
|
const DIST_DIR = path.join(PKG_ROOT, 'dist');
|
|
35
|
-
const LOG_FILE = path.join(os.tmpdir(), 'bvm-install.log');
|
|
36
20
|
|
|
37
|
-
|
|
38
|
-
function
|
|
39
|
-
const line = `[bvm] ${msg}`;
|
|
40
|
-
process.stdout.write(line + '\n');
|
|
41
|
-
try { fs.appendFileSync(LOG_FILE, line + '\n'); } catch(e) {}
|
|
42
|
-
}
|
|
21
|
+
function log(msg) { console.log(`[bvm] ${msg}`); }
|
|
22
|
+
function error(msg) { console.error(`\x1b[31m[bvm] ERROR: ${msg}\x1b[0m`); }
|
|
43
23
|
|
|
44
|
-
function
|
|
45
|
-
|
|
46
|
-
process.stderr.write(`\x1b[31m${line}\x1b[0m\n`);
|
|
47
|
-
try { fs.appendFileSync(LOG_FILE, line + '\n'); } catch(e) {}
|
|
24
|
+
function run(cmd, args, opts = {}) {
|
|
25
|
+
return spawnSync(cmd, args, Object.assign({ encoding: 'utf-8', shell: IS_WINDOWS }, opts));
|
|
48
26
|
}
|
|
49
27
|
|
|
50
|
-
function
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
function main() {
|
|
62
|
-
// Force a leading newline to break from npm's output
|
|
63
|
-
process.stdout.write('\n' + ASCII_LOGO + '\n');
|
|
64
|
-
log('Starting BVM post-install setup...');
|
|
65
|
-
|
|
66
|
-
// 1. Conflict Detection
|
|
67
|
-
const BVM_EXEC = path.join(BVM_BIN_DIR, 'bvm');
|
|
68
|
-
if (fs.existsSync(BVM_EXEC) && !process.env.BVM_FORCE_INSTALL) {
|
|
69
|
-
try {
|
|
70
|
-
const content = fs.readFileSync(BVM_EXEC, 'utf-8');
|
|
71
|
-
if (!content.includes('BVM_INSTALL_SOURCE="npm"')) {
|
|
72
|
-
log('Native BVM installation detected. Proceeding to update assets...');
|
|
73
|
-
}
|
|
74
|
-
} catch (e) {}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// 2. Deploy Assets
|
|
78
|
-
log(`Deploying to ${BVM_DIR}...`);
|
|
79
|
-
ensureDir(BVM_SRC_DIR);
|
|
80
|
-
ensureDir(BVM_BIN_DIR);
|
|
81
|
-
|
|
82
|
-
const filesToCopy = [
|
|
83
|
-
{ src: 'index.js', destDir: BVM_SRC_DIR, name: 'index.js' },
|
|
84
|
-
{ src: 'bvm-shim.sh', destDir: BVM_BIN_DIR, name: 'bvm-shim.sh', mode: 0o755 },
|
|
85
|
-
{ src: 'bvm-shim.js', destDir: BVM_BIN_DIR, name: 'bvm-shim.js' }
|
|
86
|
-
];
|
|
87
|
-
|
|
88
|
-
for (const file of filesToCopy) {
|
|
89
|
-
const srcPath = path.join(DIST_DIR, file.src);
|
|
90
|
-
const destPath = path.join(file.destDir, file.name);
|
|
91
|
-
|
|
92
|
-
if (fs.existsSync(srcPath)) {
|
|
93
|
-
fs.copyFileSync(srcPath, destPath);
|
|
94
|
-
if (file.mode) fs.chmodSync(destPath, file.mode);
|
|
95
|
-
} else {
|
|
96
|
-
error(`Source file not found: ${srcPath}`);
|
|
28
|
+
function findBinary(dir, name) {
|
|
29
|
+
const files = fs.readdirSync(dir);
|
|
30
|
+
for (const file of files) {
|
|
31
|
+
const full = path.join(dir, file);
|
|
32
|
+
const stat = fs.statSync(full);
|
|
33
|
+
if (stat.isDirectory()) {
|
|
34
|
+
const res = findBinary(full, name);
|
|
35
|
+
if (res) return res;
|
|
36
|
+
} else if (file === name || (IS_WINDOWS && file === name + '.exe')) {
|
|
37
|
+
return full;
|
|
97
38
|
}
|
|
98
39
|
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
99
42
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
log(`Found system Bun at ${systemBun.path} (v${systemBun.version})`);
|
|
109
|
-
if (runSmokeTest(systemBun.path)) {
|
|
110
|
-
log('Smoke Test passed: System Bun is compatible.');
|
|
111
|
-
systemBunCompatible = true;
|
|
112
|
-
activeVersion = ensureVersionPrefix(systemBun.version);
|
|
113
|
-
const versionDir = path.join(BVM_DIR, 'versions', activeVersion);
|
|
114
|
-
registerBunVersion(systemBun.path, versionDir);
|
|
115
|
-
activeRuntimePath = versionDir;
|
|
116
|
-
} else {
|
|
117
|
-
log('Smoke Test failed: System Bun cannot run BVM core.');
|
|
118
|
-
const versionDir = path.join(BVM_DIR, 'versions', ensureVersionPrefix(systemBun.version));
|
|
119
|
-
registerBunVersion(systemBun.path, versionDir);
|
|
120
|
-
}
|
|
121
|
-
} else {
|
|
122
|
-
log('No system Bun detected.');
|
|
123
|
-
}
|
|
43
|
+
/**
|
|
44
|
+
* Prioritized registry sniffing for speed and reliability
|
|
45
|
+
*/
|
|
46
|
+
function getPackageInfo(pkgName) {
|
|
47
|
+
const registries = [
|
|
48
|
+
'https://registry.npmmirror.com', // High speed for China
|
|
49
|
+
'https://registry.npmjs.org' // Official reliability
|
|
50
|
+
];
|
|
124
51
|
|
|
125
|
-
|
|
126
|
-
log(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
} catch (e) {
|
|
136
|
-
error(`Failed to download runtime: ${e.message}`);
|
|
52
|
+
for (const registry of registries) {
|
|
53
|
+
log(`Checking ${pkgName} info from ${registry}...`);
|
|
54
|
+
const res = run('npm', ['info', pkgName, '--json', '--registry', registry]);
|
|
55
|
+
if (res.status === 0 && res.stdout) {
|
|
56
|
+
try {
|
|
57
|
+
const info = JSON.parse(res.stdout);
|
|
58
|
+
if (info.dist && info.dist.tarball) {
|
|
59
|
+
return { url: info.dist.tarball, version: info.version };
|
|
60
|
+
}
|
|
61
|
+
} catch (e) {}
|
|
137
62
|
}
|
|
138
63
|
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
139
66
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
try { if (fs.existsSync(privateRuntimeLink)) fs.unlinkSync(privateRuntimeLink); } catch(e) {}
|
|
147
|
-
try { fs.symlinkSync(activeRuntimePath, privateRuntimeLink, 'dir'); } catch(e) {}
|
|
148
|
-
|
|
149
|
-
try { if (fs.existsSync(legacyCurrentLink)) fs.unlinkSync(legacyCurrentLink); } catch(e) {}
|
|
150
|
-
try { fs.symlinkSync(activeRuntimePath, legacyCurrentLink, 'dir'); } catch(e) {}
|
|
151
|
-
|
|
152
|
-
const aliasDir = path.join(BVM_DIR, 'aliases');
|
|
153
|
-
ensureDir(aliasDir);
|
|
154
|
-
fs.writeFileSync(path.join(aliasDir, 'default'), activeVersion);
|
|
155
|
-
log(`Active runtime set to ${activeVersion}`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 5. Create BVM Wrapper
|
|
159
|
-
createBvmWrapper();
|
|
67
|
+
function setupRuntimeLink(verDir, ver) {
|
|
68
|
+
const runtimeDir = path.join(BVM_DIR, 'runtime');
|
|
69
|
+
if (!fs.existsSync(runtimeDir)) fs.mkdirSync(runtimeDir, { recursive: true });
|
|
70
|
+
const currentLink = path.join(runtimeDir, 'current');
|
|
71
|
+
const userCurrentLink = path.join(BVM_DIR, 'current');
|
|
72
|
+
const linkType = IS_WINDOWS ? 'junction' : 'dir';
|
|
160
73
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
stdio: 'inherit',
|
|
165
|
-
env: Object.assign({}, process.env, { BVM_DIR })
|
|
74
|
+
[currentLink, userCurrentLink].forEach(link => {
|
|
75
|
+
try { if (fs.existsSync(link)) fs.unlinkSync(link); } catch(e) {}
|
|
76
|
+
try { fs.symlinkSync(verDir, link, linkType); } catch(e) {}
|
|
166
77
|
});
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
78
|
+
|
|
79
|
+
const aliasDir = path.join(BVM_DIR, 'aliases');
|
|
80
|
+
if (!fs.existsSync(aliasDir)) fs.mkdirSync(aliasDir, { recursive: true });
|
|
81
|
+
fs.writeFileSync(path.join(aliasDir, 'default'), ver);
|
|
170
82
|
}
|
|
171
83
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
84
|
+
function downloadAndInstall() {
|
|
85
|
+
const platform = process.platform === 'win32' ? 'windows' : process.platform;
|
|
86
|
+
const arch = process.arch === 'arm64' ? 'aarch64' : 'x64';
|
|
87
|
+
const pkgName = `@oven/bun-${platform}-${arch}`;
|
|
88
|
+
|
|
89
|
+
const info = getPackageInfo(pkgName);
|
|
90
|
+
if (!info) {
|
|
91
|
+
error(`Failed to locate ${pkgName} on both npmmirror and npmjs.`);
|
|
92
|
+
return false;
|
|
180
93
|
}
|
|
181
|
-
return null;
|
|
182
|
-
}
|
|
183
94
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
function runSmokeTest(binPath) {
|
|
193
|
-
try {
|
|
194
|
-
const indexJs = path.join(BVM_SRC_DIR, 'index.js');
|
|
195
|
-
const proc = spawnSync(binPath, [indexJs, '--version'], {
|
|
196
|
-
encoding: 'utf-8',
|
|
197
|
-
env: Object.assign({}, process.env, { BVM_DIR })
|
|
198
|
-
});
|
|
199
|
-
return proc.status === 0;
|
|
200
|
-
} catch (e) {
|
|
95
|
+
const { url, version } = info;
|
|
96
|
+
const tempTgz = path.join(os.tmpdir(), `bvm-bun-${Date.now()}.tgz`);
|
|
97
|
+
log(`Downloading Bun v${version} from: ${url}`);
|
|
98
|
+
|
|
99
|
+
const dl = run('curl', ['-L', '-s', '-o', tempTgz, url]);
|
|
100
|
+
if (dl.status !== 0) {
|
|
101
|
+
error('Download failed. Please check your internet connection.');
|
|
201
102
|
return false;
|
|
202
103
|
}
|
|
104
|
+
|
|
105
|
+
const extractDir = path.join(os.tmpdir(), `bvm-ext-${Date.now()}`);
|
|
106
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
107
|
+
const ex = run('tar', ['-xzf', tempTgz, '-C', extractDir]);
|
|
108
|
+
if (ex.status !== 0) { error('Extraction failed.'); return false; }
|
|
109
|
+
|
|
110
|
+
const exeName = IS_WINDOWS ? 'bun.exe' : 'bun';
|
|
111
|
+
const foundBin = findBinary(extractDir, exeName);
|
|
112
|
+
|
|
113
|
+
if (foundBin) {
|
|
114
|
+
const verName = 'v' + version.replace(/^v/, '');
|
|
115
|
+
const verDir = path.join(BVM_DIR, 'versions', verName);
|
|
116
|
+
const binDir = path.join(verDir, 'bin');
|
|
117
|
+
if (!fs.existsSync(binDir)) fs.mkdirSync(binDir, { recursive: true });
|
|
118
|
+
fs.copyFileSync(foundBin, path.join(binDir, IS_WINDOWS ? 'bun.exe' : 'bun'));
|
|
119
|
+
setupRuntimeLink(verDir, verName);
|
|
120
|
+
log(`Successfully installed Bun ${verName} as BVM runtime.`);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
203
124
|
}
|
|
204
125
|
|
|
205
|
-
function
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
126
|
+
function createWrappers() {
|
|
127
|
+
const bvmBin = path.join(BVM_BIN_DIR, IS_WINDOWS ? 'bvm.cmd' : 'bvm');
|
|
128
|
+
const bvmDirWin = BVM_DIR.replace(/\//g, '\\');
|
|
129
|
+
const entryPath = path.join(PKG_ROOT, 'bin', 'bvm-npm.js');
|
|
130
|
+
|
|
131
|
+
if (IS_WINDOWS) {
|
|
132
|
+
const content = `@echo off\r\nset "BVM_DIR=${bvmDirWin}"\r\nnode "${entryPath}" %*`;
|
|
133
|
+
fs.writeFileSync(bvmBin, content);
|
|
134
|
+
fs.writeFileSync(path.join(BVM_BIN_DIR, 'bvm'), '# BVM Windows Shim\n');
|
|
135
|
+
} else {
|
|
136
|
+
const content = `#!/bin/bash\nexport BVM_DIR="${BVM_DIR}"\nnode "${entryPath}" "$@"`;
|
|
137
|
+
fs.writeFileSync(bvmBin, content);
|
|
138
|
+
fs.chmodSync(bvmBin, 0o755);
|
|
212
139
|
}
|
|
213
140
|
}
|
|
214
141
|
|
|
215
|
-
function
|
|
216
|
-
|
|
217
|
-
const arch = process.arch;
|
|
142
|
+
function main() {
|
|
143
|
+
log('Starting BVM post-install setup...');
|
|
218
144
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
145
|
+
[BVM_SRC_DIR, BVM_BIN_DIR].forEach(d => { if (!fs.existsSync(d)) fs.mkdirSync(d, { recursive: true }); });
|
|
146
|
+
const assets = [
|
|
147
|
+
{ src: 'index.js', dest: path.join(BVM_SRC_DIR, 'index.js') },
|
|
148
|
+
{ src: 'bvm-shim.sh', dest: path.join(BVM_BIN_DIR, 'bvm-shim.sh') },
|
|
149
|
+
{ src: 'bvm-shim.js', dest: path.join(BVM_BIN_DIR, 'bvm-shim.js') }
|
|
150
|
+
];
|
|
151
|
+
assets.forEach(a => {
|
|
152
|
+
const srcPath = path.join(DIST_DIR, a.src);
|
|
153
|
+
if (fs.existsSync(srcPath)) {
|
|
154
|
+
fs.copyFileSync(srcPath, a.dest);
|
|
155
|
+
if (!a.dest.endsWith('.js')) fs.chmodSync(a.dest, 0o755);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
231
158
|
|
|
232
|
-
|
|
233
|
-
const
|
|
159
|
+
let hasValidBun = false;
|
|
160
|
+
const whichCmd = IS_WINDOWS ? 'where' : 'which';
|
|
161
|
+
const checkBun = run(whichCmd, ['bun']);
|
|
162
|
+
|
|
163
|
+
if (checkBun.status === 0 && checkBun.stdout) {
|
|
164
|
+
const binPath = checkBun.stdout.trim().split('\n')[0].trim();
|
|
165
|
+
log(`System Bun detected at: ${binPath}. Running Smoke Test...`);
|
|
166
|
+
|
|
167
|
+
const verRes = run(binPath, ['--version']);
|
|
168
|
+
const ver = 'v' + (verRes.stdout || '1.3.6').trim().replace(/^v/, '');
|
|
169
|
+
const verDir = path.join(BVM_DIR, 'versions', ver);
|
|
170
|
+
|
|
171
|
+
// Register anyway to preserve user's version
|
|
172
|
+
if (!fs.existsSync(path.join(verDir, 'bin'))) {
|
|
173
|
+
fs.mkdirSync(path.join(verDir, 'bin'), { recursive: true });
|
|
174
|
+
fs.copyFileSync(binPath, path.join(verDir, 'bin', IS_WINDOWS ? 'bun.exe' : 'bun'));
|
|
175
|
+
}
|
|
234
176
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const binPath = foundBinProc.stdout ? foundBinProc.stdout.trim().split('\n')[0] : null;
|
|
243
|
-
if (binPath && fs.existsSync(binPath)) {
|
|
244
|
-
const versionDir = path.join(bvmDir, 'versions', vBunVer);
|
|
245
|
-
registerBunVersion(binPath, versionDir);
|
|
246
|
-
return vBunVer;
|
|
177
|
+
const test = run(binPath, [path.join(BVM_SRC_DIR, 'index.js'), '--version'], { env: { BVM_DIR } });
|
|
178
|
+
if (test.status === 0) {
|
|
179
|
+
log('Smoke test passed. Reusing system Bun.');
|
|
180
|
+
setupRuntimeLink(verDir, ver);
|
|
181
|
+
hasValidBun = true;
|
|
182
|
+
} else {
|
|
183
|
+
log('Smoke test failed. System Bun is incompatible with BVM core.');
|
|
247
184
|
}
|
|
248
|
-
} catch (e) {
|
|
249
|
-
error(`Download failed: ${e.message}`);
|
|
250
|
-
} finally {
|
|
251
|
-
try {
|
|
252
|
-
if (fs.existsSync(tempTgz)) fs.unlinkSync(tempTgz);
|
|
253
|
-
if (fs.existsSync(extractDir)) fs.rmSync(extractDir, { recursive: true });
|
|
254
|
-
} catch(e) {}
|
|
255
185
|
}
|
|
256
|
-
return null;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
function createBvmWrapper() {
|
|
260
|
-
const wrapperContent = `#!/bin/bash
|
|
261
|
-
export BVM_DIR="${BVM_DIR}"
|
|
262
|
-
export BVM_INSTALL_SOURCE="npm"
|
|
263
|
-
if [ -x "\${BVM_DIR}/runtime/current/bin/bun" ]; then
|
|
264
|
-
exec "\${BVM_DIR}/runtime/current/bin/bun" "\${BVM_DIR}/src/index.js" "$@"
|
|
265
|
-
elif command -v bun >/dev/null 2>&1; then
|
|
266
|
-
exec bun "\${BVM_DIR}/src/index.js" "$@"
|
|
267
|
-
else
|
|
268
|
-
echo "Error: BVM requires Bun. Please ensure setup completed correctly."
|
|
269
|
-
exit 1
|
|
270
|
-
fi
|
|
271
|
-
`;
|
|
272
|
-
const bvmExec = path.join(BVM_BIN_DIR, 'bvm');
|
|
273
|
-
fs.writeFileSync(bvmExec, wrapperContent);
|
|
274
|
-
fs.chmodSync(bvmExec, 0o755);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function printSuccessMessage(hasSystemBun) {
|
|
278
|
-
const shell = process.env.SHELL || '';
|
|
279
|
-
let configFile = '~/.zshrc';
|
|
280
|
-
if (shell.includes('bash')) configFile = '~/.bashrc';
|
|
281
|
-
else if (shell.includes('fish')) configFile = '~/.config/fish/config.fish';
|
|
282
186
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
process.stdout.write('\x1b[33mYour existing Bun installations were NOT deleted and will coexist.\x1b[0m\n');
|
|
287
|
-
} else {
|
|
288
|
-
process.stdout.write('\x1b[33mBVM has installed a compatible Bun runtime for you.\x1b[0m\n');
|
|
187
|
+
if (!hasValidBun) {
|
|
188
|
+
log('No compatible system Bun found. Performing smart download...');
|
|
189
|
+
hasValidBun = downloadAndInstall();
|
|
289
190
|
}
|
|
290
|
-
|
|
291
|
-
|
|
191
|
+
|
|
192
|
+
createWrappers();
|
|
193
|
+
const bvmBin = path.join(BVM_BIN_DIR, IS_WINDOWS ? 'bvm.cmd' : 'bvm');
|
|
194
|
+
run(bvmBin, ['setup', '--silent'], { env: { BVM_DIR } });
|
|
195
|
+
log('🎉 BVM initialized successfully.');
|
|
292
196
|
}
|
|
293
197
|
|
|
294
|
-
// Execute
|
|
295
198
|
try {
|
|
296
199
|
main();
|
|
297
200
|
} catch (e) {
|
|
298
201
|
error(e.message);
|
|
202
|
+
process.exit(1);
|
|
299
203
|
}
|