Files

146 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 开发流程(development)
dsh-web 是 DeepSeek Harness Web 的插件 monorepo(皮肤以「皮肤」插件的资产包形式存在)。本文定义
贡献者日常流程;仓库规则见根 [AGENTS.md](../AGENTS.md),包级规则见
[packages/AGENTS.md](../packages/AGENTS.md),文档标准见 [AGENTS.md](AGENTS.md)。
## 环境准备
- Node.js >= 22 与 pnpm 11;
- 依赖解析官方 NPM SDK(registry.npmjs.org)。仍使用私有 scope 认证时需
`NPM_TOKEN` 环境变量(真实令牌只放环境变量,勿提交);token 配置放
用户级 `~/.npmrc`,项目 `.npmrc` 只留 scope 映射(见
[plugins.md](plugins.md))。
## 分支模型
- `dev`:开发分支(集成分支),本地开发与远程 PR 的统一目标;提交 /
提 PR 前先 `git fetch origin && git rebase origin/dev` 同步上游最新代码。
- `main`:稳定分支,只接收从 `dev` 合入且测试通过的代码;`dev` 上
验证通过后由维护者合入 `main`(发布 tag 仍从 `main` 打)。
## 日常循环
```sh
pnpm install
pnpm build # 全仓构建
pnpm dev:watch # 监听重编浏览器产物(dsh web 宿主自动刷新 GUI)
pnpm typecheck # 全仓类型检查
pnpm test # 全仓单测
pnpm test:standards # 测试纪律门禁(BDD 结构 / 确定性时间 / 断言质量)
pnpm docs:check # 文档一致性(链接 / README / i18n 配对)
pnpm i18n:check # 双语与第三语言俄语键集一致性及 CJK 泄漏审计
pnpm emoji:check # 手写源码无表情符号审计
pnpm libs:check # 校验已提交 lib/ 产物与源码指纹一致性
pnpm coverage:check # 覆盖率棘轮(Tier 2,整仓约一分钟)
```
改动提交前至少跑 `pnpm typecheck && pnpm test && pnpm test:standards && pnpm docs:check && pnpm i18n:check`;涉及聚合包或市场时运行对应 `pnpm aggregate:check` / `pnpm market:check`;皮肤、宠物与社区插件索引的门禁在各自的独立仓运行;CI 会全量跑所有门禁。
## 测试与门禁
业务测试纪律是仓库契约,由 `scripts/test-standards.mjs` 机械执行,规则与理由写在脚本头部:`no-arbitrary-sleep`(确定性时间用 `vi.useFakeTimers()` 配 `advanceTimersByTime()` 或带超时的 `waitFor`,不写 `setTimeout` / `sleep` 等待)、`no-ad-hoc-mock`(不用 `vi.mock` / `vi.spyOn` 打补丁,注入假实现或用真实后端)、`bdd-title`(`it` / `test` 标题以被测角色开头,如 `user ...`)、`given-when-then`(测试体写明前置条件、动作与可观察结果)、`call-count-only-assertion`(只断言调用次数不构成验证)、`tautological-assertion`(`toBeDefined()` 之类只重申值存在)。
历史测试按「文件 → 规则 → 计数」记入 `scripts/test-standards-baseline.json`:新测试文件从零基线开始,全部规则即刻生效;已有文件的计数只允许下降,修正后运行 `pnpm test:standards:write` 收紧基线。确需例外时在违规行尾或文件头部注释块写 `test-standards-allow: <原因>`,与 `i18n-allow:` 同一约定。
仓库工具测试(`scripts/`)只受机械规则约束,业务行为测试(`packages/`、`tests/`)适用全部规则;纯算法单测放在前者,用户可见行为放在后者。
覆盖率棘轮由 `scripts/coverage-gate.mjs` 执行:逐包跑 `vitest --coverage`,把 lines / statements / functions / branches 记入 `scripts/coverage-baseline.json`,任一指标低于基线超过 0.5 个百分点即失败(插桩本身有约 0.04 个百分点的抖动,故留容差),提升后运行 `pnpm coverage:write` 收紧。仓库当前并存两代 vitest,覆盖率 provider 按代声明:3.x 包各自声明 `@vitest/coverage-v8@^3.2.7`,4.x 包由根 devDependency 经 Node 解析提供;升级某包 vitest 主版本必须同步升级其 provider,否则门禁直接报错而不是静默跳过。基线必须在 CI 侧也成立:包内有条件运行的测试(如 harness 安装可用才跑的 benchmark 用例)会让本机覆盖率高于 Linux runner,两侧不一致时按 CI 的较低值记录。
门禁分两层:`ci.yml` 是 PR 门禁,一次跑完全部检查;`nightly.yml` 是 Tier 2,每晚补充 PR 单趟看不到的证据——覆盖率棘轮与全量测试三连跑(flake 检测)。
测试环境里的 storage 由 `shared/vitest.setup.ts` 统一修好(Node 25 在全局定义了 `localStorage`,那个残桩会存活到 DOM 测试里,机理见该文件头部);包自带的 vitest setup 必须接上它——用 `shared/vitest.config.ts`、import `shared/vitest.setup.ts`,或加进 `scripts/sync-shared.mjs` 的副本清单——否则该包在 Node 25 上跑的是降级路径,覆盖率随之偏低。
失败路径审计是业务特性的交付要求,以下分支必须各有测试,或在交付说明中写明其不可达:并发与幂等(重复提交、竞态、锁过期)、资源耗尽(余额不足、缺货、限流)、基础设施故障(死锁重试、事务回滚、连接中断)、第三方故障(假实现返回 500、网关超时、熔断降级)、校验与安全(越权租户、签名篡改、非法状态流转)。
## 常见任务
### 审核远程 PR
维护者可用 `node scripts/pr-review.mjs` 本地批量审核外部 PR(一次多个,
如 `--open` 审核全部 open PR):先做静态硬性检查(规模上限新增/删除各
1 万行直接拒绝、禁止提交依赖缓存与密钥、emoji 扫描、PR 模板必填项、
密钥扫描、CI 文件保护),再在工作区 worktree 上按 CI 门禁序列构建验证
(序列与 `.github/workflows/ci.yml` 一致)。worktree 建在 `~/remote-e2e/pr-<N>`
(同 head 复用,跑完保留便于排查),定期用 `pnpm pr:review --cleanup` 或手动
`rm -rf ~/remote-e2e` 清理。
外部 PR 的模板硬检查含「测试证据与上游同步」与「视觉修复要求」:贡献者
必须提供自己本地测试的证据,并附上同步上游最新 `dev` 分支后重新测试
通过的证据;文本类改动可不附截图,视觉修复 / 用户可见变更必须附截图,
且视觉修复必须使用支持图像输入的多模态模型完成(纯文本模型如
deepseek-chat / deepseek-reasoner / gpt-3.5 直接拒绝)。缺失即 REJECT;
`.github/workflows/pr-contribution-rules.yml` 在 CI 侧同步拦截(评论 + 挂红)。
皮肤、宠物与社区插件索引的 PR 投到各自的独立仓(
`.github/workflows/reject-non-content-pr.yml` 会关闭投错仓库的 PR),
相应检查由那些仓库自己的 CI 跑;本仓的硬检查与视觉修复要求只针对本仓接收的改动。
用法与 verdict 语义见脚本头部注释;`pnpm pr:review --help` 查看全部选项。
### 修改 shared 运行时模块
shared/ 是 settings 卡片、轮询护栏、DSH_HOME 解析等跨包模块的唯一事实源;各包内的
同名文件是 scripts/sync-shared.mjs 生成的同步副本。改 shared 源后运行
node scripts/sync-shared.mjs 并把副本一并提交;pnpm test:scripts 的 drift 门禁防止副本漂移。
### 新增插件包
```sh
node scripts/dsh-plugin-new <name> # 生成 packages/<name>/ 骨架
```
然后按 [plugins.md](plugins.md) 把包注册进聚合包(aggregate.yml 的
`patchFrom` 与 `deps`),跑 `node scripts/aggregate.mjs` 重新生成聚合包。
新包必须自带 README 三件套(`README.md` + `README.zh.md` +
`README.i18n.yaml`)与测试。
### 新增皮肤
皮肤与宠物的骨架、契约校验在各自的独立仓(dsh-skins / dsh-pet)内运行;本仓库消费
它们发布的 npm 包,市场内容取自 dsh-skins 子模块(钉版见
[market-inputs.lock.json](../market-inputs.lock.json))。预览图由 `scripts/capture-previews`
直接写进该子模块的工作树:
```sh
node scripts/capture-previews <id> # 重拍 satellites/dsh-skins/skins/<id>/preview/{light,dark}.jpg
pnpm market:fetch # 子模块 gitlink 指向新提交后,缓存输入过期并重新物化
pnpm market:build # 刷新市场产物(market/dist)
node scripts/skins-montage.mjs # 重排根 README 皮肤一览图(docs/images/skins-montage.png)
```
预览图随皮肤源码提交在 dsh-skins 仓,本仓随后提交该子模块的新钉版与 `market/dist`,`pnpm market:check` 校验两者一致。要在提交进 dsh-skins 之前先看市场效果,用 `pnpm market:fetch --local --force` 读子模块工作树;由未 pin 内容生成的 `market/dist` 不得提交。
皮肤启用互斥由 dsh-skins 仓的 `dsh-skin use` 管理(客户端原子切换,不改
cordis.patch.yml);skin-center npm 包只随附 `blue-fantasy`,其余皮肤由用户经
Workshop 按需安装到 `$DSH_HOME/skins/<id>/`。
### 本地验证(挂载进 dsh web)
```sh
node scripts/link-profile.mjs # 把全家桶链接进 web profile
dsh plugin --profile web add link:<仓库绝对路径>/packages/dsh-web-all
dsh web # 重启后侧边栏出现插件入口
```
## 发布
发布流程见 [publish-prep.md](publish-prep.md) 与 .github/workflows/
release.yml:推送 vX.Y.Z tag 触发发布,tag 是版本唯一来源,
`scripts/verify-version.mjs` 在发布前校验每个包版本与 tag 一致。
### 多代理并行开发资源纪律
多子代理并发工作流(如 wave 批量实施、并行 worktree 开发)与本机 DSH Web GUI 共享同一台机器的 CPU 与内存。具体并发硬上限、worktree 管理与防卡顿规则见 [multi-agent-resources.md](multi-agent-resources.md)。
## 架构与跨包指引
- 架构总览与全景图见 [architecture.md](architecture.md);
- 新插件脚手架与入桶流程见 [plugins.md](plugins.md);
- 匿名安装遥测机制见 [telemetry.md](telemetry.md);
- 双语文档配对契约见 [i18n.md](i18n.md)。
## 文档纪律
- 任何改动触及 README / AGENTS.md / docs/ 描述的行为时,同 PR 更新文档;
- 改包 README 任一侧后,同步另一侧并 `pnpm docs:write-pair <包名>`;
- 一次性记录(任务交接、验证快照)放 `docs/archive/`,不进长期文档目录。