--- id: toolchain-capability-pack name: 项目工具链能力包 status: in_progress progress: 71 --- ## 设计决策:项目工具链契约、解析与 Agent 执行闭环 v1 ### 背景 炼境现有 `project-env-scan` 能识别 `.nvmrc`、`.node-version`、Volta 与 lockfile,`devtools-scan` 能读取本机 Node、pnpm 等实际工具,但两者仍是信息展示:项目声明与当前执行环境没有形成可比较、可准备、可复现的闭环。 Enterprise System 已精确声明 Node `24.19.0` 与 pnpm `9.15.0`,而 Codex bundled runtime 暴露 pnpm `11.19.0` 且无 Corepack。现有 `check:toolchain` 能正确拦截漂移,却缺少自动选择项目版本的 resolver,导致 Agent 每次会话重复阻塞。 ### 方案选择 | 方案 | 取舍 | 结论 | | --- | --- | --- | | 所有项目追随 Codex bundled runtime | 初次零配置,但 Codex 升级会反向驱动项目漂移,且无法覆盖其他 IDE/CI | 否决 | | 仅 `.nvmrc` + Corepack | 声明简单,但依赖人工切换;Corepack 不保证随 Node/Codex 提供 | 仅兼容 | | 全量 Dev Container / Docker 开发 | 复现性强,但对 Windows/Tauri/前端热更新和本地磁盘成本过重 | 特殊项目可选 | | **标准项目声明 + mise resolver + 炼境能力包** | 项目继续拥有版本事实;人、Codex、CI、部署通过各自 adapter 消费同一契约 | **选定** | ### 统一模型与边界 ```text 项目版本事实 ├─ .nvmrc Node 精确版本 ├─ package.json#packageManager pnpm 精确版本 ├─ package.json#engines 兼容性/门禁 └─ pnpm-lock.yaml 依赖图(不承担工具版本切换) │ ▼ 工具链 adapter ├─ 本机 / Codex:mise ├─ Gitea CI:从同一声明安装对应 Node/pnpm └─ production:镜像或构建产物固定版本 │ ▼ 炼境:实时诊断、受控准备、自检报告、UI/MCP 双投影 ``` - 不新增 `.lian-jing/toolchain.*` 版本配置,避免第二事实来源。 - v1 只治理 Node + pnpm;Rust 继续由 `rust-toolchain.toml`/rustup 管理,其他语言后续按真实需求增加 adapter。 - 2026-09-22 用户确认炼境执行面只支持 Windows 项目路径;WSL 不再进入能力包、诊断、准备或消费者验收范围。 - 实际版本与可执行路径实时读取,不写入 SQLite 作为权威状态;既有 `project_env_tools` 仅保留展示/快照用途。 - `mise.toml` 只启用 `.nvmrc` 与 `packageManager` 的 idiomatic version file 读取,不重复抄写版本。 - 缺少 mise 但实际版本匹配时报告 `compliant_unmanaged`,不能伪报成可复现的 `ready_managed`。 - 安装/下载/信任属于机器状态变更:只允许已登记项目、规范化根路径和显式确认;不得自动信任未知仓库,不执行项目自定义 task/hook,不修改 package/lock 文件。 - 炼境提供能力与证据,不替项目决定升级版本;升级必须单独走 PR。 ### 系统边界变更 - 新增纯解析层,统一提取项目 Node/pnpm 声明、来源、冲突和 resolver 配置。 - 新增只读 Tauri command 与 MCP tool `get_toolchain_status(project_id)`,报告 declared/actual/executable/source/status/recommendation。 - 新增受控 Tauri/MCP 能力 `prepare_toolchain(project_id, confirmed)`,只构造并执行受限的 `mise install` 路径。 - 项目环境 UI 增加工具链契约卡和准备入口,与 agent 调用复用同一业务函数。 - onboarding/能力包增加版本化自检和条件式 Agent 指引:存在 resolver 时通过 `mise exec -- pnpm ...` 执行。 - 不新增数据库表,不改变部署协议,不自动迁移项目版本。 ### 验证路径 - 载体:Tauri command / MCP tool / CLI 消费者验证。 - 示例:`[Tauri command] get_toolchain_status(enterprise_project_id) → declared Node=24.19.0、pnpm=9.15.0,actual pnpm=11.19.0 时 status=mismatch 且返回实际 executable path。` - 示例:`[Tauri command] prepare_toolchain(enterprise_project_id, confirmed=true) → 仅调用受限 mise install,不修改 package.json/pnpm-lock.yaml;再次诊断为 ready_managed。` - 示例:`[CLI] mise exec -- pnpm check:toolchain → Node 24.19.0、pnpm 9.15.0,exit 0。` ### 风险点 - **未知仓库执行配置**:prepare 前校验项目登记、规范化根路径与显式确认;v1 不运行 mise task/hook。 - **Windows PATH/shim 差异**:状态必须同时返回版本与 executable path;测试覆盖 `.cmd` 解析和 Codex fallback 路径。WSL 明确不支持,不增加双路径兼容分支。 - **多份版本声明冲突**:解析器返回 conflict 并拒绝 prepare,不擅自选择其中一份。 - **下载与磁盘占用**:mise 使用用户级缓存、相同版本跨项目复用;UI 在下载前展示预计动作。 - **CI 与本地 adapter 不同**:要求共享同一声明并在 CI 首步执行版本断言,不要求 CI 为形式统一而安装 mise。 - **范围膨胀**:v1 不接管依赖安装、数据库、服务启动和部署,只解决运行时/包管理器选择。 ## 任务卡 ### ✅ T1. Node/pnpm 工具链契约解析器 - status: done - complexity: M - files: src-tauri/src/commands/toolchain.rs, src-tauri/src/commands/mod.rs - acceptance: "[cargo test] 临时目录分别提供 `.nvmrc`、`.node-version`、package.json#packageManager/engines 与 mise.toml → 返回 Node/pnpm declared version、source 和 resolver 配置;冲突声明返回 conflict,缺失字段返回 missing,不读取或修改 lockfile。" - done_note: "2026-09-22:新增纯解析器与 6 个测试,覆盖一致声明、精确冲突、engines 仅作兼容门禁、mise 直 pin、空项目;首次测试暴露 pnpm 来源优先级,已修正为 packageManager 优先。复盘待炼境 MCP 在本会话可用后回填。" ### ✅ T2. 只读工具链状态 Tauri command - status: done - complexity: M - depends: T1. Node/pnpm 工具链契约解析器 - files: src-tauri/src/commands/toolchain.rs, src-tauri/src/lib.rs, src/lib/commands.ts - acceptance: "[Tauri command] get_toolchain_status(project_id) → 返回 declared/actual/executable/source/resolver/status/recommendation;项目不存在或路径越界时显式报错;实际版本匹配但无 resolver 时为 compliant_unmanaged,版本不符时为 mismatch。" - done_note: "2026-09-22:新增依赖注入业务函数与薄 Tauri command,只接受已登记项目的 Windows 路径,同时解析 executable path 和版本输出;运行态 MCP 自检发现 `where pnpm` 优先返回无扩展 shim 且 cmd 引号不稳,已改为优先 `.exe/.cmd/.bat` 并分别使用直接执行或 `cmd /D /S /C`。WSL 按用户决策明确不支持。复盘待炼境 MCP 在本会话可用后回填。" ### ✅ T3. MCP 只读诊断投影与契约文档 - status: done - complexity: M - depends: T2. 只读工具链状态 Tauri command - files: src-tauri/src/mcp_tools.rs, src-tauri/src/commands/toolchain.rs, docs/ai-context/project-context.yaml - acceptance: "[MCP tool] get_toolchain_status(project_id) → 与 Tauri command 返回同一状态模型;mise/Codex/Gitea 不可用时返回 unavailable/missing 证据而非伪造 ready;cargo test 覆盖 schema、dispatch 和降级路径。" - done_note: "2026-09-22:新增 get_toolchain_status MCP schema/dispatch、必填参数降级测试并同步外部契约映射;定向测试全绿。复盘待炼境 MCP 在本会话可用后回填。" ### ✅ T4. 受控 mise 工具链准备能力 - status: done - complexity: M - depends: T2. 只读工具链状态 Tauri command - files: src-tauri/src/commands/toolchain.rs, src-tauri/src/mcp_tools.rs, src-tauri/src/lib.rs, src/lib/commands.ts - acceptance: "[Tauri command] prepare_toolchain(project_id, confirmed) → confirmed=false、未知项目、根路径越界或 contract=conflict 时零执行;confirmed=true 时只执行参数化 `mise install`,不运行项目 task/hook,不修改 package.json/pnpm-lock.yaml,并返回 before/after 状态与命令证据。" - done_note: "2026-09-22:新增 Tauri/MCP 受控 prepare_toolchain;resolver 就绪后通过 mise exec 探测项目版本,拒绝未确认、冲突、缺版本、缺 mise 和含自定义 task/hook/plugin 的配置;返回 verified 区分命令成功与二次诊断 ready_managed,定向测试全绿,未实际下载安装。复盘待炼境 MCP 在本会话可用后回填。" ### 🔴 T5. 项目环境 UI 工具链契约卡 - status: blocked - complexity: M - depends: T2. 只读工具链状态 Tauri command, T4. 受控 mise 工具链准备能力 - files: src/components/dashboard/ProjectEnvModal.tsx, src/lib/commands.ts - acceptance: "agent_verify: [pnpm typecheck] ProjectEnvModal 消费 ToolchainStatus 类型且无类型错误;[Tauri command mock/fixture] ready_managed、compliant_unmanaged、mismatch、conflict 分别渲染准确状态与可用动作,prepare 必须经过确认;human_verify: 环境工具弹窗能看懂期望/实际版本、来源路径和准备结果。" - blocked_reason: "代码接线与 pnpm typecheck 已通过;隔离分支已启动,运行态 MCP 对 Enterprise 返回 Node 24.19.0、pnpm 9.15.0 且均为 compliant_unmanaged,并由此发现并修复 Windows `.cmd` wrapper 版本探测;当前 Computer Use 未暴露 Tauri 原生窗口,本项目也不为 React 组件临时引入测试框架,仍缺 human_verify。需在环境工具弹窗终验状态卡与确认按钮。" ### ✅ T6. Onboarding 与 Codex Skill 条件式工具链指引 - status: done - complexity: M - depends: T3. MCP 只读诊断投影与契约文档, T4. 受控 mise 工具链准备能力 - files: src-tauri/src/commands/onboarding.rs, src-tauri/resources/onboarding/AGENTS.md.tmpl, src-tauri/resources/onboarding/mise.toml.tmpl, src-tauri/resources/onboarding/lefthook.yml.tmpl, src-tauri/resources/onboarding/.lian-jing/capability-packs.json, src-tauri/resources/onboarding/.agents/skills/lian-jing/SKILL.md, plugins/lian-jing-codex/skills/lian-jing/SKILL.md, lefthook.yml - acceptance: "[cargo test] 对已有手写 mise.toml 的项目重跑 onboarding → 不覆盖文件并报告 existing/conflict;对明确选择接入且仅有 `.nvmrc` + packageManager 的临时项目 → 生成不重复版本的 resolver 配置;[Codex Skill] setup 先调用 get_toolchain_status,managed 项目使用 `mise exec -- pnpm`,unavailable 时明确降级而不宣称已准备。" - done_note: "2026-09-22:接入包新增条件式最小 mise resolver、toolchain-node-pnpm v1.0.0 描述符、AGENTS v1.9.0 与两层 Codex Skill 指引;已有 mise.toml 永不覆盖;commit-msg 改用 Lefthook `{1}` 参数兼容 managed worktree;16 个 onboarding 测试全绿。复盘待炼境 MCP 在本会话可用后回填。" ### 🔴 T7. Enterprise System 消费者试点与 CI 同源验证 - status: blocked - complexity: M - depends: T3. MCP 只读诊断投影与契约文档, T4. 受控 mise 工具链准备能力, T6. Onboarding 与 Codex Skill 条件式工具链指引 - files: E:/code-project/enterprise-system/mise.toml, E:/code-project/enterprise-system/AGENTS.md, E:/code-project/enterprise-system/.gitea/workflows/ci.yml - acceptance: "agent_verify: [CLI] `mise exec -- node --version` → v24.19.0,`mise exec -- pnpm --version` → 9.15.0,`mise exec -- pnpm check:toolchain` → exit 0;[Gitea CI] 从 `.nvmrc` 与 packageManager 安装精确版本并在业务检查前通过 check:toolchain;package.json 与 pnpm-lock.yaml 无非预期改动;human_verify: 新 Codex 会话进入 Enterprise 后不再因 bundled pnpm 11 阻塞。" - blocked_reason: "运行态只读试点已确认 Enterprise 的 Node 24.19.0、pnpm 9.15.0 声明与本机版本匹配,但 resolver=unavailable,因此仍不是跨 Agent 可复现的 ready_managed。写入试点依赖本分支先完成审查、合并并重建炼境;Enterprise 当前另一个会话还有未提交 T3 migration/蓝图改动,现阶段不跨项目写入或混合验证。" ## 执行顺序 T1 → T2 → T3;T2 → T4 → T5;T3 + T4 → T6;T3 + T4 + T6 → T7。 核心能力先只读、后受控写;炼境实现者验证完成后,必须由 Enterprise System 以消费者角色完成最终闭环。