DeepSeek Harness 拥有两套 CI 表面(GitHub Actions 负责 TypeScript monorepo 及其 Python SDK;GitLab CI 负责原生 Python wheel),外加一整套本地开发工具——lefthook git 钩子、oxlint、jscpd,以及不变量/拼接链接卫生门禁。发布走基于 family 的版本号更新(release/dsh-* / release/vendor-*),并在打标签前把版本号提交进仓库——上游仓库没有 CHANGELOG,每次发布都是机械的版本号更新提交。本页梳理整个工程化流水线。
GitLab CI:Python 发布形态
.gitlab-ci.yml 仅针对 Python 发布标签(python-v<major>.<minor>.<patch>…)运行。两个阶段:build 与 publish。
sdk-wheel构建无密钥 SDK wheel。runtime-linux-x64、runtime-linux-arm64、runtime-macos-arm64、runtime-windows-x64各自为对应目标构建打包的单 exe 运行时,然后验证:Python 冒烟(python scripts/smoke-python-runtime.py)、Linux 下通过 readelf 检查 glibc ≤ 2.28、经 Docker 镜像做 manylinux 冒烟、macOS 部署目标检查;Windows 车道跑scripts/build-exe-for-python-sdk.ts --targets=node24-win-x64,并在 wheel venv 里对已安装 wheel 路径做冒烟。publish-python用twine把五个.whl上传到项目的 Package Registry,并用“标签 vspackage.json版本”断言以及find release -name '*.whl'计数检查护住。GitLab 不覆盖已有版本,因此每次发布都需要新的python-v<version>标签。
标签对版本断言是核心:test "$CI_COMMIT_TAG" = "python-v$DSH_VERSION" || exit 1。
GitHub Actions:PR 门禁
.github/workflows/ci.yml 是必跑的 PR 流水线。它在 runner 池与并发上相当讲究;关键车道(除注明外为 Node 24)如下:
| 任务 | 运行于 | 做什么 |
|---|---|---|
node-24 / static | Linux 企业池 | pnpm run check:ci:static |
node-24-coverage | Linux | pnpm run check:ci:coverage(穷尽覆盖率) |
node-24-consumers | Linux | pnpm run check:ci:consumers(快照、制品、基于 Playwright 的 web) |
node-compat(矩阵) | ubuntu-latest | Node 22.19、24.9 与 26:check:node-compat |
python-sdk | ubuntu-latest | 经 uv 的 Python 3.10 无密钥套件 |
python-runtime | 可复用构建 | 发布形态的 Linux x64 exe 构建 |
windows | ubuntu-latest | Wine:运行 scripts/wine-windows-gates.sh(Wine 下的 Windows Node) |
windows-build / windows-coverage | 真实 Windows | 拆分自原单块 windows-native 任务的两半(check:ci:windows-blocking;先 build 再 check:ci:coverage)——一个慢任务不再阻塞其余 |
windows-native-tests | 真实 Windows | Windows 专属的原生测试文件(pwsh loader、workflow worker、subprocess exit、sqlite 差分) |
windows-observational | 真实 Windows | check:ci:windows-observational,continue-on-error(不阻塞) |
all-checks-passed | ubuntu-latest | if: always() 汇总裁决;任一所依赖任务非成功即失败 |
原先仅 push 的串行 standby 演练(serial-linux-selfhosted / serial-windows)移出了 PR 裁决,进入新的 ci-master.yml(master push + 针对 larger-runner/consolidated-runner 基准的 workflow_dispatch);ci-master.yml 刻意不参与 PR 裁决,因为 needs 无法跨工作流文件。
门禁脚本来自 scripts/run-gates.ts。check:ci、check:ci:linux-primary、check:ci:static、check:ci:coverage、check:ci:snapshot、check:ci:artifacts、check:ci:consumers 与 check:ci:windows-* 都是对各自 run-gates.ts 编排的薄 npm-script 包装。环境旋钮约束并发:DSH_GATE_CONCURRENCY、DSH_COVERAGE_MAX_WORKERS、DSH_SNAPSHOT_MAX_CONCURRENCY、DSH_E2E_MAX_WORKERS、DSH_OXLINT_THREADS、DSH_PUBLINT_CONCURRENCY。
工作流 env 中写死的 CI 政策要点:DSH_TELEMETRY_DISABLED=1(CI 运行绝不向生产遥测端点上报)、fetch-depth(供归档门禁)、Web 门禁用 Playwright Chromium、prepare-ci-bubblewrap.sh 解除沙箱套件的 namespace 限制,以及经仓库变量 DSH_CI_FAILOVER_LINUX / DSH_CI_FAILOVER_WINDOWS 把任务改指到自有 self-hosted 池的 failover 机制。
发布流程(从 git 可见)
发布流程是版本化且仅标签:
$ git log --oneline --grep=release -15
99f6f02fec Merge pull request #2620 from deepseek-harness/release/dsh-0.1.0-rc.7
bb4ca698d6 release(dsh): 0.1.0-rc.7
887c4977db Merge pull request #2546 from deepseek-harness/fix/publish-deporder
d5be1d62c9 feat(release): count publish progress against the whole release set
0e50fa290c fix(release): state what the echo helper does, and drop two dead claims
7b973e27c8 feat(release): reject a module-scope load of an optional dependency
9fa0575ccc fix(release): print the publish order and the peer edges it drops
70eb76eaec fix(release): keep npm's own output in the publish log
47399764c5 fix(release): order publication by every installed dependency section
fb82698709 Merge pull request #2531 from deepseek-harness/release/dsh-0.1.0-rc.6
15148dbd9a release(dsh): 0.1.0-rc.6
47f943859b Merge pull request #2519 from deepseek-harness/feat/npm-public
abe560f81e release(dsh): 0.1.0-rc.5
8c1e8d9890 build(release): publish the dsh family publicly
124aa5f01a Merge pull request #2521 from deepseek-harness/release/dsh-0.1.0-rc.3scripts/release/ 实现它:
| 脚本 | 作用 |
|---|---|
bump.ts | 递增某 family 版本并提交(--family dsh 在成员与根上共享一个版本;--family vendor 每个包一行版本,但整族一起发布) |
verify.ts | 对照 workspace 状态核验发布版本 |
pack.ts | 构建并打包 tarball 到 dist/npm |
verify-packed-install.ts | 安装打包 tarball(外加 vendor 与 Landlock tarball)并证明它们能解析 |
publish.ts | 把打包好的确切字节上传到 npm |
.github/workflows/release.yml 工作流(连同被拼接/原生变体)在每个 PR/push 上运行 release:verify → build → release:pack → release:verify-packed-install(只做打包证明:整组发布集仍可打包)。发布是手动动作:dsh 族经 release-publish.yml 发布,被拼接框架经 release-vendor-publish.yml 发布——两者都只响应 workflow_dispatch,在触发时重新打包当前树,且设计上从 dsh-v*(相应为 vendor-*)标签显式运行。两者都不监听 pull_request/push,且都声明 contents: read——CI 从不写仓库。Landlock 原生包经自己的 native/landlock-run 工作流发布。依赖编辑改变载荷时,lefthook 会重新生成 THIRD_PARTY_NOTICES.md。没有 CHANGELOG:每次发布都是机械的版本号更新提交(release(dsh): … / release(vendor): …)。
开发工具
lefthook git 钩子(lefthook.yml)
postinstall 运行 node scripts/install-lefthook.mjs。本地钩子刻意保持快速检查点;完整矩阵由 CI 负责:
- pre-commit:stage 文件 lint(
tsx scripts/run-oxlint.ts --config .oxlintrc.staged.json)、*.i18n.yaml的翻译配对、归档 agent note 检查、空白符git diff --cached --check、vendor 清单守卫,以及第三方通知重新生成(重新生成并git add THIRD_PARTY_NOTICES.md)。 - pre-merge-commit:翻译配对 + 归档 note。
- pre-push:
pnpm run typecheck。
oxlint(run-oxlint.ts、.oxlintrc.json)
npm run lint = build:lib:host 然后 tsx scripts/run-oxlint.ts .(contracts-ready 变体在客户端契约构建后运行)。.oxlintrc.json 在顶层把 correctness 规则关掉,再按 override 范围重新启用严格的、多为类型感知的规则;它忽略 vendor/**、native/** 与 *.config.ts。钩子用的是更严的 --fix staged 变体(.oxlintrc.staged.json)。
jscpd 重复代码(jscpd.json)
npm run duplication 以 minTokens: 60、minLines: 6、mode: "mild" 运行 jscpd --config .jscpd.json packages scripts,并用 ignorePattern 处理显式的 /* jscpd:ignore-start */ … /* jscpd:ignore-end */ 块(不变量伴生包与导出中大量使用)。
hygiene 组合
pnpm run hygiene 串起深层门禁:rescope-vendor:check、publint、constraints、verify-dsh-package-licenses、verify-package-invariants、verify-built-package-invariants、verify-cordis-config、verify-node-next-types、verify-runtime-closure、verify-vendored-links。(knip 已在仓库层面移除——没有 knip.json、没有 knip 脚本、没有 CI 车道;未用代码检测不再属于门禁。)这些保证发布前 workspace 内部一致。
贡献流程
CONTRIBUTING.md 说明项目处于早期阶段,目前不接受外部 PR;贡献通过 GitHub Discussions、生态插件(经 dsh-plugin 主题)与社区内容发生。这是个刻意设置的关卡,把团队 PR 评审精力聚焦在内部,同时围绕 harness 培育生态。
工具
| 工具 | 版本(根 package.json devDependencies) |
|---|---|
| vitest | ^4.1.8 |
| oxlint | |
| oxlint-tsgolint | |
| jscpd | ^5.0.12 |
| lefthook | ^2.1.9 |
| tsx | ^4.22.4 |
| typescript | ^6.0.3 |
| publint | ^0.3.21 |
knip 刻意缺席:它已在仓库层面移除。 | tsdown | ^0.22.2 |