# 贡献指南 / Contributing > 🌐 返回目录首页:[中文 README](README.md) · [English README](README.en.md) > 中文为主,English below each section. 先看 [目录收录标准](#目录收录标准),再决定是「收录第三方插件」还是「开发自研插件」。 --- ## 目录收录标准 / Inclusion criteria 一个条目要进 `data/plugins.json` 的 `plugins` 数组,需满足: 1. **真是 DSH 插件或 DSH 生态组件**——npm 包带 `dsh.bundle` manifest,或 GitHub 仓库明确面向 DeepSeek Harness。蹭 `dsh-plugin` tag 但跟 DSH 无关的仓库不收(进入 `watchlist` 观察区)。 2. **有真实代码**——占位仓库、空壳、纯 README 不收。 3. **信息可核实**——`repo`(owner/name)与 `stars` 必须真实(用 `gh api` 核实)。 4. **中英双语描述**——`description.en` 与 `description.zh` 都要有(各 ≤140 字符,一句话)。 5. **兼容性诚实**——`compat.status` 只能填四个枚举值;没实测过就留 `unknown`,绝不手填 `ok`。 以下条目进入 `watchlist`(「未收录/观察」区),不显示在 README 主目录里: - `蹭tag`(与 DSH 无关却挂了 dsh-plugin topic) - `工具链`(教程 / 其他 harness / Python 工具链,非 DSH 插件) - `占位`(占位仓库 / 未完成) An entry belongs in the `plugins` array only if it (1) is a real DSH plugin or ecosystem component, (2) has real code, (3) has a verifiable `repo` + real `stars`, (4) has both `description.en` and `description.zh`, and (5) keeps `compat.status` honest (leave `unknown` until verified). Spam / toolchain / placeholder entries go to `watchlist`. --- ## 提交目录条目 / Adding a catalog entry 1. 用[收录申请 issue 模板](.github/ISSUE_TEMPLATE/plugin-submission.md)开 issue,填好包名/仓库/描述/分类。 2. 维护者核实后,在 `data/plugins.json` 里加一条(字段见 [docs/catalog-schema.md](docs/catalog-schema.md)),`compat.status` 填 `unknown`、`featured` 默认 `false`。 3. 本地跑 `npm run gen:readme` 重新生成 README 表格,跑 `npm run compat:check:layer1` 出兼容报告。 4. 开 PR,CI 会自动校验;合并后表格随数据自动更新——**永远不要手改 README 里的目录表格**。 Open an [inclusion-request](.github/ISSUE_TEMPLATE/plugin-submission.md) issue first; a maintainer verifies, then the entry is added to `data/plugins.json` and the README tables are regenerated by `npm run gen:readme` (never hand-edit the tables). --- ## 15 条插件设计准则(精简版)/ 15 design principles (condensed) 完整版见 `research/dsh-plugin-design-principles.md`,每条对应 Cordis 时空可组合性论文里的概念。写 DSH 插件时逐条对照。 1. **注册即效果,register 必须返回 disposer** / Registrations are reversible effects —— 一切贡献经 `ctx.effect()` / `ctx.on()` 安装并返回 disposer,卸载才能 LIFO 回卷。 2. **共享状态必须物化为协作用键,禁止全局/模块级可变态** / Reify shared state as a service key —— 全局变量在系统边界外,不跟踪、不撤销、卸载即泄漏。 3. **依赖走 `inject` 声明,不乐观查找** / Declare dependencies via `inject` —— 满足性判定决定组件激活,service locator 会破坏响应式协作用。 4. **每个原子副作用配一个逆,且逆必须真的撤销** / Supply an inverse per atomic effect —— 运行时校验依赖作者写的逆正确,写错了卸载就留下半恢复状态。 5. **把需顺序拆除的相关操作放进同一个 effect** / Keep related teardown in one effect —— 逆按反序复合,拆开就失去 LIFO 顺序。 6. **共享能力做成「集合型可交换协作用」** / Prefer commutative set-valued coeffects —— 可交换键让不同插件效果相互独立、可乱序撤销。 7. **多 provider 走 service broker,不要 exclusive binding** / Use a service broker —— broker 吸收 provider 切换扰动,消费者无感知。 8. **能力封装成 seam(Service + Provider + Consumer)** / Encapsulate capabilities as seams —— consumer 只依赖接口,provider 卸载自动退出路由集。 9. **外部副作用(发射)不可逆,需扣留或补偿** / Emission crosses the boundary —— 写文件、发消息、调 API 越过边界,只能 output-commit 扣留或 saga 补偿。 10. **需跨重载存活的状态放进更长命的协作用** / Long-lived state lives in a dependency —— 插件闭包状态不跨 HMR/reload 存活。 11. **避免依赖环:双向依赖 = 永久失活** / Avoid dependency cycles —— 拆成「单向核心 + 集成组件」。 12. **声明式配置走 cordis.yml + `!!js`** / Declarative config via cordis.yml —— 加载器按字段增量协调,静息态与加载顺序无关。 13. **消费依赖用 Proxy 属性访问 `ctx.`,而非裸 `ctx.get`** / Consume deps via `ctx.` —— 未声明抛 `UNDECLARED_ACCESS`,teardown 期间依赖仍可读。 14. **用 realm 隔离做多租户/测试,用 interception 做零改动策略** / Isolate with realms; govern with interception —— 编排器不改代码即可约束访问(如只读)。 15. **事件通信走类型化事件 + 声明的派发模式** / Use typed events with declared dispatch modes —— 横切用事件,直接能力调用用 service 方法。 --- ## 开发自研插件 / First-party plugins 自研插件在 `packages/plugins//` 下,命名 `@dsh-suite/plugin-*`。要求: - 纯 ESM + TypeScript,能 `pnpm build` 通过;Node `^22.19 || >=24`。 - `dsh.bundle` manifest + `cordis.patch.yml` 齐全(按 `packages/create-dsh-plugin` 模板 + `research/plugin-spike/` 验证序列)。 - 遵守上面 15 条;`inject` 声明依赖、`ctx.on` 返回 disposer、发射副作用只 `console.warn` 不重试。 - 包内 README 中英双语;提交前按 spike 验证序列真实装进 DSH profile 跑通装载。 First-party plugins live in `packages/plugins//`, named `@dsh-suite/plugin-*`. Pure ESM + TypeScript, must build, ship a `dsh.bundle` manifest + `cordis.patch.yml`, obey the 15 principles, and be verified by actually loading into a DSH profile before submission. --- ## 提交流程 / PR workflow 1. Fork → 分支 → 提交(单 PR 单主题)。 2. 数据类改动:改 `data/plugins.json` 后**必须**跑 `npm run gen:readme` 并一起提交 README 变更。 3. 脚本类改动:跑 `node scripts/compat-check.mjs` 验证不报错。 4. 提交前自查:`npm run gen:readme` 无 diff 漂移、README 表格行数与数据一致。 5. 描述写清「改了什么 / 为什么 / 验证了什么」,等 CI 绿了再合并。 Fork → branch → commit (one topic per PR). Data changes must re-run `npm run gen:readme` and commit the regenerated README. Script changes must pass `node scripts/compat-check.mjs`. Self-check for drift before pushing, then wait for CI. --- ## 给插件作者 / For plugin authors 收录进目录后,把徽章或横幅挂到自己的 README,回链 dsh-suite,让更多人发现你的插件。 ### 标准徽章(所有收录插件自助可用) 复制这段 Markdown 到你的 README 顶部: ```markdown [![featured on dsh-suite](https://img.shields.io/badge/featured%20on-dsh--suite-4d6bfe)](https://whyihaveyou.github.io/dsh-suite/) ``` ### 精选横幅(仅 featured 插件) Featured 插件另有一张专属横幅,直接引用(把 `` 换成你自己的 id): ```markdown [![dsh-suite Featured Pick](https://whyihaveyou.github.io/dsh-suite/assets/badges/.png)](https://whyihaveyou.github.io/dsh-suite/) ``` Once listed, add the badge above to your README to link back to dsh-suite. Featured plugins also get a per-plugin banner under `site/assets/badges/.png` (generated by `scripts/gen-featured-banners.mjs`, not hand-edited).