Files
deepseek-harness/docs/development.zh.md
Tianyi Cui 53283003e9 feat(i18n): unit-mapped briefings with mechanical --apply, adopting the #684 planner mechanics
The briefing now maps each update at the narrowest safely aligned
granularity, widening deterministically on mapping failure: a change
confined to the pair's byte-identical code fences is computed outright
(--apply splices it into the counterpart and validates the result
against the pairing gate's structural signature before writing);
otherwise changed Markdown units — headings, paragraphs, table rows,
list items, fences, block quotes, HTML blocks, thematic breaks, link
definitions, matched by container-scoped kind sequences — each carry
their last-confirmed source, current source, and current counterpart
text; units that do not align fall back to depth-matched heading
sections (depth only, so translated heading text still maps); and when
sections do not align either, or both sides drifted, the briefing says
so and withholds the mapping. Terminology rows now match the changed
spans only, English terms on word boundaries with plural inflections,
and Chinese-target briefings track each relevant term's document-wide
first occurrence — a moved occurrence pulls the vacated and receiving
spans into the briefing with an explanatory note.

The unit mapping, mechanical code splice, and first-occurrence tracking
adopt the planner design from the incremental prompt-pipeline PR (#684),
whose provider-backed bake-off independently validated the same scope
ladder; this PR carries those mechanics into the agent-facing briefing
path so both consumers of the consistency records behave alike. The
prior line-hunk section mapping and its heading-text alignment (which
could not map cross-language sections) are replaced wholesale.

Docs: SKILL.md update path, i18n README pair, development.md pair, and
the briefed-updates Agent Note pair brought along; the development.md
fence edit was applied with --apply itself, and the prose updates were
made through the new unit/section briefings.
2026-07-27 02:31:07 +08:00

12 KiB
Raw Blame History

开发指南

English | 中文

本指南覆盖参与 DeepSeek Harness 开发所需的本地环境搭建、日常工作流与 CI 流程;设计动机与技术权衡请查阅相应 Agent Note。

前置条件

  • Node.js 支持 22.19+ 与 24+。CI 覆盖 22.19、24 和 26Node 引擎下限 Agent Note
  • 启用了 Corepack 的 pnpm。仓库在 package.json 中固定使用 pnpm@11.7.0;如果 pnpm --version 无法通过 Corepack 解析,请先运行 corepack enable
  • Git。
  • 可选:一个 DeepSeek API key用于 TUI、headless 和 ACPAgent Client Protocol自动化 agent智能体演示以及真实 API 的 e2e 测试。

首次搭建

在仓库根目录安装依赖:

pnpm install

安装过程同时会运行根目录的 postinstall 脚本,该脚本通过 scripts/install-lefthook.mjs 从仓库 dev 依赖安装 lefthook。包装脚本使用 lefthook 经过评审的 --force 模式,确保已存在 core.hooksPath 的关联 worktree 不会导致正常的 pnpm run … 命令失败。

如果依赖是从缓存恢复或 postinstall 被跳过而导致缺少钩子,请手动安装:

pnpm exec lefthook install --force

新克隆后请先运行一次类型检查:

pnpm run typecheck

首次类型检查会执行全仓 tsc -b tsconfig.json 图:发射每个 package/vendor 的 lib/types,并通过下述两个 no-emit 聚合检查示例、测试和脚本。

TypeScript 项目布局

仓库的 TypeScript 配置只有三种角色;每个 tsconfig 文件恰好扮演其中一种。

文件 角色 是否构成 program
tsconfig.json solution 根:extends base、files: []、引用两个聚合。全仓 tsc -b tsconfig.json 图、tsserver 发现入口,并经继承的 paths 充当 tsx 运行 examples/scripts/ 时的解析配置(它们最近的 tsconfig 就是此文件)。
tsconfig.host.json host 聚合host 侧各包(经 references、示例、测试、脚本、website。排除 packages/client
tsconfig.client.json client 聚合:packages/client/* 各包及其测试、apps/web
tsconfig.base.json 共享 compilerOptions 与源码 paths 映射。同时是各 vitest 配置让 vite-tsconfig-paths 指向的解析门面:它没有 include,因此其 paths 适用于任何 importer。
tsconfig.base.client.json 浏览器编译形状(jsx、DOM lib、types: []),由 client 聚合和每个 packages/client/* 包 extends。

host 与 client 保持两个聚合 program是因为两侧在相同键下以不同服务对 cordis Context 接口做声明合并;单一 program 同时看到两份合并会报冲突。这种冲突只存在于 ts.Program 内部——模块解析永远不会触发它——所以 solution 可以同时引用两个聚合,一个 paths 门面也可以横跨两侧。由此推出两条纪律:

  • tsconfig.base.json 永不添加 includefiles:它们会泄漏进每个 extends 它的包项目,并收窄门面的全匹配范围。
  • 构造全仓 ts.Program 的脚本显式种子 tsconfig.host.jsontsconfig.client.json——永不种子根 solution因为把两个聚合展平进一个 program 会撞上 Context 合并冲突。基于 program 的生成器与门禁(scripts/ts-project.ts 的消费者、doc-typecheck standalone 模式)按决策仅覆盖 host 侧client 侧只在出现真实需求时再获得基于 program 的工具。

静态分析和测试通过 base 的 paths 映射把工作区 import 解析到 src,且必须在干净树上通过;消费构建产物 lib/ 的门禁显式声明该依赖。决策记录:solution-root notetsc-first 发射管线见 ts-build-config note

如果相关的本地检查需要使用构建后的包产物,请先构建一次:

pnpm run build

pnpm run hygiene 包含 publint(用构建出的 lib/*.js 文件校验 package 入口点)和 verify-node-next-types(用一个临时的 NodeNext 消费方校验构建出的声明文件)。新 worktree 在 pnpm run build 运行之前没有打包的 JS 和声明文件;普通提交和推送无需构建,除非所选检查会使用这些产物。

环境变量

真实的 DeepSeek 适配器和需要密钥的 agent 演示从环境变量或仓库根目录一个被 gitignore 的 .env 文件读取凭证:

DEEPSEEK_API_KEY=sk-...
DEEPSEEK_BASE_URL=https://... # optional

DEEPSEEK_BASE_URL 可选,默认为公开 API。请勿提交真实凭证。未设置 DEEPSEEK_API_KEY 时,真实 API 的 e2e 套件会自动跳过。

Git 钩子

lefthook 在 lefthook.yml 中配置,作为快速的本地检查点:

  • pre-commit 运行对暂存文件的 ESLint 修复,检查暂存 diff 中的空白错误,并运行 vendor manifest元数据清单守卫
  • pre-push 只运行仓库增量类型检查(对根 solution 执行 tsc -b,覆盖 host 与 client 两个聚合)。

vendor manifest 守卫检查 vendor/*/src 下的改动是否连同对应的 vendor/README.md manifest 更新一起暂存。请在编辑 vendor 代码前先阅读 vendor/README.md

这些钩子有意不运行测试、快照、文档检查、构建或 hygiene。贡献者只运行一次与改动行为相关的检查CI 负责全量覆盖率门禁、构建产物冒烟测试,以及 Node 22.19、24 和 26 兼容性矩阵。

贡献者可以选择运行 pnpm run check:all,执行全面的本地门禁集。该命令独立于两个 Git 钩子,也不是对 agent 的指令。

CI 门禁

keyless CI 工作流 将独立门禁分组到若干宽粒度 lane并在受支持的 Node 版本上运行一组较小的兼容性检查。产物消费方在各自 lane 内等待一次 build。单独的真实 API 工作流按其配置的 worker 上限运行 pnpm run test:e2e。当前门禁和 job 清单以 scripts/run-gates.ts 和工作流文件为准。

日常命令

在仓库根目录使用:

pnpm run test           # unit tests
pnpm run test:coverage  # unit tests with per-file coverage gates
pnpm run test:e2e       # real-API tests; self-skips without DEEPSEEK_API_KEY
pnpm run check:all      # comprehensive opt-in gate set; not wired to Git hooks
pnpm run typecheck      # tsc -b over the root solution: emits package/vendor lib/types, checks both aggregates
pnpm run lint           # eslint .
pnpm run lint:fix       # eslint . --fix
pnpm run doc-typecheck  # compile checked TypeScript snippets in Markdown docs
pnpm run gen-cordis-catalog     # regenerate docs/cordis-catalog/events.md + services.md from source
pnpm run verify-cordis-catalog  # fail if either cordis catalog is stale
pnpm run verify-export-jsdoc    # fail if a module-level package export lacks complete JSDoc
pnpm run gen-doc-graphs     # regenerate generated relationship docs from source and curated graph definitions
pnpm run verify-doc-graphs  # fail if generated relationship docs are stale
pnpm run verify-md-wrap  # fail on hard-wrapped prose paragraphs in docs/README markdown
pnpm run verify-mermaid  # fail if a ```mermaid diagram has invalid Mermaid syntax
pnpm run verify-type-equiv  # fail if a ```ts type-equiv doc block drifts from its source type
pnpm run verify-doc-budgets  # fail if a budgeted standing doc exceeds its word ceiling
pnpm run gen-translation-brief   # print the minimal-update briefing for out-of-sync translation pairs (--apply splices code-only edits)
pnpm run doc-sync       # all Markdown/doc gates, scheduled concurrently; the doc-sync leaf list in scripts/run-gates.ts is the full list
pnpm run gen-module-graph     # regenerate docs/module-graph.md from package peerDeps
pnpm run verify-module-graph  # fail if docs/module-graph.md is stale
pnpm run build          # emit lib/types intermediates, then bundle lib/index.* runtime files
pnpm run verify-node-next-types  # fail if built declarations are not NodeNext-consumable
pnpm run hygiene        # knip, publint, workspace constraints, and NodeNext declaration check

修改 package 的公开行为时,请在同一个变更中更新相关 README 或 JSDoc。pnpm run doc-sync 能检测到被检查的 TypeScript 片段、生成文档的新鲜度、Markdown 换行/链接漂移、type-equiv、翻译配对、Mermaid 语法和文档预算,但更广泛的行文/API 同步仍需评审把关。

演示

单次运行的 Headless coding agent 需要环境变量或仓库根目录 .env 中的 DEEPSEEK_API_KEY

pnpm run demo:headless "summarize this workspace"

全屏交互式 coding agent 需要环境变量或仓库根目录 .env 中的 DEEPSEEK_API_KEY

pnpm run demo:tui

自指的 cordis-agent 演示可以检查并修改其实时插件运行时,并需要相同的凭证:

pnpm run demo:cordis

ACP 自动化服务器通过 JSON-RPC stdio 提供全新 agent 会话,同样需要 DEEPSEEK_API_KEY

pnpm run demo:acp

TODO 标记

请使用以下三种注释标签之一标记代码中的已知问题,按紧急程度排序:

  • FIXME:应当阻塞新版本发布的问题。除非评审者明确同意该更改可以合并,否则发布版本不应包含未解决的 FIXME
  • TODO:应当尽快修复的问题,等资源到位即可处理;
  • XXX:也许某天会修复的问题,优先级最低,不作承诺。

请选择与紧急程度匹配的标签,让浏览代码的人一眼分清「发布阻塞」和「有空再说」。

逐字记录类型(ts type-equiv

核心数据结构文档会把与源码等价的声明及其原始 JSDoc 一并粘贴,让读者看到确切形状和源码契约。为防止粘贴内容在源码变化时漂移,请将其围栏为 ```ts type-equiv(而不是 ```ts),并在 scripts/type-equiv.manifest.json 中登记它镜像的源文件和符号:

{ "doc": "docs/core-data-structures/session.md", "symbol": "SessionEvent", "source": "packages/core/session/src/types.ts" }

pnpm run verify-type-equivdoc-sync 的一环)随后通过 TypeScript 解析器从源码提取该符号的声明及其附带的 JSDoc并断言代码块同时匹配两者。对于不应把实现体写进目录的类请使用 ```ts public-api 并设置 "projection": "public-api";门禁检查的投影会保留公共字段、构造函数、访问器、方法以及类和成员的原始 JSDoc同时省略实现体和私有或受保护成员。比对会忽略空白和非 JSDoc 注释,但要求保留每条原始 JSDoc包括成员文档让读者同时看到源码契约和确切形状。该门禁按文档、符号和投影在主块与 manifest 条目之间强制 1:1 对应;只有当配对 .zh.md 块的完整受跟踪围栏序列与其无后缀兄弟文件按字节一致且顺序相同时,才会复用后者的条目。doc-typecheck 对可编译围栏应用同一派生规则,同时跳过两种源码等价围栏的编译,并将其排除在 opt-out 比例之外。当你改动一个已记录的类型声明或其 JSDoc 时,门禁会失败直到你更新粘贴内容;当你增删一个主块时,请在同一个变更里更新 manifest。

架构上下文

在修改 packages/ 目录下的任何内容之前,请先阅读 docs/architecture.md。这套代码围绕 Cordis 插件、事件溯源的会话、类型化的服务 seam 与显式扩展点构建。