AGENTS.md
August 13, 2026 · View on GitHub
本文件是仓库的宪法:任何改动(代码、语料、文档、新包)都必须符合这里的规则。 读它之前,先读 README.md 了解仓库全貌与 DSH 官方 AGENTS.md 了解 DSH 自身的工程约定。
0. 一句话立场
我们移植 omp 的能力到 DSH,但不移植 omp 的体积。 每个插件只做一件事,做小、做薄、做可替换;宁可多一个包,不许多一层职责。
1. 与 DSH 设计哲学一致(强制)
- 一切皆插件:能力 = 组合里的一行(cordis.yml / cordis.patch.yml)。不写"独立程序"式代码。
- 双平面:HOST 组合持有注册表与跨会话共享能力(本仓库的 uri-registry 属于此面);AGENT PRESET 持有单会话贡献(工具、人设、提示词段)。新包先问自己:它贡献到哪个面?
- 服务契约通信:插件之间只通过
ctx.provide/ctx.get(或inject)声明的服务往来,禁止跨包直接 import 对方的实现细节(类型 import 允许)。服务是边界,实现是隐私。 - 生命周期可逆:一切副作用(工具注册、服务提供、事件监听、handler 注册)必须返回 disposer 或挂在
ctx.effect()上;插件卸载 = 零残留。 - 官方 API 优先:用
@deepseek-ai/dsh-*与cordis的既有能力(defineTool、ctx.tools.register、ctx.on),不自造轮子;API 以 DSH 检出的类型声明为唯一权威,不猜。
2. KISS(强制)
- 单插件单职责:一个插件回答一个问题。"内置文档"= 语料 + handler;"协议路由"= 注册表 + 工具。谁要把两件事塞进一个包,先解释为什么解耦会失败。
- 体积红线:
- 单插件源码 < 400 行;超过 = 拆文件(仍单职责)或拆包(职责变了)。
- 依赖红线:运行依赖 ≤ 2 个非 DSH 包;能用 node 内建就不用依赖。
- 语料/配置等数据不进代码:放
corpus/、assets/等数据目录,随包分发、独立更新。
- 不做的事清单(反模式,看到就打回):
- ❌ 一个插件同时做 路由 + 内容 + 搜索 + 翻译 + UI + 发布(生态里已有的大而全反例,禁止效仿)。
- ❌ 为"可能有用"预埋抽象/配置项(YAGNI)。
- ❌ 把文档/语料硬编码进
.ts源码(大字符串即技术债)。 - ❌ 在
apply()外产生进程级副作用。
3. 解耦(强制)
- 三层分离(本仓库的样板架构):
- 路由层(uri-registry):scheme → handler 注册表 + 通用安全 + 统一工具。
- 内容层(dsh-docs):具体协议语义 + 语料访问。
- 数据层(corpus/):纯数据,与代码零耦合。
- 可替换性:任何一层可以被等价实现替换而不影响其他层(换个语料、换个注册表实现、加个协议,都不动彼此)。
- 协议即插即用:新协议 = 新插件注册 handler,不得修改 uri-registry。
4. 包结构规范(新建包照抄)
packages/<name>/
src/index.ts # 插件主体:export const name / inject / apply
package.json # name: @omp2dsh/<name>; dsh.bundle.patch 声明
cordis.patch.yml # - insert: [{ id: <name>, name: '@omp2dsh/<name>' }]
tsconfig.json # extends ../../tsconfig.base.json
README.md # 职责边界 + 服务契约 + 与 omp 的对应 + 安装
name(插件名)必须与cordis.patch.yml的 row id 一致。- 依赖关系只允许
workspace:*指向本仓库其他包;peerDependencies 声明 cordis / dsh 运行时。 - 每个包独立
build/typecheck/test(node:test,不引测试框架)。 - client half 契约(强制):有浏览器 UI 的包必须按官方 client 插件契约——入口只导出
inject/apply,tsdown 以__ModuleLoader__.load包裹产出lib/client.js,样式用官方--dsw-alias-*token,dsh.client声明 platform/inject。inject 必须覆盖 apply 里 访问的每个 ctx 服务(如ctx.remote需声明'remote'+'remote.commands',漏声明 直接页面崩溃)。禁止裸 ESM 导出(fsck 报loaded without registering)。详细见 docs/plugin-development-experience.md §9。
5. 质量门槛(合并前必须全绿)
pnpm install && pnpm build && pnpm typecheck && pnpm test零报错。- 测试守修复:每个测试必须对应一次真实修复——它必须在某个历史版本上失败、在修复版上通过(回归测试)。禁止"初版就能通过"的泛测试:通用逻辑、纯函数行为、初版即正确的契约不配测试。新功能提交时若无可失败的历史版本,先记录行为,待真实 bug 出现再补回归测试。
- 文档同步:改了协议/服务签名,README 与 AGENTS.md 相关段落必须同步改。
- changelog:每个包维护 CHANGELOG.md(Unreleased 一节,格式:Added / Changed / Fixed / Removed),随 PR 更新。
6. 移植 omp 的翻译表(判断"迁移是否忠实")
| omp 概念 | DSH 对应 | 本仓库落点 |
|---|---|---|
| InternalUrlRouter | uriRegistry 服务(ctx.provide) | @omp2dsh/uri-registry |
| ProtocolHandler | UriHandler 接口(scheme/resolve/complete/immutable) | 各内容包 |
| OmpProtocolHandler | dsh:// handler | @omp2dsh/dsh-docs |
| docs-index(嵌入/包/磁盘三级) | STATIC_DOCS + corpus/(同步脚本) | @omp2dsh/dsh-docs |
| read 工具解析内部 URL | read_uri 模型工具 | @omp2dsh/uri-registry |
| 穿越校验/did-you-mean | normalizePath / 同名语义 | 路由层 + 内容层 |
迁移时必须按职责拆分,禁止把 omp 的单一文件结构照搬成一个巨型插件。
7. 工作流
- 新想法先写进 README(一句话)+ 拆包判断(哪个面、谁依赖谁)。
- 实现最小可用(一个包一个职责)。
- 实证:在 DSH 里实际运行验证(动态插件或 profile 安装),记录结果。
- 提交信息格式:
pkg(<name>): 动词 简述(如pkg(dsh-docs): add corpus sync script)。
8. 反例存档(引以为戒)
- 大而全:生态中"文档阅读器"类插件把语料、路由、搜索、翻译、UI、发布全塞进一个 bundle(11MB corpus 随包)——违背 DSH 插件思想。本仓库用两包 + 数据目录复刻同一能力,每个包 < 400 行。