Files
deepseek-harness/.agents/notes/implemented/architecture/2026-07-30-package-manager-native-repository-cache.zh.md

5.5 KiB
Raw Blame History

Agent Note: 包管理器原生仓库缓存

Status: implemented

English | 中文

问题

独立运行的 Harness 应用不能依赖开发者自有的 SDK 工程来声明并安装仓库依赖。因此,加载配置中的 GitHub 仓库需要一道持久的获取、准备与缓存边界;但如果在 DSH 内实现 Git 传输、托管来源语法、包准备流程和内容存储,就会重复实现包管理器。若要求用户另行安装包管理器,则只需修改配置即可使用的功能还会依赖宿主环境的额外配置。

缓存还需要明确更新标识。若没有独立的刷新协议,可变分支名无法既永久缓存,又反映后续 commit。

决策

vendor 中的 @cordisjs/plugin-loader/repository 导出 RepositoryCache:一个不包含 DSH 插件格式知识、仅限 Node 使用的通用包辅助工具。把它保留在子路径上,可以避免 Loader 主入口的浏览器消费方在解析依赖时遍历到 Node 文件系统和子进程 import。调用方提供包管理器原生的来源 specifier 和缓存根目录。DSH 专属调用方负责规定可接受的来源语法、路径选择与缓存根目录位置;SDK 工程依赖工作流仍是另一条路径,由开发者工程选定的包管理器负责。

Loader 将 pnpm@11.7.0 作为固定版本的运行时依赖,并使用当前 Node 可执行文件调用该包的 JavaScript 入口。它绝不探测全局可执行文件,也不经 Corepack 调用。每次缓存未命中都会创建一个隔离工程,其中只有一个名为 repository 的依赖Git 与 GitHub 来源的解析和获取、pnpm 自身的内容寻址 store、依赖安装以及仓库依赖图中的生命周期脚本均由 pnpm 负责。

隔离工作区设置 dangerouslyAllowAllBuilds: true。用户配置的仓库及其依赖图都属于受信任的可执行代码DSH 读取任何已声明资产之前,生命周期脚本就可能运行。子进程会收到 Git 与 pnpm 所需的常规宿主进程状态,但会移除环境中名称形似凭据(KEYPASSWORDSECRETTOKEN)的变量。该机制不新增 OAuth、token 转发或私有仓库认证约定。

缓存项以精确 specifier 的 SHA-256 命名。同一进程内针对相同 specifier 的并发请求共享一项任务。安装在同级临时目录中进行;只有安装成功且存在包目录和标记时,系统才会把暂存目录原子重命名为最终键对应的目录。失败的暂存目录会被删除;如果另一进程已发布有效项,则以该项为准。后续进程会先校验标记与包目录,再返回稳定的 node_modules/repository 路径。

相同的 specifier 会永久复用已发布项。调用方通过修改 ref 或 specifier 的其他部分来请求新的缓存代次;缓存不会轮询远端、重新解释可变 ref、让条目过期也不会垃圾回收旧代次。

曾考虑的替代方案

直接实现 GitHub 下载、归档解压、准备与缓存。 根据依赖政策不予采纳pnpm 已负责托管 Git 语法、Git 执行、生命周期政策和共享内容存储。第二套解析器会增加更多代码,却仍需实现包语义。

要求 pnpm 位于 PATH 上,或调用 Corepack。 不予采纳:在每种受支持的安装形态中,只修改一份应用配置就必须足以启用该功能。固定并随应用分发 CLI命令行界面还能使准备政策可供评审并与宿主的包管理器版本无关。

每次启动都重新解析分支或 tag。 不予采纳:这会把启动变成网络刷新,在配置 diff 未变化时更改代码,并让回滚依赖远端状态。即使用户有意选择可变 ref显式修改 ref 仍能保持可审计性。

禁用仓库生命周期脚本。 不予采纳:常见插件仓库需要声明式 prepare 步骤来校验并打包插件子目录。信任边界是显式配置可执行来源,而不是营造一种不完整的假象,仿佛只有静态文件能够运行。

引入 Cordis 仓库服务。 不予采纳:缓存查找没有运行时贡献注册表,也不存在提供方变体。小型 helper 让后续宿主负责 Cordis 生命周期与 HMR热模块替换无需过早新增服务 seam。

后果

  • 独立应用随附 pnpm 约 18.6 MB 的解压后运行时,不要求全局工具,也无需自行实现 Git 与包处理。
  • 仓库作者可以使用常规包准备流程;恶意的已配置仓库或依赖可以在经过上述清理的子进程环境中,以用户的文件系统权限执行代码。
  • 精确 specifier 使首次安装成功后的启动具有确定性;更改缓存代码必须修改配置或 ref。
  • 安装失败不会留下已发布缓存项,可以再次重试。已发布缓存损坏时会明确报错,而不会在同一标识下静默重装。
  • 缓存代次会持续占用磁盘,直到未来有明确的缓存管理政策将其移除。

测试

packages/boot/app-boot/tests/repository-cache.spec.ts 覆盖同进程 single-flight、跨实例缓存复用、精确 specifier 隔离、失败暂存清理与重试,以及边界校验。其真实本地 Git 用例会调用随附的 pnpm运行 fixture测试前置数据仓库的 prepare 脚本,并在不访问网络的情况下,从已安装缓存项中读取准备后的文件。