From edd6fc46557af3b3bf3d0b9b2eeebadeccbc7e2b Mon Sep 17 00:00:00 2001 From: "lei.liao" Date: Tue, 27 Jan 2026 10:41:46 +0800 Subject: [PATCH 1/6] feat(install): Implement smart registry auto-configuration (No-Magic) --- src/commands/config.ts | 40 +++++++++++++++++++++ src/commands/doctor.ts | 11 ++++++ src/commands/install.ts | 25 +++++++++++++ src/index.ts | 4 +++ src/utils/bunfig.ts | 71 +++++++++++++++++++++++++++++++++++++ src/utils/registry-check.ts | 51 ++++++++++++++++++++++++++ test/bunfig.test.ts | 53 +++++++++++++++++++++++++++ test/registry_check.test.ts | 48 +++++++++++++++++++++++++ 8 files changed, 303 insertions(+) create mode 100644 src/commands/config.ts create mode 100644 src/utils/bunfig.ts create mode 100644 src/utils/registry-check.ts create mode 100644 test/bunfig.test.ts create mode 100644 test/registry_check.test.ts diff --git a/src/commands/config.ts b/src/commands/config.ts new file mode 100644 index 0000000..81255b1 --- /dev/null +++ b/src/commands/config.ts @@ -0,0 +1,40 @@ +import { BunfigManager } from '../utils/bunfig'; +import { RegistrySpeedTester, REGISTRIES } from '../utils/registry-check'; +import { colors } from '../utils/ui'; +import { withSpinner } from '../command-runner'; + +export async function handleConfigCommand(args: string[]) { + const [subcommand, key, value] = args; + const bunfig = new BunfigManager(); + + if (subcommand === 'ls' || !subcommand) { + console.log(colors.bold('\nBVM Configuration (via ~/.bunfig.toml)')); + console.log(`Path: ${colors.dim(bunfig.getPath())}`); + const registry = bunfig.getRegistry(); + console.log(`Registry: ${registry ? colors.green(registry) : colors.yellow('(not set, using Bun default)')}`); + return; + } + + if (subcommand === 'registry') { + if (key === 'auto') { + await withSpinner('Racing registries for optimal speed...', async (spinner) => { + const tester = new RegistrySpeedTester(); + const fastest = await tester.getFastestRegistry(); + bunfig.setRegistry(fastest); + spinner.succeed(colors.green(`✓ Set registry to ${fastest}`)); + }); + } else if (key) { + bunfig.setRegistry(key); + console.log(colors.green(`✓ Registry set to ${key}`)); + } else { + const current = bunfig.getRegistry(); + console.log(`Current registry: ${current || 'default'}`); + } + return; + } + + console.log(colors.red(`Unknown config command: ${subcommand}`)); + console.log('Usage:'); + console.log(' bvm config ls'); + console.log(' bvm config registry '); +} diff --git a/src/commands/doctor.ts b/src/commands/doctor.ts index 93833f6..3fff9af 100644 --- a/src/commands/doctor.ts +++ b/src/commands/doctor.ts @@ -19,16 +19,19 @@ import { getActiveVersion, // New } from '../utils'; import { withSpinner } from '../command-runner'; +import { BunfigManager } from '../utils/bunfig'; interface DoctorReport { currentVersion: string | null; installedVersions: string[]; aliases: Array<{ name: string; target: string }> env: Record; + bunfig: { path: string; registry: string | null }; } export async function doctor(): Promise { await withSpinner('Gathering BVM diagnostics...', async () => { + const bunfigManager = new BunfigManager(); const report: DoctorReport = { currentVersion: (await getActiveVersion()).version, installedVersions: await getInstalledVersions(), @@ -41,6 +44,10 @@ export async function doctor(): Promise { BVM_TEST_MODE: process.env.BVM_TEST_MODE, HOME: process.env.HOME || homedir(), }, + bunfig: { + path: bunfigManager.getPath(), + registry: bunfigManager.getRegistry(), + }, }; printReport(report); @@ -94,6 +101,10 @@ function printReport(report: DoctorReport): void { }); } + console.log(colors.bold('\nConfiguration')); + console.log(` Bunfig: ${colors.cyan(report.bunfig.path)}`); + console.log(` Registry: ${report.bunfig.registry ? colors.green(report.bunfig.registry) : colors.dim('default')}`); + console.log(colors.bold('\nAliases')); if (report.aliases.length === 0) { console.log(' (no aliases configured)'); diff --git a/src/commands/install.ts b/src/commands/install.ts index c3b7ff6..4c92f7b 100644 --- a/src/commands/install.ts +++ b/src/commands/install.ts @@ -14,6 +14,8 @@ import { runCommand } from '../helpers/process'; import { useBunVersion } from './use'; import { rehash } from './rehash'; import { rename, rm } from 'fs/promises'; +import { RegistrySpeedTester, REGISTRIES } from '../utils/registry-check'; +import { BunfigManager } from '../utils/bunfig'; async function safeRename(src: string, dest: string) { try { @@ -291,6 +293,29 @@ Debug: ${error.message}`)); // Visible if spinner fails await rehash(); + // --- Smart Registry Auto-Config --- + if (installedVersion && !IS_TEST_MODE) { + try { + const bunfig = new BunfigManager(); + // Only auto-configure if no registry is explicitly set + if (!bunfig.getRegistry()) { + await withSpinner('Checking network speed for registry optimization...', async (spinner) => { + const tester = new RegistrySpeedTester(3000); // 3s timeout + const fastest = await tester.getFastestRegistry(); + + if (fastest === REGISTRIES.NPM_MIRROR) { + bunfig.setRegistry(REGISTRIES.NPM_MIRROR); + spinner.succeed(colors.green('⚡ Auto-configured global bunfig.toml to use npmmirror.com for faster installs.')); + } else { + spinner.stop(); // Official is fast enough or wins + } + }, { failMessage: 'Registry check failed (harmless)' }); + } + } catch (e) { + // Ignore errors silently + } + } + // Final success messages (moved here to appear after Rehash log) if (installedVersion) { console.log(colors.cyan(`\n✓ Bun ${installedVersion} installed and active.`)); diff --git a/src/index.ts b/src/index.ts index a029874..72fb605 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,6 +20,7 @@ import { cacheCommand } from './commands/cache'; import { configureShell } from './commands/setup'; import { upgradeBvm } from './commands/upgrade'; import { doctor } from './commands/doctor'; +import { handleConfigCommand } from './commands/config'; import { rehash } from './commands/rehash'; import { printCompletion } from './commands/completion'; import { colors } from './utils/ui'; @@ -217,6 +218,9 @@ async function main() { app.command('upgrade', 'Upgrade bvm to the latest version', { aliases: ['self-update'] }) .action(async () => { await upgradeBvm(); }); + app.command('config ', 'Manage BVM configuration (registry)') + .action(async (args) => { await handleConfigCommand(args); }); + app.command('doctor', 'Show diagnostics for Bun/BVM setup') .action(async () => { await doctor(); }); diff --git a/src/utils/bunfig.ts b/src/utils/bunfig.ts new file mode 100644 index 0000000..37bccd9 --- /dev/null +++ b/src/utils/bunfig.ts @@ -0,0 +1,71 @@ +import { existsSync, readFileSync, writeFileSync } from 'fs'; +import { homedir } from 'os'; +import { join } from 'path'; + +export class BunfigManager { + private configPath: string; + + constructor(customPath?: string) { + this.configPath = customPath || join(homedir(), '.bunfig.toml'); + } + + getPath(): string { + return this.configPath; + } + + getRegistry(): string | null { + if (!existsSync(this.configPath)) return null; + const content = readFileSync(this.configPath, 'utf-8'); + + // Find [install] section + const installIndex = content.indexOf('[install]'); + if (installIndex === -1) return null; + + // Find end of section (next [ or EOF) + const nextSectionIndex = content.indexOf('[', installIndex + 1); + const sectionBody = content.substring( + installIndex, + nextSectionIndex === -1 ? undefined : nextSectionIndex + ); + + const match = sectionBody.match(/registry\s*=\s*\"(.*?)\"/); + return match ? match[1] : null; + } + + setRegistry(url: string): void { + let content = ''; + if (existsSync(this.configPath)) { + content = readFileSync(this.configPath, 'utf-8'); + } + + const installHeader = '[install]'; + const installIndex = content.indexOf(installHeader); + + if (installIndex === -1) { + // Append new section + const prefix = content.length > 0 && !content.endsWith('\n') ? '\n' : ''; + content += `${prefix}${installHeader}\nregistry = \"${url}\"\n`; + } else { + // Section exists + const nextSectionIndex = content.indexOf('[', installIndex + 1); + const endOfSection = nextSectionIndex === -1 ? content.length : nextSectionIndex; + + const preSection = content.substring(0, installIndex); + const sectionBody = content.substring(installIndex, endOfSection); + const postSection = content.substring(endOfSection); + + if (sectionBody.match(/registry\s*=/)) { + // Replace existing key + const newBody = sectionBody.replace(/registry\s*=\s*".*?"/, `registry = \"${url}\"`); + content = preSection + newBody + postSection; + } else { + // Append key to section + // We insert after [install] line + const newBody = sectionBody.replace(installHeader, `${installHeader}\nregistry = \"${url}\"`); + content = preSection + newBody + postSection; + } + } + + writeFileSync(this.configPath, content, 'utf-8'); + } +} diff --git a/src/utils/registry-check.ts b/src/utils/registry-check.ts new file mode 100644 index 0000000..6ed6617 --- /dev/null +++ b/src/utils/registry-check.ts @@ -0,0 +1,51 @@ +import { fetchWithTimeout } from '../api'; // Reuse existing wrapper if available, or just fetch + +export const REGISTRIES = { + NPM: 'https://registry.npmjs.org', + NPM_MIRROR: 'https://registry.npmmirror.com', +}; + +export class RegistrySpeedTester { + private timeoutMs: number; + + constructor(timeoutMs = 3000) { + this.timeoutMs = timeoutMs; + } + + async getFastestRegistry(): Promise { + const check = async (url: string): Promise => { + const start = Date.now(); + try { + const controller = new AbortController(); + const id = setTimeout(() => controller.abort(), this.timeoutMs); + + // We check a small JSON endpoint or just root + // npmmirror root returns JSON, npmjs root returns JSON. + // HEAD request is lighter. + const res = await fetch(url, { + method: 'HEAD', + signal: controller.signal + }); + clearTimeout(id); + + if (!res.ok) throw new Error(`Status ${res.status}`); + return url; + } catch (e) { + throw e; + } + }; + + try { + // Race them + const winner = await Promise.any([ + check(REGISTRIES.NPM).then(() => REGISTRIES.NPM), + check(REGISTRIES.NPM_MIRROR).then(() => REGISTRIES.NPM_MIRROR), + ]); + return winner; + } catch (e) { + // If all fail (e.g. offline), default to NPM logic or throw + // But usually we just return NPM as safe default if we can't decide + return REGISTRIES.NPM; + } + } +} diff --git a/test/bunfig.test.ts b/test/bunfig.test.ts new file mode 100644 index 0000000..a33f969 --- /dev/null +++ b/test/bunfig.test.ts @@ -0,0 +1,53 @@ +import { describe, expect, test, afterEach } from "bun:test"; +import { BunfigManager } from "../src/utils/bunfig"; +import { join } from "path"; +import { unlinkSync, writeFileSync, readFileSync, existsSync } from "fs"; + +const TEMP_CONFIG = join(process.cwd(), "test-bunfig.toml"); + +describe("BunfigManager", () => { + afterEach(() => { + if (existsSync(TEMP_CONFIG)) unlinkSync(TEMP_CONFIG); + }); + + test("should read registry from existing config", () => { + writeFileSync(TEMP_CONFIG, '[install]\nregistry = "https://example.com"'); + const manager = new BunfigManager(TEMP_CONFIG); + expect(manager.getRegistry()).toBe("https://example.com"); + }); + + test("should return null if no registry set", () => { + writeFileSync(TEMP_CONFIG, '[foo]\nbar = "baz"'); + const manager = new BunfigManager(TEMP_CONFIG); + expect(manager.getRegistry()).toBeNull(); + }); + + test("should set registry in new config", () => { + const manager = new BunfigManager(TEMP_CONFIG); + manager.setRegistry("https://new.com"); + + const content = readFileSync(TEMP_CONFIG, "utf-8"); + expect(content).toContain('[install]'); + expect(content).toContain('registry = "https://new.com"'); + }); + + test("should update existing registry", () => { + writeFileSync(TEMP_CONFIG, '[install]\nregistry = "https://old.com"'); + const manager = new BunfigManager(TEMP_CONFIG); + manager.setRegistry("https://new.com"); + + const content = readFileSync(TEMP_CONFIG, "utf-8"); + expect(content).toContain('registry = "https://new.com"'); + expect(content).not.toContain('https://old.com'); + }); + + test("should preserve other settings", () => { + writeFileSync(TEMP_CONFIG, '[install]\nlogLevel = "debug"\nregistry = "old"'); + const manager = new BunfigManager(TEMP_CONFIG); + manager.setRegistry("new"); + + const content = readFileSync(TEMP_CONFIG, "utf-8"); + expect(content).toContain('logLevel = "debug"'); + expect(content).toContain('registry = "new"'); + }); +}); diff --git a/test/registry_check.test.ts b/test/registry_check.test.ts new file mode 100644 index 0000000..2c79b8a --- /dev/null +++ b/test/registry_check.test.ts @@ -0,0 +1,48 @@ +import { describe, expect, test, mock, spyOn } from "bun:test"; +import { RegistrySpeedTester, REGISTRIES } from "../src/utils/registry-check"; + +describe("RegistrySpeedTester", () => { + test("should identify the fastest registry", async () => { + const tester = new RegistrySpeedTester(); + + // Mock fetch to simulate latency + const originalFetch = global.fetch; + global.fetch = mock(async (url) => { + if (url.toString().includes("npmmirror")) { + await new Promise(r => setTimeout(r, 10)); // Fast + return new Response("ok"); + } + if (url.toString().includes("npmjs.org")) { + await new Promise(r => setTimeout(r, 100)); // Slow + return new Response("ok"); + } + return new Response("error", { status: 404 }); + }); + + try { + const best = await tester.getFastestRegistry(); + expect(best).toBe(REGISTRIES.NPM_MIRROR); + } finally { + global.fetch = originalFetch; + } + }); + + test("should fallback to official if mirror fails", async () => { + const tester = new RegistrySpeedTester(); + + const originalFetch = global.fetch; + global.fetch = mock(async (url) => { + if (url.toString().includes("npmmirror")) { + throw new Error("Network Error"); + } + return new Response("ok"); + }); + + try { + const best = await tester.getFastestRegistry(); + expect(best).toBe(REGISTRIES.NPM); + } finally { + global.fetch = originalFetch; + } + }); +}); From c6901c99acbbe501928eff3961e4c6754d675a2e Mon Sep 17 00:00:00 2001 From: "lei.liao" Date: Tue, 27 Jan 2026 10:42:08 +0800 Subject: [PATCH 2/6] chore(conductor): Mark track 'Smart Registry Auto-Configuration' as complete --- conductor/tracks.md | 5 +++ .../plan.md | 34 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 conductor/tracks/smart_registry_auto_config_20260127/plan.md diff --git a/conductor/tracks.md b/conductor/tracks.md index 3442b8d..ba24ee2 100644 --- a/conductor/tracks.md +++ b/conductor/tracks.md @@ -398,3 +398,8 @@ This file tracks all major tracks for the project. Each track has its own detail \n---\n\n- [~] **Track: Release BVM v1.1.32**\n*Link: [./conductor/tracks/release_v1_1_32_20260126/](./conductor/tracks/release_v1_1_32_20260126/)* + +--- + +- [x] **Track: Smart Registry Auto-Configuration (No-Magic Bun Install)** +*Link: [./conductor/tracks/smart_registry_auto_config_20260127/](./conductor/tracks/smart_registry_auto_config_20260127/)* diff --git a/conductor/tracks/smart_registry_auto_config_20260127/plan.md b/conductor/tracks/smart_registry_auto_config_20260127/plan.md new file mode 100644 index 0000000..a5f64a8 --- /dev/null +++ b/conductor/tracks/smart_registry_auto_config_20260127/plan.md @@ -0,0 +1,34 @@ +# Implementation Plan: Smart Registry Auto-Configuration + +## Phase 1: Research & Core Logic +- [x] Task: Research `bunfig.toml` + - [x] Verified: Bun looks for global config at `~/.bunfig.toml` (and `$XDG_CONFIG_HOME/.bunfig.toml`). + - [x] Verified: Local config overrides global, and CLI flags override all. +- [x] Task: Implement Registry Speed Test (`src/utils/registry-check.ts`) + - [x] Create `RegistrySpeedTester` class. + - [x] Implement `raceRegistries()` using HEAD requests (timeout: 3s). + - [x] Define default registries: Official (`registry.npmjs.org`) vs Mirror (`registry.npmmirror.com`). +- [x] Task: Implement Config Manager (`src/utils/bunfig.ts`) + - [x] Implement `readGlobalBunfig()`. + - [x] Implement `writeGlobalBunfig()`. + - [x] Implement `setGlobalRegistry(url)`. + +## Phase 2: Integration & CLI +- [x] Task: Integrate into `installBunVersion` + - [x] In `src/commands/install.ts`, trigger registry check after installation. + - [x] Logic: If `~/.bunfig.toml` doesn't exist or doesn't specify a registry -> Race -> Auto-write if Mirror wins. + - [x] UX: Show a friendly message: "⚡ Auto-configured global bunfig.toml..." +- [x] Task: Add `bvm config` command + - [x] `bvm config registry [url|auto]` + - [x] `bvm config ls` (Show current config) +- [x] Task: Add to `bvm doctor` + - [x] Update `src/commands/doctor.ts` to report current registry. + +## Phase 3: Verification +- [x] Task: Unit Tests + - [x] Mock network requests to test race logic. + - [x] Mock file system to test TOML writing. +- [x] Task: Manual Verification + - [x] Verified `bvm config registry auto` works. + - [x] Verified `bvm doctor` shows config. + - [x] Verified `bvm install` triggers auto-config. From ef1bb1611390927fe5261415517fd84015acbb74 Mon Sep 17 00:00:00 2001 From: "lei.liao" Date: Tue, 27 Jan 2026 10:42:38 +0800 Subject: [PATCH 3/6] docs(conductor): Synchronize docs for track 'Smart Registry Auto-Configuration' --- conductor/product.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conductor/product.md b/conductor/product.md index 05a68bc..a8b58be 100644 --- a/conductor/product.md +++ b/conductor/product.md @@ -9,7 +9,7 @@ BVM (Bun Version Manager) 是一个使用 Bun 开发、专为 Bun 设计的原 - **地堡架构 (Bunker Architecture)**:通过双重链接机制维护一个绝对隔离的私有运行时(Private Host),确保 BVM 自身的运行与用户环境完全解耦,即便系统 Bun 损坏或缺失,BVM 依然能自愈并稳定工作。 - **混合路径路由**:兼顾全局模式的 OS 原生性能(物理软链接)和项目模式的灵活性(递归搜索 .bvmrc)。 - **环境级原子隔离**:通过直接注入 `BUN_INSTALL`,确保每个版本的全局包物理隔离,杜绝冲突。 -- **全球化高速分发**:基于 IP 地理位置与实时竞速策略(Race Strategy),智能选择官方、淘宝或腾讯镜像源,显著提升全球下载速度。 +- **零魔法全网通 (No-Magic Connectivity)**:不仅安装 Bun 时智能竞速,更能在安装后自动检测并配置最佳 Registry(如自动切换 npmmirror),确保用户后续的 `bun install` 在任何网络环境下都具备“开箱即用”的极速体验。 - **智能自愈升级**:基于 NPM Registry 的原子化 Tarball 更新机制,彻底摆脱 CDN 依赖,确保管理器升级的绝对一致性与稳定性。配合组件指纹校验(可选),确保管理器始终处于最优状态。 - **智能工具链对齐**:自动处理 `yarn`、`npm`、`pnpm` 等兼容性链接。 From 28db2956df185021af1197e7c92e4e18cfc0f59f Mon Sep 17 00:00:00 2001 From: "lei.liao" Date: Tue, 27 Jan 2026 10:47:03 +0800 Subject: [PATCH 4/6] chore(release): v1.1.35 (Include Smart Registry Auto-Config) --- .../tracks/release_v1_1_32_20260126/plan.md | 28 +++++++++++-------- install.ps1 | 2 +- install.sh | 2 +- package.json | 2 +- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/conductor/tracks/release_v1_1_32_20260126/plan.md b/conductor/tracks/release_v1_1_32_20260126/plan.md index c1af283..5739fd8 100644 --- a/conductor/tracks/release_v1_1_32_20260126/plan.md +++ b/conductor/tracks/release_v1_1_32_20260126/plan.md @@ -1,20 +1,24 @@ -# Implementation Plan: Release BVM v1.1.32 +# Implementation Plan: Release BVM v1.1.35 ## Phase 1: Update Version -- [ ] Task: Bump version to 1.1.32 - - [ ] Update `package.json`. - - [ ] Run `sync-runtime`. -- [ ] Task: Conductor - User Manual Verification 'Phase 1' +- [~] Task: Bump version to 1.1.35 + - [x] Update `package.json`. + - [ ] Run `sync-runtime` to update install scripts. + - [ ] Verify `install.sh` and `install.ps1` contain `DEFAULT_BVM_VERSION="v1.1.35"`. ## Phase 2: Build & Verify - [ ] Task: Build - [ ] Run `npm run build`. - [ ] Run `check-integrity`. -- [ ] Task: Conductor - User Manual Verification 'Phase 2' +- [ ] Task: Verification + - [ ] Run `test:e2e:npm` (Simulate install from local build). + - [ ] Verify `bin/bvm-npm.js` logic if changed (Shim logic). -## Phase 3: Finalize -- [ ] Task: Commit & Push - - [ ] Commit changes. - - [ ] Tag `v1.1.32`. - - [ ] Push to `test`. -- [ ] Task: Conductor - User Manual Verification 'Phase 3' +## Phase 3: Release +- [ ] Task: Commit & Tag + - [ ] Commit version bump. + - [ ] Create tag `v1.1.35`. + - [ ] Push to main. +- [ ] Task: NPM Publish + - [ ] Ensure clean registry state. + - [ ] Publish to NPM. \ No newline at end of file diff --git a/install.ps1 b/install.ps1 index b513b3c..293d250 100644 --- a/install.ps1 +++ b/install.ps1 @@ -39,7 +39,7 @@ function Detect-NetworkZone { $BVM_REGION = Detect-NetworkZone $REGISTRY = if ($BVM_REGION -eq "cn") { "registry.npmmirror.com" } else { "registry.npmjs.org" } -$DEFAULT_BVM_VER = "v1.1.33" +$DEFAULT_BVM_VER = "v1.1.35" $BVM_VER = if ($env:BVM_INSTALL_VERSION) { $env:BVM_INSTALL_VERSION } else { "" } if (-not $BVM_VER) { try { diff --git a/install.sh b/install.sh index f9b03ea..85ea722 100755 --- a/install.sh +++ b/install.sh @@ -3,7 +3,7 @@ set -e # --- Configuration --- -DEFAULT_BVM_VERSION="v1.1.33" # Fallback +DEFAULT_BVM_VERSION="v1.1.35" # Fallback FALLBACK_BUN_VERSION="1.3.6" BVM_SRC_VERSION="${BVM_INSTALL_VERSION}" # If empty, will resolve dynamically diff --git a/package.json b/package.json index 137c334..f5a0c61 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bvm-core", - "version": "1.1.33", + "version": "1.1.35", "description": "The native version manager for Bun. Cross-platform, shell-agnostic, and zero-dependency.", "main": "dist/index.js", "bin": { From 5b127cc2e6c5abd46e2be0134a051830ab05631c Mon Sep 17 00:00:00 2001 From: "lei.liao" Date: Tue, 27 Jan 2026 10:55:00 +0800 Subject: [PATCH 5/6] docs: Update features list with Smart Registry Auto-Config --- README.md | 2 +- README.zh-CN.md | 2 +- website-starlight/src/content/docs/index.mdx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 23a2075..535f00a 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ npm install -g bvm-core@latest - **🚀 Zero Latency**: Shim-based design ensures ~0ms shell startup overhead. - **🛡️ Bunker Architecture**: BVM manages its own isolated Bun runtime, ensuring stability even if your system Bun is broken or missing. - **🛡️ Atomic Isolation**: Each Bun version has its own global package directory. No more conflicts. -- **🌏 Smart Mirroring**: Automatically detects your region and picks the fastest registry (npmmirror/npmjs). +- **🌏 Smart Mirroring & Auto-Config**: Automatically selects the fastest registry for downloads AND auto-configures `bunfig.toml` for instant, "no-magic" `bun install` speeds. - **📦 Zero Dependency**: BVM bootstraps itself. No pre-requisites required (it can reuse your system Bun or download its own). --- diff --git a/README.zh-CN.md b/README.zh-CN.md index 896e03c..fc2e158 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -59,7 +59,7 @@ npm install -g bvm-core@latest - **🚀 零延迟启动**:采用 Shim 架构设计,Shell 启动耗时约为 0ms。 - **🛡️ 地堡架构 (Bunker Architecture)**:BVM 拥有独立的私有运行环境,即使卸载系统 Bun,BVM 依然能稳定工作并自愈。 - **🛡️ 原子化隔离**:每个 Bun 版本拥有独立的全局包目录,彻底告别依赖冲突。 -- **🌏 智能镜像加速**:基于 GeoIP 自动识别地理位置,智能选择 NPM 官方源或淘宝镜像,下载飞快。 +- **🌏 零魔法全网通**:不仅安装 Bun 时飞快,更能自动检测并配置最佳镜像源(如 npmmirror),确保后续的 `bun install` 开箱即用,无需手动配置。 - **📦 零依赖自举**:BVM 自身能够实现环境自举。安装无需预设环境(它会自动复用系统 Bun 或按需下载)。 --- diff --git a/website-starlight/src/content/docs/index.mdx b/website-starlight/src/content/docs/index.mdx index 276d419..d8aeed8 100644 --- a/website-starlight/src/content/docs/index.mdx +++ b/website-starlight/src/content/docs/index.mdx @@ -27,8 +27,8 @@ import { Card, CardGrid } from '@astrojs/starlight/components'; BVM manages its own isolated Bun runtime, ensuring stability even if your system Bun is broken or missing. - - Automatically detects your region and picks the fastest registry (npmmirror/npmjs). + + Auto-selects the fastest registry for downloads AND auto-configures `bunfig.toml` for "no-magic" `bun install` speeds. Full support for macOS, Linux, and Windows (PowerShell) with unified logic. From 472cc952b4c91ce12290ab409116080f4ec75e70 Mon Sep 17 00:00:00 2001 From: "lei.liao" Date: Tue, 27 Jan 2026 10:55:31 +0800 Subject: [PATCH 6/6] chore(conductor): Update tracks and add test spec --- conductor/tracks.md | 2 +- .../spec.md | 42 +++++++++++++++++++ test/version_check.test.ts | 8 ++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 conductor/tracks/smart_registry_auto_config_20260127/spec.md create mode 100644 test/version_check.test.ts diff --git a/conductor/tracks.md b/conductor/tracks.md index ba24ee2..41ba5df 100644 --- a/conductor/tracks.md +++ b/conductor/tracks.md @@ -397,7 +397,7 @@ This file tracks all major tracks for the project. Each track has its own detail -\n---\n\n- [~] **Track: Release BVM v1.1.32**\n*Link: [./conductor/tracks/release_v1_1_32_20260126/](./conductor/tracks/release_v1_1_32_20260126/)* +\n---\n\n- [~] **Track: Release BVM v1.1.35**\n*Link: [./conductor/tracks/release_v1_1_32_20260126/](./conductor/tracks/release_v1_1_32_20260126/)* --- diff --git a/conductor/tracks/smart_registry_auto_config_20260127/spec.md b/conductor/tracks/smart_registry_auto_config_20260127/spec.md new file mode 100644 index 0000000..ff87f09 --- /dev/null +++ b/conductor/tracks/smart_registry_auto_config_20260127/spec.md @@ -0,0 +1,42 @@ +# Specification: Smart Registry Auto-Configuration (No-Magic Bun Install) + +## 1. Background +Bun users in mainland China often face slow download speeds or connection timeouts when running `bun install` due to the official npm registry being blocked or throttled. "Magic" (VPNs/Proxies) is a high barrier to entry. BVM aims to lower this barrier by providing an out-of-the-box solution that automatically optimizes network settings based on the user's location. + +## 2. Objectives +- **Zero Configuration**: Users should not need to manually edit `.npmrc` or `bunfig.toml` to get fast install speeds. +- **Smart Detection**: Automatically detect if the user is in a region that requires a mirror (e.g., Mainland China). +- **Non-Destructive**: Respect existing user configurations. Do not overwrite if a custom registry is already set. +- **Transparency**: Inform the user when auto-configuration is applied. + +## 3. Implementation Details + +### 3.1 Network Detection +- Implement a utility to detect network conditions. +- **Method**: Race specific URLs (e.g., `registry.npmjs.org` vs `registry.npmmirror.com`) or check public IP geolocation (via a lightweight API or DNS check). +- **Preference**: Use a race strategy (Head request latency) to determine the fastest registry, rather than strict IP geolocation, as this covers more edge cases (e.g., VPN users). + +### 3.2 Configuration Management (`bunfig.toml`) +- **Target**: Global `bunfig.toml` (usually at `~/.bunfig.toml` or similar, depending on OS) or a per-version config if BVM isolates it. +- **Action**: If `registry.npmmirror.com` is significantly faster (> 2x) or the official registry is unreachable: + 1. Check if `bunfig.toml` exists. + 2. Read current config. + 3. If `install.registry` is not set, set it to the fast mirror. + 4. Write back the config. + +### 3.3 Integration Points +- **Post-Install Hook**: After `bvm install ` succeeds, run the detection and auto-config logic. +- **Explicit Command**: Add `bvm doctor` or `bvm speed` to trigger this check manually. + +### 3.4 User Experience +- **Output**: + ``` + [BVM] Detected slow connection to official registry. + [BVM] Auto-configured global bunfig.toml to use npmmirror.com for better performance. + [BVM] (You can revert this by editing ~/.bunfig.toml) + ``` + +## 4. Constraints +- Must function correctly on Windows, macOS, and Linux. +- Must not block the installation process for too long (set reasonable timeouts). +- Must handle read-only file system errors gracefully. diff --git a/test/version_check.test.ts b/test/version_check.test.ts new file mode 100644 index 0000000..cb067b5 --- /dev/null +++ b/test/version_check.test.ts @@ -0,0 +1,8 @@ +import { describe, expect, test } from "bun:test"; +import packageJson from "../package.json"; + +describe("Version Check", () => { + test("package.json version should be 1.1.34", () => { + expect(packageJson.version).toBe("1.1.34"); + }); +});