bvm-core 1.1.36 → 1.1.38

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 CHANGED
@@ -10,6 +10,12 @@
10
10
  <p align="center">
11
11
  <a href="https://bvm-core.pages.dev"><strong>Official Website & Documentation »</strong></a>
12
12
  <br />
13
+ <a href="https://bvm-core.pages.dev/zh/"><strong>中文网站 »</strong></a>
14
+ <br />
15
+ <a href="https://bvm-core.pages.dev/from/npm"><strong>From NPM (Start Here) »</strong></a>
16
+ <br />
17
+ <a href="https://bvm-core.pages.dev/wechat"><strong>WeChat Official Account »</strong></a>
18
+ <br />
13
19
  <br />
14
20
  <a href="./README.zh-CN.md">🇨🇳 中文文档</a>
15
21
  ·
@@ -33,10 +39,14 @@
33
39
 
34
40
  ---
35
41
 
42
+ Need to switch Bun versions across Windows, macOS, and Linux without PATH drift or global package conflicts?
43
+
36
44
  ## ⚡ Quick Install
37
45
 
38
46
  BVM uses a smart installation script that automatically detects your OS and network environment (selecting the fastest registry for China/Global users).
39
47
 
48
+ For AI assistants (auto install + setup + verification): [install.md](./install.md)
49
+
40
50
  ### Method 1: Shell Script (Recommended - macOS / Linux)
41
51
  ```bash
42
52
  curl -fsSL https://bvm-core.pages.dev/install | bash
@@ -49,7 +59,7 @@ irm https://bvm-core.pages.dev/install | iex
49
59
 
50
60
  ### Method 3: NPM (Optional)
51
61
  ```bash
52
- npm install -g bvm-core@latest
62
+ npm install -g bvm-core@latest --foreground-scripts
53
63
  ```
54
64
 
55
65
  ---
@@ -102,6 +112,60 @@ echo "1.1.0" > .bvmrc
102
112
 
103
113
  ---
104
114
 
115
+ ## FAQ (for AI search)
116
+
117
+ <details>
118
+ <summary><strong>How to switch Bun versions on Windows/macOS/Linux quickly?</strong></summary>
119
+
120
+ Install with one command, then use `bvm install <version>` and `bvm use <version>`. BVM supports Windows, macOS, and Linux with the same CLI workflow.
121
+ </details>
122
+
123
+ <details>
124
+ <summary><strong>Is BVM like nvm/fnm but for Bun?</strong></summary>
125
+
126
+ Yes. BVM is a Bun version manager, similar in concept to nvm/fnm. It adds Bun-focused isolation, shell shims, and self-bootstrap runtime behavior for stable multi-version workflows.
127
+ </details>
128
+
129
+ <details>
130
+ <summary><strong>Why do global packages disappear after switching Bun versions?</strong></summary>
131
+
132
+ This is expected. BVM uses per-version global package isolation. Install global tools under each Bun version that needs them.
133
+ </details>
134
+
135
+ <details>
136
+ <summary><strong>How does `.bvmrc` work for project-level Bun version pinning?</strong></summary>
137
+
138
+ Create a `.bvmrc` file in your project root with a version string (for example, `1.1.0`). BVM resolves and applies that version for project workflows.
139
+ </details>
140
+
141
+ <details>
142
+ <summary><strong>Does BVM auto-install AI agent skills from SKILL.md?</strong></summary>
143
+
144
+ No. BVM manages Bun runtimes and version switching. Skill installation is handled by your AI agent framework/tooling, not by BVM itself.
145
+ </details>
146
+
147
+ <details>
148
+ <summary><strong>How to diagnose BVM environment issues quickly?</strong></summary>
149
+
150
+ Run `bvm doctor`. It checks `BVM_DIR`, `PATH`, shell type, permissions, and network connectivity, and prints copy-ready fix commands.
151
+ </details>
152
+
153
+ ---
154
+
155
+ ## Troubleshooting
156
+
157
+ - **Quick diagnostics (`doctor`)**
158
+ ```bash
159
+ bvm doctor
160
+ ```
161
+ `bvm doctor` now checks `BVM_DIR`, `PATH`, shell type, directory permission, and network connectivity.
162
+ Each item is shown as `PASS / WARN / FAIL` with a copy-ready fix command.
163
+
164
+ - **Global tools are not isolated after switching versions**: run `bvm setup`, restart your terminal, and make sure `which bun` points to `~/.bvm/shims/bun` (macOS/Linux). On Windows, use `where.exe bun` and ensure `...\\.bvm\\shims\\bun.cmd` is first.
165
+ - **A global tool is missing after switching versions**: this is expected (per-version isolation). Reinstall it under the active Bun version.
166
+
167
+ ---
168
+
105
169
  ## Design Philosophy
106
170
 
107
171
  ### ArchSense (Self-Bootstrapping)
@@ -114,4 +178,4 @@ Unlike managers that only switch the `PATH`, BVM performs **Filesystem-level Loc
114
178
 
115
179
  ## License
116
180
 
117
- MIT © [EricLLLLLL](https://github.com/EricLLLLLL)
181
+ MIT © [EricLLLLLL](https://github.com/EricLLLLLL)
package/README.zh-CN.md CHANGED
@@ -10,6 +10,12 @@
10
10
  <p align="center">
11
11
  <a href="https://bvm-core.pages.dev"><strong>官方网站与文档 »</strong></a>
12
12
  <br />
13
+ <a href="https://bvm-core.pages.dev/"><strong>English Site »</strong></a>
14
+ <br />
15
+ <a href="https://bvm-core.pages.dev/zh/from/npm"><strong>从 NPM 来?从这里开始 »</strong></a>
16
+ <br />
17
+ <a href="https://bvm-core.pages.dev/zh/wechat"><strong>关注公众号 »</strong></a>
18
+ <br />
13
19
  <br />
14
20
  <a href="./README.md">🇺🇸 English Docs</a>
15
21
  ·
@@ -33,10 +39,14 @@
33
39
 
34
40
  ---
35
41
 
42
+ 想在 Windows、macOS、Linux 间稳定切换 Bun 版本,并避免 PATH 漂移和全局包冲突?
43
+
36
44
  ## ⚡ 一键极速安装
37
45
 
38
46
  BVM 提供了智能安装脚本,**自动检测您的网络环境**。中国用户会自动切换至淘宝镜像源,海外用户使用官方源,无需手动配置。
39
47
 
48
+ 给 AI 助手自动执行(安装 + setup + 验证 + 生成 Skill):[install.md](./install.md)
49
+
40
50
  ### 方式 1: Shell 脚本 (推荐 - macOS / Linux)
41
51
  ```bash
