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` 是给市场/网站读的版本闸门(市场会把 `engines.dsh` 与 `@deepseek-ai/*` 的 peer 范围一起收进兼容性卡片)。写它有个坑:**不带预发布分支的范围会静默匹配不到 harness 的 `-rc.x` 构建** —— node-semver 只在范围里某个比较符与该版本的 `major.minor.patch` 元组完全一致、且自身带预发布标签时才放行预发布版本。所以这里用显式的 `||` 分支: ```json "engines": { "dsh": "^0.1.0-rc.1 || ^0.1.1-0 || ^0.1.2-0 || ^0.1.5-0" } ``` harness 出一个新的 minor 预发布(例如 `0.1.6-rc.1`)时需要补一个分支,这是这类声明 固有的维护成本。`peerDependencies` 同一处理:官方 `@deepseek-ai/*` 一律写进 `peerDependencies`(而不是 `dependencies`),并全部标 `optional`。原来写的 `"*"` 看着最宽, 实际受同一条 semver 规则影响**匹配不到任何 `-rc.x`**。 `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` 字段:它是要被公开安装的插件。
