Skip to content

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,并用“标签 vs package.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 / staticLinux 企业池pnpm run check:ci:static
node-24-coverageLinuxpnpm run check:ci:coverage(穷尽覆盖率)
node-24-consumersLinuxpnpm run check:ci:consumers(快照、制品、基于 Playwright 的 web)
node-compat(矩阵)ubuntu-latestNode 22.19、24.9 与 26:check:node-compat
python-sdkubuntu-latest经 uv 的 Python 3.10 无密钥套件
python-runtime可复用构建发布形态的 Linux x64 exe 构建
windowsubuntu-latestWine:运行 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真实 WindowsWindows 专属的原生测试文件(pwsh loader、workflow worker、subprocess exit、sqlite 差分)
windows-observational真实 Windowscheck:ci:windows-observational,continue-on-error(不阻塞)
all-checks-passedubuntu-latestif: 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 可见) ​

发布流程是版本化且仅标签:

bash
$ 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.3

scripts/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 |

延伸阅读 ​

  • 测试策略— 每个 check:ci:* 门禁实际跑什么。
  • 运行时不变量— verify-package-invariants 门禁与伴生包。
  • 拼接库— verify-vendored-links、rescope-vendor 与 family 发布。
  • .gitlab-ci.yml— Python wheel 流水线及其标签守卫。
  • scripts/run-gates.ts 与 scripts/release/bump.ts— 门禁编排与 family 版本化。
  • lefthook.yml— 具体的 pre-commit/pre-push 任务及其 glob。