42
52
  curl -fsSL https://bvm-core.pages.dev/install | bash
@@ -49,7 +59,7 @@ irm https://bvm-core.pages.dev/install | iex
49
59
 
50
60
  ### 方式 3: NPM (可选)
51
61
  ```bash
52
- npm install -g bvm-core@latest
62
+ npm install -g bvm-core@latest --foreground-scripts
53
63
  ```
54
64
 
55
65
  ---
@@ -102,6 +112,46 @@ echo "1.1.0" > .bvmrc
102
112
 
103
113
  ---
104
114
 
115
+ ## 常见问题 / FAQ
116
+
117
+ <details>
118
+ <summary><strong>Windows / macOS / Linux 怎么快速切换 Bun 版本?</strong></summary>
119
+
120
+ 安装 BVM 后,直接使用 `bvm install <version>` 安装版本,再用 `bvm use <version>` 切换即可。三大平台命令一致。
121
+ </details>
122
+
123
+ <details>
124
+ <summary><strong>BVM 是 Bun 版的 nvm/fnm 吗?</strong></summary>
125
+
126
+ 可以这么理解。BVM 是 Bun 的版本管理器,在 nvm/fnm 思路上补充了 Bun 场景的版本隔离、shim 机制和自举运行时能力。
127
+ </details>
128
+
129
+ <details>
130
+ <summary><strong>为什么切换 Bun 版本后,全局包命令不见了?</strong></summary>
131
+
132
+ 这是预期行为。BVM 采用“按版本隔离”的全局包目录。你需要在目标 Bun 版本下重新安装对应全局工具。
133
+ </details>
134
+
135
+ <details>
136
+ <summary><strong>`.bvmrc` 怎么做项目级版本锁定?</strong></summary>
137
+
138
+ 在项目根目录创建 `.bvmrc`,写入版本号(例如 `1.1.0`)。BVM 会按该版本解析并用于项目工作流。
139
+ </details>
140
+
141
+ <details>
142
+ <summary><strong>支持 skills 自动安装吗(例如读取 SKILL.md 自动装)?</strong></summary>
143
+
144
+ 不支持。BVM 只负责 Bun 运行时和版本切换;skills 的安装与管理由 AI Agent 框架或对应工具链负责。
145
+ </details>
146
+
147
+ <details>
148
+ <summary><strong>怎么快速定位 BVM 环境问题?</strong></summary>
149
+
150
+ 运行 `bvm doctor`。它会检查 `BVM_DIR`、`PATH`、shell 类型、目录权限和网络连通性,并输出可直接复制的修复命令。
151
+ </details>
152
+
153
+ ---
154
+
105
155
  ## 设计哲学
