Overview
dsh-plugin-local-model
README / EN
Package documentation
Registry summary
dsh.pub verifies the pinned bundle contract, runtime facts, and distribution semantics. The complete README remains in the source repository.
Read the full README on GitHubLIMITATIONS
Known limitations
dsh 目前处于开发者预览期,接口仍在变动,因此**所有宿主集成点都做了显式降级,宁可少做也不报错**: - 本插件 `inject` 为空:`llm` / `tools` / `commands` / `timer` 全部通过 `ctx.get()` 读取, 缺失或接口对不上时只跳过对应增强,**模型加载与空闲卸载这条主线始终可用**。 - `llmBridge` 会依次探测 `registerProvider / upsertProvider / registerRoute / addRoute / setRoute`, 全都不匹配时打印可直接粘贴的 `settings.yaml` 片段(第 5 节),而不是失败。 - `/local-model` 命令同时挂了 `execute` 和 `run` 两种入口名,以适配不同版本的 commands 服务。 - `src/commands.ts` 与 `/local-model status` 的输出格式可能随宿主调整而调整 —— 它们只是便利功能, 真实状态以 `GET http://127.0.0.1:18080/local-model/status` 为准。 - `types/dsh-ambient.d.ts` 是**离线编译用**的环境声明(只覆盖本插件用到的接口)。 在 dsh 仓库内开发时以主仓库的真实类型为准;若出现重复声明告警,把它从 `tsconfig.json` 的 `include` 里去掉即可。 - 未做:多模型同时常驻(严格一次一个,符合"释放资源"的目标)、图像输入透传的端到端验证、 Windows 上 llama-server 的优雅退出(llama.cpp 无状态可刷,直接结束进程树)。 ### 浏览器半侧是复刻的构建,不是官方预设 dsh 官方明确说明产出 `dsh.client` bundle 的 `clientBundle` 预设**不在已发布的包里**, 仓库之外的插件必须自己复刻。本项目的复刻落在 `scripts/build-client.mjs`:esbuild 打成 CJS (`react` / `react/jsx-runtime` 全部 external,由宿主提供),再手工套上 `window.__ModuleLoader__.load({ id, factory })` 外壳;形状是拿本机三个**已经在生效**的 `dsh.client` 包的产物逐字节对照出来的,并由 `npm run test:client` 用假 loader 真跑一遍守住。 升级 dsh 后如果设置页不出现,先跑这两个脚本,再检查 `dsh.client.inject` 里的客户端包名是否仍然存在。 面板的数据面是**自建的同源 HTTP 桥**而不是 dsh 的 settings 命名空间(原因见第 4 节), 因此设置写在插件自己的 `<DSH_HOME>/local-model/state/config.json` 里。这是刻意的取舍: 它不依赖宿主内部接口的版本,代价是这些设置不出现在 `settings.yaml` 中,也就不能跟着 dsh 的凭据/同步机制走。桥只服务回环来源 —— 通过局域网访问 dsh 时面板不可用。 界面文案目前是中文硬编码(只额外注册了中英两份分区标题词条)。 ### 本包的 manifest 是按实机对照确认的 `dsh.bundle` 与 `dsh.client` 的形状不是照文档猜的,是拿本机几个**已经在生效**的第三方插件 逐个字段对出来的(`dshmarket`、`@linxin666/dsh-web-all`、`dsh-better-sidebar`): ```json "dsh": { "bundle": { "patch": "./cordis.patch.yml" }, "client": { "inject": ["@deepseek-ai/dsh-client-locale", "@deepseek-ai/dsh-client-ui-settings"], "platform": "web" } } ``` `engines.dsh` 与 `@deepseek-ai/dsh-tools` 的 peer 范围都**不再声明**,只留 `engines.node`。 历史上这里写过显式的预发布分支(`^0.1.0-rc.1 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0`), 原因是 node-semver 的一条规则:**范围里不含预发布标签的比较符不会匹配预发布版本** —— 所以裸 `"*"` 反而匹配不到 harness 的 `-rc.x` 构建,必须逐个 minor 补 `|| ^X.Y.Z-0` 分支。 但这条路是死胡同:harness 每出一个新 minor 预发布(例如 `0.2.0-rc.1`)就要补一个分支, 漏补就会被市场判成「与当前 DSH 不兼容」并弹出崩溃警告,而插件本身其实照常工作 —— 这是纯声明侧的维护成本,不是真实的功能依赖。 现在改为**不设版本闸门**:删掉 `engines.dsh`,`dsh-tools` 的 peer 范围回归 `"*"`。 插件对 harness 的耦合实际很弱,全部走运行时能力探测 —— `lib/tools.js` 对 `dsh-tools` 是 `await import()` 且失败只告警跳过工具注册,客户端依赖走 `dsh.client.inject` 由宿主解析, 没有任何一处硬编码 harness 版本号。因此版本上限交给宿主/市场自己去管,插件不再替它断言。 官方 `@deepseek-ai/*` 仍一律写进 `peerDependencies`(而不是 `dependencies`),并全部标 `optional`。 `cordis.patch.yml` 里的 loader entry id 带作者前缀(`dzqjoker-local-model`),不用裸的 `local-model`:cordis 拒绝加载含重复 entry id 的插件树,而插件市场一旦发现新装插件的 id 与已加载的相撞,会直接把该插件卸载(否则下次启动整个 profile 都起不来)。 `exports` 只声明了 `.` / `./client` / `./cordis.patch.yml` / `./package.json` 四个入口, 与上述包的风格保持一致。 `repository` 字段必须指回本仓库 —— 插件市场用它把 npm 包与列表条目关联起来。 本包不再有 `private` 字段:它是要被公开安装的插件。
