DeepSeek Harness 拥有两套 CI 表面(GitHub Actions 负责 TypeScript monorepo 及其 Python SDK;GitLab CI 负责原生 Python wheel),外加一整套本地开发工具——lefthook git 钩子、oxlint、knip、jscpd,以及不变量/拼接链接卫生门禁。发布走基于 family 的版本号更新(release/dsh-* / release/vendor-*),并在打标签前把版本号提交进仓库。本页梳理整个工程化流水线。
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各自为对应目标构建打包的单 exe 运行时,然后验证:Python 冒烟(python scripts/smoke-python-runtime.py)、Linux 下通过 readelf 检查 glibc ≤ 2.28、经 Docker 镜像做 manylinux 冒烟、macOS 部署目标检查。publish-python用twine把四个.whl上传到项目的 Package Registry,并用“标签 vspackage.json版本”断言护住。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 与 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-native | 真实 Windows | check:ci:windows-complete |
serial-linux-selfhosted / serial-windows | self-hosted | 仅 push 的 standby 演练(为 failover 池提供热备证据) |
all-checks-passed | ubuntu-latest | if: always() 汇总裁决;任一所依赖任务非成功即失败 |
门禁脚本来自 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
abe560f81e release(dsh)
8c1e8d9890 build(release): publish the dsh family publicly
8a954b2eca release(dsh): 0.1.0-rc.3
60b04b6ef7 release(dsh): 0.1.0-rc.2
22ab3beac1 release(dsh): 0.1.0-rc.1
7bedce822f release(vendor)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(只做打包证明:整组发布集仍可打包),再由一个由 environment: npm-publish 门禁单独保护的 publish 任务,在从 dsh-v* 标签手动触发时上传字节。被拼接的框架族经单独的 release-vendor.yml 发布;Landlock 原生包经 native/landlock-run 发布。依赖编辑改变载荷时,lefthook 会重新生成 THIRD_PARTY_NOTICES.md。
开发工具
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)。
knip 未用代码检查(knip.json)
npm run knip(knip --treat-config-hints-as-errors)检测整个 workspace 中未用的依赖/文件/导出。vendor 与 python/sdk-runtime 被忽略;若干二进制(bwrap、pwsh、sandbox-exec,…)与依赖(@yarnpkg/cli-dist、lightningcss)被加入白名单。
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、knip、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。这些保证发布前 workspace 内部一致。
贡献流程
CONTRIBUTING.md 说明项目处于早期阶段,目前不接受外部 PR;贡献通过 GitHub Discussions、生态插件(经 dsh-plugin 主题)与社区内容发生。这是个刻意设置的关卡,把团队 PR 评审精力聚焦在内部,同时围绕 harness 培育生态。
工具
| 工具 | 版本(根 package.json devDependencies) |
|---|---|
| vitest | ^4.1.8 |
| oxlint | |
| oxlint-tsgolint | |
| knip | ^6.16.1 |
| jscpd | ^5.0.12 |
| lefthook | ^2.1.9 |
| tsx | ^4.22.4 |
| typescript | ^6.0.3 |
| publint | ^0.3.21 |
| tsdown | ^0.22.2 |