# ldesign-tool-runtime **Repository Path**: ldesign-v1/ldesign-tool-runtime ## Basic Information - **Project Name**: ldesign-tool-runtime - **Description**: LDesign runtime and toolchain management - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-20 - **Last Updated**: 2026-09-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # @ldesign/runtime > 面向 Node.js 工具链的运行时探测基础包,负责版本采集、包管理器推断、Node 范围校验与子进程环境变量注入。 ## 简介 `@ldesign/runtime` 把 CLI、脚本、构建工具里反复出现的运行时判断逻辑收敛成一套统一 API。它专注解决四类问题: 1. 探测当前机器上的 `node`、`npm`、`pnpm`、`yarn`、`bun` 2. 根据 `package.json`、workspace、lockfile、user-agent 推断项目更可能使用的包管理器 3. 根据策略生成 registry / cache 环境变量,并做轻量级 Node 版本范围校验 4. 输出包管理器解析 explain 报告,帮助 CLI、doctor、dry-run 说明“为什么这样选” 5. 生成运行时综合报告和可展示的解析摘要,减少上层工具重复拼装 doctor 输出 ## 安装 ```bash pnpm add @ldesign/runtime ``` ## 快速开始 ```ts import { collectRuntimeReport, createToolchainProcessEnv, explainPackageManagerResolution, resolvePackageManager, } from '@ldesign/runtime' const report = await collectRuntimeReport({ policy: { preferredNodeRange: '20.x || 22.x', preferredPackageManager: 'pnpm', registry: 'https://registry.npmmirror.com', }, }) const snapshot = report.snapshot const resolved = resolvePackageManager(snapshot, { preferredPackageManager: 'pnpm', }) const explanation = explainPackageManagerResolution(snapshot, { preferredPackageManager: 'pnpm', }) const env = createToolchainProcessEnv({ registry: 'https://registry.npmmirror.com', cacheDirectory: '.cache/npm', }) console.log(snapshot.versions) console.log(resolved.name) console.log(explanation.candidates) console.log(report.nodeVersion.ok) console.log(env.NPM_CONFIG_REGISTRY) ``` ## 核心能力 ### 1. 运行时版本探测 - 支持同步与异步两种模式 - 返回结构化版本记录,包含 `version`、`executable`、`error` - 内建 best-effort 缓存,适合在同一进程内重复调用 ```ts import { detectRuntime, detectRuntimeSync } from '@ldesign/runtime' const nodeVersion = await detectRuntime('node') const pnpmVersion = detectRuntimeSync('pnpm') ``` ### 2. 运行时快照采集 ```ts import { RuntimeService } from '@ldesign/runtime' const runtime = new RuntimeService() const snapshot = await runtime.collectSnapshot({ runtimes: ['node', 'npm', 'pnpm'], }) console.log(snapshot.platform) console.log(snapshot.arch) console.log(snapshot.versions) ``` ### 3. 项目包管理器推断 推断优先级如下: 1. 最近 `package.json#packageManager` 2. 工作区根 `package.json#packageManager` 3. `pnpm-workspace.yaml` / `pnpm-workspace.yml` 4. 最近 lockfile 5. `npm_config_user_agent` ```ts import { detectProjectPackageManager } from '@ldesign/runtime' const hint = detectProjectPackageManager({ cwd: process.cwd() }) console.log(hint?.name) console.log(hint?.source) ``` ### 4. 包管理器解析 Explain `resolvePackageManager()` 只返回最终选择;`explainPackageManagerResolution()` 会额外返回候选顺序、项目线索、策略快照、诊断备注和风险提示。它不会执行任何安装命令,适合 `doctor`、`--dry-run`、日志和测试断言。 ```ts import { collectRuntimeSnapshot, explainPackageManagerResolution } from '@ldesign/runtime' const snapshot = await collectRuntimeSnapshot() const explanation = explainPackageManagerResolution( snapshot, { preferredPackageManager: 'pnpm', packageManagerFallbackOrder: ['pnpm', 'npm', 'yarn'], }, { cwd: process.cwd(), env: process.env, } ) console.log(explanation.selected.name) console.table(explanation.candidates) console.log(explanation.warnings) ``` `packageManagerFallbackOrder` 可以自定义无策略或线索不可用时的回退顺序;未传入时默认使用 `pnpm -> yarn -> npm -> bun`。 ### 5. 包管理器命令 Helper ```ts import { createPackageManagerAddCommand, createPackageManagerDlxCommand, createPackageManagerExecCommand, createPackageManagerInstallCommand, createPackageManagerScriptCommand, } from '@ldesign/runtime' const install = createPackageManagerInstallCommand('pnpm', { frozenLockfile: true, }) const build = createPackageManagerScriptCommand('pnpm', 'build', ['--clean']) const addDev = createPackageManagerAddCommand('npm', ['vite@latest'], { dev: true, }) const localBin = createPackageManagerExecCommand('pnpm', 'vite', ['--version']) const once = createPackageManagerDlxCommand('pnpm', 'create-vite', ['demo']) console.log(install.commandLine) console.log(build.commandLine) console.log(addDev.commandLine) console.log(localBin.commandLine) console.log(once.commandLine) ``` ### 6. 运行时综合报告 ```ts import { collectRuntimeReport, formatPackageManagerResolutionExplanation } from '@ldesign/runtime' const report = await collectRuntimeReport({ policy: { preferredNodeRange: '20.x || 22.x', preferredPackageManager: 'pnpm', }, runtimes: ['node', 'npm', 'pnpm', 'yarn', 'bun'], }) console.log(report.packageManager.name) console.log(report.nodeVersion.ok) console.log(formatPackageManagerResolutionExplanation(report.packageManagerExplanation)) ``` ### 7. Node 版本范围校验 支持的简化语法: - 比较符:`>=18 <23` - caret / tilde:`^20.0.0`、`~20` - 通配符:`20.x` - 通配比较:`>=18.x <23.x` - 区间:`18 - 20`、`18.x - 20.x` - OR:`^20 || ^22` - 预发布版本:`>=22.0.0-rc.1 <22.0.0` ```ts import { checkNodeVersion, collectRuntimeSnapshot } from '@ldesign/runtime' const snapshot = await collectRuntimeSnapshot() const result = checkNodeVersion(snapshot, { preferredNodeRange: '20.x || 22.x', }) if (!result.ok) { throw new Error(result.reason) } ``` ### 8. 运行时缓存管理 `RuntimeService` 会在实例内缓存运行时版本探测结果。长生命周期进程可以显式查看和清理缓存: ```ts import { RuntimeService } from '@ldesign/runtime' const runtime = new RuntimeService() runtime.detectRuntimeSync('node') console.log(runtime.getCacheStats().versionEntries) runtime.clearCache() ``` ### 9. 子进程工具链环境变量注入 ```ts import { createToolchainProcessEnv, runCommand } from '@ldesign/runtime' const env = createToolchainProcessEnv( { registry: 'https://registry.npmmirror.com', cacheDirectory: '.cache/npm', }, { overrides: { NODE_OPTIONS: '--max-old-space-size=4096', }, } ) const result = await runCommand('npm', ['config', 'get', 'registry'], { env }) console.log(result.stdout) ``` 如果命令输出可能很长,可以用 `maxOutputLength` 限制单路 stdout / stderr 保留长度,结果中的 `stdoutTruncated` / `stderrTruncated` 会标记是否发生截断: ```ts const result = await runCommand('pnpm', ['list', '--json'], { maxOutputLength: 20_000, }) ``` ## API 列表 | API | 返回类型 | 说明 | | ---------------------------------------------------- | ------------------------------------- | ----------------------------------- | | `new RuntimeService()` | `RuntimeService` | 创建带缓存的运行时服务实例 | | `createRuntimeService()` | `RuntimeService` | 创建新的运行时服务实例 | | `RuntimeService#getCacheStats()` | `RuntimeCacheStats` | 获取服务实例缓存统计 | | `RuntimeService#clearCache()` | `void` | 清理服务实例探测缓存 | | `detectRuntime(name, options?)` | `Promise` | 异步探测单个运行时 | | `detectRuntimeSync(name, options?)` | `RuntimeVersion` | 同步探测单个运行时 | | `collectRuntimeSnapshot(options?)` | `Promise` | 异步采集运行时快照 | | `collectRuntimeSnapshotSync(options?)` | `RuntimeSnapshot` | 同步采集运行时快照 | | `collectRuntimeReport(options?)` | `Promise` | 异步采集运行时综合报告 | | `collectRuntimeReportSync(options?)` | `RuntimeReport` | 同步采集运行时综合报告 | | `createRuntimeReport(snapshot, policy?, options?)` | `RuntimeReport` | 基于已有快照创建运行时综合报告 | | `resolvePackageManager(snapshot, policy?, options?)` | `ResolvedPackageManager` | 结合策略与项目线索选出包管理器 | | `explainPackageManagerResolution(...)` | `PackageManagerResolutionExplanation` | 输出包管理器选择候选链路与诊断信息 | | `formatPackageManagerResolutionExplanation(...)` | `string` | 将解析 explain 结果格式化为日志文本 | | `checkNodeVersion(snapshot, policy?)` | `NodeVersionCheck` | 校验快照中的 Node 版本是否满足范围 | | `createToolchainEnv(policy?)` | `Record` | 生成 npm / pnpm 可复用的 env 变量 | | `createToolchainProcessEnv(policy?, options?)` | `NodeJS.ProcessEnv` | 合并基础环境、工具链策略和覆盖项 | | `detectProjectPackageManager(options?)` | `ProjectPackageManagerHint \| null` | 独立推断项目包管理器 | | `createPackageManagerInstallCommand(name, options?)` | `PackageManagerCommand` | 生成可移植的依赖安装命令 | | `createPackageManagerScriptCommand(name, script)` | `PackageManagerCommand` | 生成可移植的 package script 命令 | | `createPackageManagerAddCommand(name, packages)` | `PackageManagerCommand` | 生成可移植的依赖添加命令 | | `createPackageManagerRemoveCommand(name, packages)` | `PackageManagerCommand` | 生成可移植的依赖移除命令 | | `createPackageManagerExecCommand(name, executable)` | `PackageManagerCommand` | 生成包内可执行文件命令 | | `createPackageManagerDlxCommand(name, executable)` | `PackageManagerCommand` | 生成一次性包执行命令 | | `findNearestPackageJson(startDir?)` | `string \| null` | 向上查找最近的 `package.json` | | `findNearestLockfile(startDir?)` | `NearestLockfile \| null` | 向上查找最合适的 lockfile | | `findWorkspaceRoot(startDir?)` | `string \| null` | 向上查找工作区根目录 | | `readJsonFile(filePath)` | `T \| null` | 以容错方式读取 JSON 文件 | | `runCommand(command, args, options?)` | `Promise` | 异步执行命令并返回标准化结果 | | `runCommandSync(command, args, options?)` | `CommandResult` | 同步执行命令并返回标准化结果 | | `resolveExecutablePath(command, env?)` | `string \| undefined` | 从 PATH 中解析命令对应的可执行文件 | | `extractNumericVersion(value)` | `string \| null` | 从任意文本提取数字版本号 | | `compareVersions(left, right)` | `number` | 比较两个版本号的大小 | | `satisfiesSimpleRange(current, range)` | `boolean \| null` | 校验版本是否满足简化范围表达式 | ## 子路径导入 当只需要局部能力时,可以通过子路径导入: ```ts import { runCommand } from '@ldesign/runtime/command' import { createToolchainEnv, createToolchainProcessEnv } from '@ldesign/runtime/env' import { resolveExecutablePath } from '@ldesign/runtime/executable' import { createPackageManagerDlxCommand, createPackageManagerExecCommand, createPackageManagerScriptCommand, detectProjectPackageManager, } from '@ldesign/runtime/project' import { collectRuntimeReport, formatPackageManagerResolutionExplanation, RuntimeService, } from '@ldesign/runtime/runtime' import { satisfiesSimpleRange } from '@ldesign/runtime/version' ``` ## 开发指南 ```bash pnpm run type-check pnpm run lint:check pnpm run test:run pnpm run build pnpm run verify ``` 说明: - 构建由 `@ldesign/pack` 零配置驱动,默认从 `src/**/*.ts` 推导入口 - 打包范围为 `src/**/*.ts`,会生成 ESM、CJS、`.d.ts`、sourcemap 和 `.d.ts.map` - 测试由 `ltesting run:unit` 调起 Vitest ## 文档 - 设计说明:[docs/design.md](docs/design.md) - 快速开始:[docs/guide/gettingStarted.md](docs/guide/gettingStarted.md) ## 许可协议 MIT