# Contributing to AI Harness Launcher
> 欢迎!**AI Harness Launcher** 是一个用 Tauri 2 + Rust 构建的「PCL for AI Harnesses」Windows 桌面启动器:管理 DSH 运行时、多实例、Provider、插件,然后一键 Launch。
>
> 动手前请先读 [`README.md`](./README.md)(怎么跑)和本文件(分支、提交、测试与评审约定)。这份文档约 5 分钟,能帮你少走 90% 的弯路。
## 目录
- [技术栈与仓库结构](#技术栈与仓库结构)
- [环境准备](#环境准备)
- [常用命令](#常用命令)
- [分支规范](#分支规范)
- [提交信息规范](#提交信息规范)
- [提 PR 流程](#提-pr-流程)
- [代码规范](#代码规范)
- [测试要求](#测试要求)
- [评审与合并](#评审与合并)
- [Issue 规范](#issue-规范)
## 技术栈与仓库结构
pnpm workspace + Cargo workspace 的 monorepo:
```text
apps/desktop/ Tauri 2 应用
├── src/ React 19 + TypeScript 前端(Vite + Tailwind v4 + Zustand)
└── src-tauri/ Rust 壳:commands/、state/、tauri.conf.json
crates/
├── launcher-core/ 核心库(无 Tauri 依赖,可单测):
│ paths / settings / instance / provider / process / runtime / history / market
└── dsh-adapter/ DSH 专属适配器(实现 RuntimeAdapter):
runtimes / theme / diagnostics
scripts/ 开发辅助脚本(如 gen-icon.mjs)
```
### 语言边界(红线)
项目刻意把「边界」定死:
- **TypeScript 只管 UI**:页面、表单、状态、展示。
- **Rust 只管系统**:进程、文件系统、网络、密钥、SQLite、运行时管理。
两条禁令:
1. 不要在 TS 里 `exec()` / 写文件 / 发进程——系统操作一律走 Rust command 经 typed IPC。
2. 不要在 Rust 里管 UI 状态——状态放 Zustand,Rust 只返回数据。
IPC 类型(`lib/ipc.ts` ↔ `commands/`)是唯一的跨语言契约,改一侧必须同步另一侧。
## 环境准备
| 依赖 | 版本 | 说明 |
| --- | --- | --- |
| Node.js | ≥ 22 | 开发工具链;运行时用的 Node 已捆绑进安装包 |
| pnpm | ≥ 10(仓库锁定 `pnpm@11.18.0`) | `corepack enable` 后自动用锁定版本 |
| Rust | MSVC toolchain(`stable-x86_64-pc-windows-msvc`) | 用 `rustup` 安装 |
| WebView2 | 系统自带(Win 11) | Tauri 运行时 |
```bash
pnpm install # 安装前端依赖(esbuild postinstall 已在 pnpm-workspace.yaml 批准)
cargo build --workspace
```
## 常用命令
| 命令 | 作用 |
| --- | --- |
| `pnpm install` | 安装前端依赖 |
| `pnpm dev` | 启动 Tauri 开发窗口(根目录,委派到 apps/desktop) |
| `pnpm dev:web` | 只起 Vite,不挂 Tauri 壳(调试前端) |
| `cargo check --workspace` | Rust 快速编译检查 |
| `cargo test --workspace` | 全部 Rust 单测 + 集成测试 |
| `cargo clippy --all-targets -- -D warnings` | Rust 静态检查(**必须零告警**) |
| `npx tsc --noEmit` | 前端类型检查(在 `apps/desktop/` 下执行) |
| `pnpm build` | 打 NSIS 安装包(tauri build --release) |
> ⚠️ 根目录**没有** `tauri` script——用 `pnpm dev` / `pnpm build`,不要敲 `pnpm tauri dev`。
## 分支规范
- **`main`**:唯一长期分支,始终保持可发布。**禁止直接 push**,只接受合并后的 PR。
- **功能分支**:`feature/-`,如 `feature/market-reconcile`、`feature/portable-mode`。
- **修复分支**:`fix/`,如 `fix/process-tree-zombie`。
- **实验分支**:`experiment/`(不进入 PR,验证后即删)。
- 每次从最新的 `main` 拉分支;提交 PR 前先
```bash
git fetch origin && git rebase origin/main
```
保持历史线性,减少冲突。
- 绝不提交 `target/`、`node_modules/`、`*.log`、`*.pids`、密钥/证书(已在 `.gitignore`)。
## 提交信息规范
采用 [Conventional Commits](https://www.conventionalcommits.org/),一条提交只做一件事:
```text
():
<为什么这么改 / 注意事项>
```
- **type**:`feat` `fix` `refactor` `test` `docs` `chore` `ci` `perf`
- **scope**:`launcher-core` `dsh-adapter` `desktop` `ui` `market` `ci` `docs`
- **subject**:祈使句、首字母小写、≤ 72 字符,不带句号
示例:
```text
feat(dsh-adapter): 解析链增加 bundled node 回退
fix(launcher-core): 作业对象挂载失败时降级 taskkill /T
test(launcher-core): 进程树 10 轮 teardown 集成测试
ci: 新增 release 流水线四道 gate
```
关联 issue:PR 标题或提交里写 `Closes #123` / `Refs #123`(合并时自动关 issue)。
## 提 PR 流程
1. **先开 issue,再动手**(大改动先出方案)。小修复/文档可直接 PR。
2. 从 `main` 拉分支(见[分支规范](#分支规范))。
3. 本地全绿后再提交:
```bash
cargo test --workspace && cargo clippy --all-targets -- -D warnings && npx tsc --noEmit
```
4. push 后提 PR,用模板填清楚:
- **为什么**:关联 issue、要解决的问题
- **改了什么**:涉及的文件/模块、设计取舍
- **怎么测**:跑过的命令与结果;真机行为(如 Launch→窗口→Stop)附输出/截图
5. 打 `draft` 直到能通过全部 CI gate(`.github/workflows/ci.yml` 会在 PR 上自动跑)。
6. 至少 1 人 review 通过 + CI 全绿才可合并。
## 代码规范
### Rust
- 必须 `cargo fmt` + `cargo clippy --all-targets -- -D warnings` **零告警**。
- 依赖收敛到根 `Cargo.toml` 的 `[workspace.dependencies]`,crate 里用 `xxx.workspace = true`,版本只改一处。
- 错误用 `anyhow::Result`;库路径**不允许 `unwrap()`/`expect()`**;系统调用错误保留上下文(`with_context`)。
- 日志用 `tracing`(`debug/info/warn/error` + 结构化字段),不用 `println!`。
- Windows 专属逻辑用 `#[cfg(windows)]`,并为非 Windows 提供**行为一致的桩函数**(如 `sweep_leftover` 返回 0),保持 `cargo check` 跨平台可过。
- 进程、文件、密钥等核心路径**必须带测试**(见[测试要求](#测试要求))。
### TypeScript
- `npx tsc --noEmit` 零错误(严格模式)。
- 组件只负责渲染;状态放 Zustand store;IPC 统一封装在 `lib/ipc.ts`,类型与 Rust command 一一对应。
- 样式用 Tailwind 类,不用内联 `style`;主题色走 CSS 变量(`--color-*`),不写死 hex。
## 测试要求
- 改了 `crates/*`,**必须** `cargo test --workspace` 全绿。
- 核心链路(进程 teardown、运行时安装、市场开关)至少补一个集成测试,守护「Launch → 窗口 → Stop」这条主线。
- 依赖真机环境的测试用 `#[ignore = "..."]` 并在注释里写明前置条件(如 P0 managed runtime),单独跑:
```bash
cargo test -p dsh-adapter --lib -- --ignored real_dsh_stop_start_10_rounds_no_scars
```
- 前端改动至少过 `npx tsc --noEmit`;store 逻辑改动尽量补单测。
- 测试要能稳定复现——「真机跑一次通过」不算,CI 能绿才算。
## 评审与合并
- Reviewer 重点看:正确性、错误处理与边界、测试覆盖、是否越界到别的 crate / 层。
- 阻塞项(会崩、会丢数据、会泄漏进程/文件)必须修完才能合并;风格小问题不阻塞。
- 合并用 **squash**,保持 `main` 线性;PR 标题即最终提交信息,写清 `Closes #NNN`。
## Issue 规范
- 用模板:**现象 / 期望 / 环境**;bug 附日志(`%LOCALAPPDATA%/AIHarnessLauncher/logs/launcher.log`)与复现步骤。
- 一个 issue 一件事;用标签 `bug` `enhancement` `ci` `docs` `p2`–`p6`。
- 完成后在对应 PR 里写清 `Closes #NNN`,合并时自动关 issue。