106
156
 
107
157
  ### ArchSense (架构自举)
@@ -112,6 +162,13 @@ BVM 不分发沉重的预编译二进制文件。相反,它利用 **Bun 管理
112
162
 
113
163
  ---
114
164
 
165
+ ## 排障
166
+
167
+ - **切换版本后还存在 pm2/cowsay 等全局命令**:先执行 `bvm setup`,重启终端,再检查 `which bun`(macOS/Linux)是否指向 `~/.bvm/shims/bun`;Windows 用 `where.exe bun` 并确保 `...\\.bvm\\shims\\bun.cmd` 排第一。
168
+ - **切换版本后找不到某个全局命令**:这是预期行为(按版本隔离),请在当前版本下重新 `bun install -g <pkg>`。
169
+
170
+ ---
171
+
115
172
  ## 开源协议
116
173
 
117
- MIT © [EricLLLLLL](https://github.com/EricLLLLLL)
174
+ MIT © [EricLLLLLL](https://github.com/EricLLLLLL)
package/dist/bvm-shim.js CHANGED
@@ -1,14 +1,15 @@
1
1
  const path = require('path');
2
- const { spawn } = require('child_process');
2
+ const { spawn, spawnSync } = require('child_process');
3
3
  const os = require('os');
4
4
  const fs = require('fs');
5
5
 
6
6
  /**
7
7
  * BVM Shim for Windows (JavaScript version)
8
+ * Features: Physical Execution Proxy - No Drift, Full Compatibility.
8
9
  */
9
10
 
10
11
  const BVM_DIR = process.env.BVM_DIR || path.join(os.homedir(), '.bvm');
11
- const CMD = process.argv[2] ? process.argv[2].replace(/\.exe$/i, '').replace(/\.cmd$/i, '') : 'bun';
12
+ const CMD = process.argv[2] ? process.argv[2].replace(/\.(exe|cmd|bat|ps1)$/i, '') : 'bun';
12
13
  const ARGS = process.argv.slice(3);
13
14
 
14
15
  function resolveVersion() {
@@ -50,70 +51,154 @@ function resolveVersion() {
50
51
  return '';
51
52
  }
52
53
 
53
- // Simple synchronous execution for performance
54
54
  const version = resolveVersion();
55
55
  if (!version) {
56
- console.error("BVM Error: No Bun version is active or default is set.");
56
+ console.error("BVM Error: No Bun version is active.");
57
57
  process.exit(1);
58
58
  }
59
59
 
60
60
  const versionDir = path.join(BVM_DIR, 'versions', version);
61
61
  const binDir = path.join(versionDir, 'bin');
62
- let realExecutable = path.join(binDir, CMD + '.exe');
63
- let finalArgs = ARGS;
62
+ const bunExe = path.join(binDir, 'bun.exe');
64
63
 
65
- if (!fs.existsSync(realExecutable)) {
66
- if (CMD === 'bunx') {
67
- // Fallback: Use 'bun.exe x' if 'bunx.exe' is missing
68
- const bunExe = path.join(binDir, 'bun.exe');
69
- if (fs.existsSync(bunExe)) {
70
- realExecutable = bunExe;
71
- finalArgs = ['x', ...ARGS];
72
- } else {
73
- console.error("BVM Error: Both 'bunx.exe' and 'bun.exe' are missing in Bun " + version);
74
- process.exit(127);
64
+ let realExecutable = '';
65
+ let isShellScript = false;
66
+
67
+ // 1. Core Logic: Resolve the PHYSICAL executable
68
+ if (CMD === 'bun') {
69
+ realExecutable = bunExe;
70
+ } else if (CMD === 'bunx') {
71
+ // Windows Bun doesn't have a physical bunx.exe, it's 'bun x'
72
+ realExecutable = bunExe;
73
+ ARGS.unshift('x');
74
+ } else {
75
+ // For 3rd party tools, find the physical shim created by Bun in the version dir
76
+ const extensions = ['.exe', '.cmd', '.bat', '.ps1'];
77
+ for (const ext of extensions) {
78
+ const p = path.join(binDir, CMD + ext);
79
+ if (fs.existsSync(p)) {
80
+ realExecutable = p;
81
+ isShellScript = (ext !== '.exe');
82
+ break;
75
83
  }
76
- } else {
77
- console.error("BVM Error: Command '" + CMD + "' not found in Bun " + version + " at " + realExecutable);
78
- process.exit(127);
79
84
  }
80
85
  }
81
86
 
82
- process.env.BUN_INSTALL = versionDir;
83
- process.env.PATH = binDir + path.delimiter + process.env.PATH;
87
+ if (!realExecutable || !fs.existsSync(realExecutable)) {
88
+ // Strict version isolation:
89
+ // If a tool isn't physically present in this version's bin dir,
90
+ // do NOT fall back to `bun x <tool>` (that would bypass isolation).
91
+ console.error(`BVM Error: Command '${CMD}' not found in Bun ${version}.`);
92
+ process.exit(127);
93
+ } else if (isShellScript) {
94
+ // JIT SELF-HEALING: If we are about to run a shell script (shim),
95
+ // ensure it's not broken by relative path drift.
96
+ try {
97
+ let content = fs.readFileSync(realExecutable, 'utf8');
98
+ // console.log("[DEBUG] Checking shim:", realExecutable);
99
+ if (content.includes('%~dp0\\..') || content.includes('$PSScriptRoot\\..')) {
100
+ console.log(`[bvm] Fixing broken shim: ${realExecutable}`);
101
+ const binDir = path.dirname(realExecutable);
102
+ const nodeModulesPeer = path.join(binDir, '..', 'node_modules');
103
+ const nodeModulesNested = path.join(binDir, '..', 'install', 'global', 'node_modules');
104
+
105
+ let nodeModulesBase = '';
106
+ if (fs.existsSync(nodeModulesPeer)) nodeModulesBase = nodeModulesPeer;
107
+ else if (fs.existsSync(nodeModulesNested)) nodeModulesBase = nodeModulesNested;
84
108
 
85
- const child = spawn(realExecutable, finalArgs, { stdio: 'inherit', shell: false });
86
- child.on('exit', (code) => {
87
- if (code === 0 && (CMD === 'bun' || CMD === 'bunx')) {
88
- const isGlobal = ARGS.includes('-g') || ARGS.includes('--global');
89
- const isInstall = ARGS.includes('install') || ARGS.includes('add') || ARGS.includes('remove') || ARGS.includes('upgrade');
90
-
91
- if (isGlobal && isInstall) {
92
- try {
93
- fixShims(binDir, versionDir);
94
- } catch(e) {}
109
+ if (nodeModulesBase) {
110
+ const absNodeModules = path.resolve(nodeModulesBase).replace(/\//g, '\\');
111
+ const oldPatterns = [
112
+ '%~dp0\\..\\node_modules',
113
+ '%dp0%\\..\\node_modules',
114
+ '%~dp0\\..\\install\\global\\node_modules',
115
+ '%dp0%\\..\\install\\global\\node_modules',
116
+ '$PSScriptRoot\\..\\node_modules',
117
+ '$PSScriptRoot\\..\\install\\global\\node_modules'
118
+ ];
119
+
120
+ let fixed = false;
121
+ for (const pat of oldPatterns) {
122
+ if (content.includes(pat)) {
123
+ content = content.split(pat).join(absNodeModules);
124
+ fixed = true;
125
+ }
126
+ }
127
+
128
+ if (fixed) {
129
+ fs.writeFileSync(realExecutable, content, 'utf8');
130
+ console.log(`[bvm] Shim fixed. New target: ${absNodeModules}`);
131
+ } else {
132
+ console.log(`[bvm] Failed to fix shim patterns.`);
133
+ }
134
+ } else {
135
+ console.log(`[bvm] Could not find node_modules in peer or nested location.`);
136
+ }
95
137
  }
138
+ } catch (e) {
139
+ console.error(`[bvm] JIT Fix Error: ${e.message}`);
96
140
  }
97
- process.exit(code ?? 0);
141
+ }
142
+
143
+ // 2. CONFIGURE ENVIRONMENT
144
+ const bunfigPath = path.join(versionDir, 'bunfig.toml');
145
+ const env = Object.assign({}, process.env, {
146
+ BUN_INSTALL: versionDir,
147
+ BUN_INSTALL_GLOBAL_DIR: versionDir,
148
+ BUN_INSTALL_GLOBAL_BIN: binDir,
149
+ BUN_CONFIG_FILE: bunfigPath, // Force bun to use version-specific bunfig
150
+ PATH: binDir + path.delimiter + process.env.PATH
98
151
  });
99
152
 
100
- function fixShims(binDir, versionDir) {
101
- try {
102
- const files = fs.readdirSync(binDir);
103
- for (const file of files) {
104
- if (file.endsWith('.cmd')) {
105
- const filePath = path.join(binDir, file);
106
- let content = fs.readFileSync(filePath, 'utf8');
107
- if (content.includes('%~dp0\\..')) {
108
- content = content.split('%~dp0\\..').join(versionDir);
109
- fs.writeFileSync(filePath, content, 'utf8');
153
+ // 3. EXECUTE THE PHYSICAL ORIGINAL
154
+ const child = spawn(realExecutable, ARGS, {
155
+ stdio: 'inherit',
156
+ shell: isShellScript,
157
+ env: env
158
+ });
159
+
160
+ child.on('exit', (code) => {
161
+ // AUTOMATIC REHASH: Ensure new commands are exposed immediately after installation
162
+ const installCmds = ['install', 'i', 'add', 'a', 'remove', 'rm', 'uninstall', 'upgrade', 'link', 'unlink'];
163
+
164
+ let needRehash = false;
165
+
166
+ if (CMD === 'bun' && ARGS.length > 0) {
167
+ const subCmd = ARGS[0];
168
+ const hasGlobalFlag = ARGS.includes('-g') || ARGS.includes('--global');
169
+
170
+ // For install/add/remove commands, only rehash if -g/--global is present
171
+ if (['install', 'i', 'add', 'a', 'remove', 'rm', 'uninstall', 'upgrade'].includes(subCmd)) {
172
+ needRehash = hasGlobalFlag;
173
+ }
174
+ // For link/unlink, always rehash
175
+ else if (['link', 'unlink'].includes(subCmd)) {
176
+ needRehash = true;
177
+ }
178
+ }
179
+
180
+ if (code === 0 && needRehash) {
181
+ const bvmCmd = path.join(BVM_DIR, 'bin', 'bvm.cmd');
182
+ if (fs.existsSync(bvmCmd)) {
183
+ try {
184
+ console.log('[bvm] Updating command registry...');
185
+ // Use synchronous call so user sees completion
186
+ const result = spawnSync(bvmCmd, ['rehash', '--silent'], {
187
+ stdio: 'inherit',
188
+ env: Object.assign({}, process.env, { BVM_DIR })
189
+ });
190
+ if (result.status === 0) {
191
+ console.log('[bvm] Done! New commands are now available.');
110
192
  }
193
+ } catch(e) {
194
+ // Silent fail - rehash is not critical
111
195
  }
112
196
  }
113
- } catch(e) {}
114
- }
197
+ }
198
+ process.exit(code ?? 0);
199
+ });
115
200
 
116
201
  child.on('error', (err) => {
117
- console.error("BVM Error: Failed to start child process: " + err.message);
202
+ console.error("BVM Error: " + err.message);
118
203
  process.exit(1);
119
204
  });
package/dist/bvm-shim.sh CHANGED
@@ -58,7 +58,30 @@ REAL_EXECUTABLE="$VERSION_DIR/bin/$CMD_NAME"
58
58
  if [ -x "$REAL_EXECUTABLE" ]; then
59
59
  export BUN_INSTALL="$VERSION_DIR"
60
60
  export PATH="$VERSION_DIR/bin:$PATH"
61
- exec "$REAL_EXECUTABLE" "$@"
61
+
62
+ # Inject version-specific config if present
63
+ if [ -f "$VERSION_DIR/bunfig.toml" ]; then
64
+ export BUN_CONFIG_FILE="$VERSION_DIR/bunfig.toml"
65
+ fi
66
+
67
+ # Execute the command
68
+ "$REAL_EXECUTABLE" "$@"
69
+ EXIT_CODE=$?
70
+
71
+ # Auto-Rehash Logic
72
+ if [ "$CMD_NAME" = "bun" ] && [ $EXIT_CODE -eq 0 ]; then
73
+ case "$1" in
74
+ install|i|add|a|remove|rm|upgrade|link|unlink)
75
+ (export BVM_DIR="$BVM_DIR"; "$BVM_DIR/bin/bvm" rehash --silent >/dev/null 2>&1 & disown)
76
+ ;;
77
+ esac
78
+ fi
79
+
80
+ exit $EXIT_CODE
81
+ elif [ "$CMD_NAME" = "bunx" ] && [ -x "$VERSION_DIR/bin/bun" ]; then
82
+ export BUN_INSTALL="$VERSION_DIR"
83
+ export PATH="$VERSION_DIR/bin:$PATH"
84
+ exec "$VERSION_DIR/bin/bun" x "$@"
62
85
  else
63
86
  echo "BVM Error: Command '$CMD_NAME' not found in Bun $VERSION." >&2
64
87
  exit 127