# deepseek-harness-plugins **Repository Path**: NullPE/deepseek-harness-plugins ## Basic Information - **Project Name**: deepseek-harness-plugins - **Description**: DeepSeek Harness 插件集合 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-18 - **Last Updated**: 2026-10-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # deepseek-harness-plugins dsh(DeepSeek Harness)插件的开发工作区。每个插件是 `packages/` 下的独立包,由本仓库自带的 dsh 实例(profile `web`)加载调试。 ``` packages// 插件源码,一个插件一个包(入库的主体) GLOSSARY.md 该包的领域词汇 docs/adr/ 该包的架构决策 docs/adr/ 全仓库的架构决策 docs/agents/ 给 agent 的仓库约定(issue tracker、领域文档) GLOSSARY-MAP.md 领域词汇入口,列各上下文 GLOSSARY.md 仓库级领域词汇 .scratch// 规格与 issue,用仓库内的 markdown 文件追踪 .dsh/run/dsh.sh 本地实例的启停脚本 .dsh/run/dsh.conf 本地实例配置 .dsh/ 运行数据(profiles/、sessions/、logs/…),已 gitignore ``` ## 本地实例 环境要求:Node `^22.19.0 || >=24.0.0`、pnpm、一份 dsh 源码检出。检出路径见 [dsh.conf](.dsh/run/dsh.conf) 的 `DSH_WORKDIR`。 ```bash ./.dsh/run/dsh.sh start # 等待就绪,打印 http://127.0.0.1:3081/?token=… ./.dsh/run/dsh.sh status # pid / 端口 / 运行时长 / 日志路径 ./.dsh/run/dsh.sh logs # 跟踪当前日志 ./.dsh/run/dsh.sh restart ./.dsh/run/dsh.sh stop ``` Web UI 用 start 输出里带 token 的地址打开,token 也在日志里。 日志两份:`dsh.log` 与脚本同级,是本次启动的实时输出,`start` 前清空;`logs/dsh-<日期>-<时间>.log` 每次启动一份,逐次保留。启动失败时脚本只报错并指向日志,不改 profile,也不自动恢复。 参数都在 [dsh.conf](.dsh/run/dsh.conf):`DSH_WORKDIR`、`DSH_HOME`、`DSH_PORT`、`DSH_LOG_DIR`。`DSH_HOME` 钉死为本仓库的 `.dsh`,不继承父环境,避免串到别的实例的凭据和会话。 ## 写一个插件 最小插件就是一个目录,Node 直接跑 ESM:零依赖、免构建。以 `packages/hello/` 为例。 `package.json` ```json { "name": "@lilyanna/hello", "version": "1.0.0", "private": true, "type": "module", "exports": { ".": "./index.js", "./locale/*.json": "./locale/*.json", "./icon": "./icon.svg" }, "files": ["index.js", "cordis.patch.yml", "locale/*.json", "icon.svg"], "dsh": { "bundle": { "patch": "./cordis.patch.yml" } } } ``` `cordis.patch.yml` — 把插件行插进 profile 的 Loader 组合 ```yaml - insert: - id: hello name: '@lilyanna/hello' config: {} ``` `index.js` — Host 侧入口;注册的资源都要返回清理函数 ```js export function apply(ctx, config) { // 例: const off = ctx.on('…', handler); return off } ``` `locale/zh.json` — 插件面板读这里的标题与描述 ```json { "meta": { "title": "Hello", "description": "示例插件。" } } ``` 再加 `icon.svg`(也支持 PNG/JPEG/WebP,≤256 KiB)。硬要求: - `package.json` 必须声明 `dsh.bundle.patch`;否则只作普通依赖装上,不成 profile 层。 - 行 `id` 在组合里唯一,`name` 写包名;覆盖 `config` 或停用都按这个 `id` 命中。 - 统一用 `@lilyanna/<插件名>` 命名,并加 `private: true`。 - 提供 `locale/*.json` 与图标;缺失时面板回退到包名和默认图。 ## 带 Web UI 的插件 在 `package.json` 上追加 `./client` 出口与 `dsh.client` 段: ```json { "exports": { "./client": "./client.js" }, "files": ["client.js"], "dsh": { "client": { "platform": "web", "immediately": true, "inject": ["@deepseek-ai/dsh-client-ui-conversation"] } } } ``` `client.js` 用浏览器模块加载器注册惰性工厂,`id` 必须等于包名;React 由模块表提供,在工厂里 `require('react')` 取用: ```js window.__ModuleLoader__.load({ id: '@lilyanna/hello', factory(require) { const React = require('react'); return { inject: ['slots'], apply(ctx) { // 先确认目标 slot 的 props 与注册选项,再注入并注册: // ctx.slots.inject('', () => ctx.slots.register( // { name: '', id: 'hello' }, Component)); }, }; }, }); ``` 工厂保持无副作用。定时器、监听器、样式都在 `apply` 里用 `ctx.effect`/`ctx.on` 注册并返回清理,可见文案走 Client 侧 locale。 ## 装进本地实例 `dsh plugin` 把参数转发给 profile 目录里的 pnpm,装完把新 bundle 选进 `dsh.profile.bundles`。命令要在 dsh 源码检出里跑(`apps/cli/src/bin.ts` 与 `tsx` 都相对检出解析): ```bash REPO=$(git rev-parse --show-toplevel) # 本仓库根 DSH_SRC=$(sed -n 's/^DSH_WORKDIR=//p' "$REPO/.dsh/run/dsh.conf") # 读 dsh.conf cd "$DSH_SRC" DSH_HOME="$REPO/.dsh" node --import tsx/esm apps/cli/src/bin.ts \ plugin --profile web add "link:$REPO/packages/hello" ``` - 路径用绝对路径最稳;`./`、`../` 开头的相对路径按**执行命令时所在的目录**展开后再交给 pnpm。 - 卸载把 `add` 换成 `remove @lilyanna/hello`。 - 装好后可在 Web UI 插件管理里启用/停用。 - 也可在 `$DSH_HOME/profiles/web/cordis.patch.yml` 按行 `id` 覆盖 `config` 或写 `disabled: true`。 - 在 dsh 会话里也可让 agent 用 `plugin_manager` 装同一个包目录,效果等价。 - 新装 bundle 通常热加载;改动已装插件的 JS 要重启实例。 - 没生效时先看 `dsh.log` 有无启动报错。 - 再查 `$DSH_HOME/profiles/web/package.json` 的 `dsh.profile.bundles` 是否含它。 - `node_modules/<包名>` 应指向 `packages/`。 `.dsh/profiles/` 不进仓库,profile 组合因此每台机器各异。 ## 版本兼容 安装前 DSH 检查 `engines.dsh`(无则看 dsh 的 peer 依赖);不满足直接拒绝安装。确需放行只能按精确版本豁免: ```bash … plugin --profile web allow-version <包名>@<版本> --dsh-version <精确版本> --accept-risk ``` 这会让不兼容的插件真的跑起来,可能崩溃或损坏数据,只在明确知道后果时用。 ## 约定 - 有依赖或构建时注意:`link:` 只做目录链接,不装被链接包自己的依赖。 - `files` 只影响打包发布;`link:` 直接链接目录,不按它过滤文件。 - 规格与 issue 写进 `.scratch//`,见 [issue-tracker.md](docs/agents/issue-tracker.md)。 - 架构决策与领域词汇分两层:仓库级与包级,见 [domain.md](docs/agents/domain.md)。 - 贡献走 fork + 分支 + Pull Request。