149 lines
14 KiB
Markdown
149 lines
14 KiB
Markdown
---
|
||
id: toolchain-capability-pack
|
||
name: 项目工具链能力包
|
||
status: done
|
||
progress: 100
|
||
---
|
||
|
||
## 设计决策:项目工具链契约、解析与 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: done
|
||
- 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: 环境工具弹窗能看懂期望/实际版本、来源路径和准备结果。"
|
||
- done_note: "2026-09-22:运行态 MCP 对 Enterprise 返回 Node 24.19.0、pnpm 9.15.0 且均为 compliant_unmanaged,由此发现并修复 Windows `.cmd` wrapper 版本探测;pnpm typecheck 通过。用户截图完成 human_verify,并要求将模态框扩大到 92vw/max-w-5xl、88vh/max-h-900px,确认信息密度与滚动体验符合预期。复盘待炼境 MCP 在本会话可用后回填。"
|
||
|
||
### ✅ 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: done
|
||
- 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 阻塞。"
|
||
- done_note: "2026-09-22:PR #11 合并后,通过炼境 apply_onboarding_pack 为 Enterprise 写入最小 mise.toml、升级 AGENTS/skill/capability-packs,verify_onboarding 12/12;Windows 用户级安装 mise 2026.9.12 后,get_toolchain_status 为 ready_managed。消费者 CLI 实测 Node v24.19.0、pnpm 9.15.0、pnpm check:toolchain exit 0,package.json/pnpm-lock.yaml 零非预期改动;新 Codex 会话可直接通过 mise 使用项目版本,不再被 bundled pnpm 11 阻塞。Enterprise 主线经 PR #173–#175 收敛,合并提交 a2e85f50 的 Gitea main CI #529 中 agent 与 deploy-impact 成功,agent 在业务检查前完成 Node/pnpm 安装及工具链断言;纯蓝图变更未触发 API/Web 部署。"
|
||
|
||
### ✅ T8. 炼境自身工具链契约闭环
|
||
- status: done
|
||
- complexity: M
|
||
- files: .nvmrc, package.json, mise.toml, .blueprint/modules/toolchain-capability-pack.md, .blueprint/manifest.yaml
|
||
- acceptance: "agent_verify: [CLI] `mise exec -- node --version` → v24.19.0,`mise exec -- pnpm --version` → 9.15.0;[炼境能力本体] get_toolchain_status(dev-manager-tauri) → Node/pnpm 均为 ready_managed 且 executable 指向 mise 安装目录;[项目验证] `pnpm typecheck` 与 `cargo test --lib` 通过;[Git] `git diff -- pnpm-lock.yaml` → 空。"
|
||
- decision_note: "版本事实继续使用开放标准声明:`.nvmrc` 固定 Node,package.json#packageManager 固定 pnpm;mise.toml 仅启用 idiomatic version file 读取,不复制版本,也不新增 engines 第二事实来源。"
|
||
- done_note: "2026-09-22:炼境自身新增 `.nvmrc` 24.19.0、packageManager pnpm@9.15.0 与最小 mise resolver。CLI 命中 mise 安装目录,typecheck 通过、Rust 151/151;真实启动 Tauri 后经 MCP get_toolchain_status 验收,Node/pnpm 均为 ready_managed,pnpm-lock.yaml 零改动。"
|
||
- retrospective: "【复盘】炼境自身工具链契约闭环|任务类型: 架构调整|复杂度: M|实际轮数: 2轮(预估 1 轮)|是否返工: 否|有效策略: 先以开放标准声明建立唯一事实来源,再从真实 MCP 能力入口验证而非只检查文件|遗留风险: 沙箱内 mise 无法写用户级 trusted-configs,Agent 需在受控本机环境执行验证|auto_applied_rules: R02, R13|rule_effectiveness: R02=有效, R13=有效"
|
||
|
||
## 执行顺序
|
||
|
||
T1 → T2 → T3;T2 → T4 → T5;T3 + T4 → T6;T3 + T4 + T6 → T7 → T8。
|
||
|
||
核心能力先只读、后受控写;炼境实现者验证完成后,必须由 Enterprise System 以消费者角色完成最终闭环。
|