AIRI 单仓工程实践:pnpm 全局虚拟存储、Git Worktree 多 Agent 并行开发与 v11 隔离全局包
在大型 pnpm monorepo 中同时维护多个分支或多个 AI Agent 并行作业时,每个检出目录各自复制一份 node_modules 既浪费磁盘又拖慢安装。本文基于 AIRI 仓库内置的 pnpm 技能参考文档,系统讲解 pnpm 全局虚拟存储(enableGlobalVirtualStore)的原理与边界、结合 git worktree 实现"近乎零成本"多分支并行的完整流程,以及 pnpm v11 隔离式全局包的安装规则。AIRI 当前锁定的包管理器为 pnpm 11.24.0(见 package.json 的 packageManager 字段),因此这些能力在该项目环境中均可直接适用。
一、pnpm 虚拟存储:从每项目硬链接到全局符号链接
默认模式:每项目一个 .pnpm 虚拟存储
默认情况下,每个 pnpm 项目都有自己的 node_modules/.pnpm 虚拟存储,其中存放指向内容寻址存储(content-addressable store)的硬链接。这已经比 npm/yarn 的全量复制高效得多,但在同一仓库存在多个检出(checkout)时,每个检出仍然会占据完整的包目录空间,首次安装也都需要实际写入。
启用全局虚拟存储
开启全局虚拟存储后,pnpm 只维护一个位于 <store-path>/links/ 的共享虚拟存储(可通过 pnpm store path 查询到),每个项目的 node_modules 中只剩下指向它的符号链接:
enableGlobalVirtualStore: true
两种模式下的 node_modules 结构对比:
# 默认(每项目 .pnpm,硬链接)
project-a/node_modules/lodash -> .pnpm/lodash@4.17.21/node_modules/lodash
# 全局虚拟存储(符号链接指向共享位置)
project-a/node_modules/lodash -> <store>/links/@/lodash/4.17.21/<hash>/node_modules/lodash
project-b/node_modules/lodash -> <store>/links/@/lodash/4.17.21/<hash>/node_modules/lodash # 同一目标
几个关键设计点:
- 包身份 = 依赖图的哈希。两个项目若拥有相同的
lodash@4.17.21且传递依赖树一致,会指向完全相同的目录(NixOS 式寻址);若 peer 依赖不同,则生成不同的存储条目。 - 每项目成本趋近于零:一旦某版本进入全局存储,后续项目的安装就是瞬间完成的符号链接写入。
- 版本状态:在 pnpm v11 中,该模式对
pnpm dlx/pnx(一次性执行)和全局安装已是默认行为;对项目级安装(pnpm install)则仍然是可选启用(opt-in)/实验性的。这一点也可以从 AIRI 仓库的 pnpm 技能索引得到印证:该技能明确将 global virtual store 归类为 v11 的行为变更之一,并且标注其适用于"git worktree 多 Agent 场景"(见 .agents/skills/pnpm/SKILL.md)。
AIRI 仓库的现状观察
从源码结构看,AIRI 仓库的 pnpm-workspace.yaml 目前并未启用 enableGlobalVirtualStore——其配置集中在使用 catalogMode、catalog、overrides、patchedDependencies、packageExtensions、allowBuilds 等能力上。这说明全局虚拟存储属于按需开启的优化项:单检出开发用默认模式即可,只有当仓库出现多检出(worktree / 并行 Agent)压力时才需要评估开启。这也符合该技能文档"对 project install 仍为实验性"的定位。
限制与适用边界(必须了解)
原文档明确列出三条限制,直接决定了该特性能否落地:
- CI 中自动禁用:CI 环境没有可复用的"温热缓存",收益不存在,pnpm 检测到 CI 会自动关闭该特性。这与 .agents/skills/pnpm/references/best-practices-ci.md 中"pnpm 在 CI 自动切换 frozen-lockfile 且自动禁用 global virtual store"的说明一致。
- 信任边界:共享存储是一份可写的共享状态,只应在相互信任的项目 / 用户 / 任务之间共享,并应使用文件系统权限保护该路径。这一点在 .agents/skills/pnpm/references/features-supply-chain-security.md 中也被强调:内容寻址存储、全局虚拟存储和元数据缓存同属 pnpm 的信任域,
verifyStoreIntegrity(默认true)只能检测意外损坏,不能让一个可被不可信方写入的存储变得安全。 - ESM 提升(hoisting)问题:pnpm 依赖
NODE_PATH实现未声明依赖的兜底解析,但 Node 对 ESM import 会忽略NODE_PATH。若某个 ESM 依赖内部 import 了它自己未声明的包,解析会失败。修复方式是使用packageExtensions补齐依赖声明,或引入@pnpm/plugin-esm-node-path配置依赖。AIRI 仓库自身就大量使用packageExtensions(见 pnpm-workspace.yaml 中为@pixiv/three-vrm-core、@tresjs/core、vitepress等补齐 peerDependencies 的段落),这条经验路径在本仓库中同样适用。
二、Git Worktree + 全局虚拟存储:多 Agent 并行的标准组合
为什么是 worktree
Git worktree 允许同时检出多个分支,各自位于独立目录,但共享同一个 .git 对象库。与全局虚拟存储组合后:每个 worktree 都拥有一棵功能完整的 node_modules,而磁盘开销几乎为零——这正是并行运行多个 AI Agent(每个 Agent 负责一个分支/任务)的理想条件。
完整操作流程
以裸仓库(bare repo)为枢纽,每个分支/Agent 一个 worktree:
# Bare repo as the hub, one worktree per branch/agent
git clone --bare https://github.com/your-org/your-monorepo.git your-monorepo
cd your-monorepo
git worktree add ./main main
git worktree add ./feature-auth feat/auth
git worktree add ./fix-api fix/api-error
工作区配置(在 monorepo 根目录的 pnpm-workspace.yaml 中):
packages:
- 'packages/*'
enableGlobalVirtualStore: true
随后在每个 worktree 中执行安装:
cd main && pnpm install # 首次安装:填充全局存储
cd ../feature-auth && pnpm install # 后续 worktree:近乎瞬间,只是符号链接
工作要点:
- 每个 worktree 有各自独立的
node_modules树,因此不同分支的 Agent 可以安装不同版本互不冲突;但所有包内容都来自同一个共享存储。 - 用
git worktree remove ./feature-auth移除 worktree。 - 原文档指出 pnpm 仓库自身就使用这套配置,并提供
pnpm worktree:new <branch|pr>辅助脚本;前提是所有 worktree/Agent 处于同一信任边界内。 - 与 AIRI 仓库的衔接:AIRI 的 workspace 目录结构为
packages/**、apps/**、plugins/**、integrations/**、services/**、docs/**、engines/**、server/**(见 pnpm-workspace.yaml 的packages字段)。若在本仓库采用 worktree 多 Agent 方案,packages列表应沿用这些 glob,再追加enableGlobalVirtualStore: true即可,无需改动其他配置。 - 从源码结构看,AIRI 仓库中已存在多 Agent 并行的实践痕迹:.agents/skills/pnpm/SKILL.md 面向 Agent 工作流生成,AGENTS.md 中"通过 shell 命令另起 Codex 或 Claude Code 实例完成实现"的做法,以及 .agents/skills/pnpm/references/best-practices-performance.md 将 global virtual store 列为"同仓库多检出(worktree / 多 Agent)"场景的优化手段。
三、pnpm v11 全局包:隔离式全局安装
pnpm add -g 在 v11 中被重新设计,核心目标是隔离:每个全局安装的包(或包组)拥有独立的安装目录、独立的 package.json、node_modules/ 和 lockfile,全局工具之间不再通过 peer/hoisting 冲突互相破坏。安装位置为 {pnpmHomeDir}/global/v11/{hash}/,并与全局虚拟存储共享底层存储。
命令语义对照
pnpm add -g typescript prettier # 空格分隔 = 各自独立的隔离安装
pnpm add -g eslint,prettier # 逗号分隔 = 同一个共享安装组
pnpm remove -g eslint # 只移除 eslint 所在的组
pnpm add -g --allow-build=esbuild esbuild # 预批准构建脚本
pnpm list -g # depth 0 时总是可用
pnpm bin -g # 全局 bin 目录 = $PNPM_HOME/bin
关键规则(原文档逐条给出,均为 v11 新行为):
pnpm install -g(不带参数)不受支持——请使用pnpm add -g <pkg>。- 二进制文件位于
$PNPM_HOME/bin(不是$PNPM_HOME本身)。升级 pnpm 后执行pnpm setup将其加入 PATH。 - 使用
pnpm add -g .将本地包的 bin 注册到全局(取代旧的pnpm link --global)。 pnpm list -g --depth=<n>(n>0)仅对单个安装组有效。
与 AIRI 仓库的关联
AIRI 仓库的根 package.json 中有 "nolyfill": "pnpm dlx nolyfill" 脚本——pnpm dlx 属于一次性执行命令,按原文档所述在 v11 中默认使用全局虚拟存储。此外 .agents/skills/pnpm/references/core-store.md 提到 pnpm store prune 会同时做存储与全局虚拟存储 links 的 GC。日常维护共享存储时可以结合使用。
四、落地要点清单
汇总原文档 Key Points 并结合仓库证据:
enableGlobalVirtualStore: true⇒ 所有node_modules变为指向同一个按哈希寻址的共享存储的符号链接;配置写入pnpm-workspace.yaml(camelCase 键)。注意 pnpm 的配置模型:pnpm 设置位于pnpm-workspace.yaml(及全局config.yaml),.npmrc只用于认证/registry 凭据,package.json的pnpm字段不再被读取(见 .agents/skills/pnpm/SKILL.md)。- 最佳场景:同一仓库的多个检出(git worktree、并行 Agent);CI 中自动禁用,不要指望它在 CI 中生效。
- 警惕 ESM 未声明依赖:
NODE_PATH对 ESM import 无效,用packageExtensions或@pnpm/plugin-esm-node-path修复。 - v11 全局安装:每包隔离;逗号列表共享组;bin 在
$PNPM_HOME/bin;pnpm install -g无参形式不支持。 - 适用前提:该特性面向 pnpm v11(AIRI 锁定
pnpm@11.24.0);信任边界内的可写共享存储必须用文件系统权限保护;首次安装仍需完整填充全局存储,收益体现在后续检出与后续版本命中。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00