概览
dsh-image-tool
README / ZH
插件文档
目录摘要
dsh.pub 核对固定版本的组合包契约、运行时事实与分发语义;完整 README 请查看源仓库。
在 GitHub 阅读完整 READMELIMITATIONS
已知限制
- **可选服务必须用 `ctx.inject`,不能直接 `ctx.get('x')` / `ctx.x`。** 这是本项目踩过的最贵的坑:访问**未在 `inject` 里声明**的服务会抛 `cannot get property "webServer" without inject`,而这行如果在 `apply` 里, 整个插件的 entry 就直接变成「启动失败」—— 使用者只看到插件卡上那一个词, 看不到任何原因。只有 Web profile 才有 `webServer`,所以它天然是**可选依赖**: ```js // ❌ 抛错:webServer 不在 inject 里 const webServer = ctx.get('webServer') ?? ctx.webServer // ✅ 可选依赖的正确写法 ctx.inject(['connection', 'webServer'], routeCtx => { const ws = routeCtx.get('webServer') }) ``` `inject = [...]`(模块导出)是**硬依赖**:缺了插件就不激活。 `ctx.inject([...], cb)` 才是"可用时才执行"。另外 `apply` 里每一步都独立 try/catch (见 `lib/index.js` 的 `step()`)—— 工具挂不上不该拖垮路由,反之亦然。 - **改代码要重启 DSH;改配置不用。** 这两条是真的不一样: - **配置**走 `settings.describe()`,是每次调用现读的运行时值(`applies: 'live'`),写入即生效; - **代码**是模块,Node 会缓存已加载的 ESM(浏览器半同理,由外壳的模块加载器持有)。 只改配置文件不会重新加载 `lib/*.js` 或 `client.js`。 - 另外每次 volatile 更新都会**重新执行 `apply`**,所以诊断日志里会看到多次 `apply:` —— 这是平台的正常行为,不是重复装载(loader entry 只有一条)。 ⚠️ 正因如此,工具与路由的注册**必须经 `ctx.effect`**:同一层里重名注册会直接失败, 症状是插件卡显示「启动失败」,而且**第一次是好的、动过配置之后才坏**。 - **浏览器半依赖外壳的槽位与主题契约**(`settings.section`、`tool.call.toolview`、 `--dsw-alias-*`、宿主提供 `react`)。这些是平台内部约定,跨大版本升级时可能变; `npm run test:client` 会在加载层先把最典型的几种破裂挡下来。 全屏浮层还需要 `react-dom` 的 `createPortal`:拿不到时**降级**成就地 `fixed` 渲染 (功能可用,但浮层可能被祖先容器的 `transform` / `overflow` 裁切),不会让卡片崩掉 —— 卡片渲染抛错会被宿主永久弃用,代价远大于少一个浮层。 - **确认通道依赖 `userQuestions`**:没有它的 composition 里,开启确认会**拒绝生图**并说明原因 (fail-closed:宁可画不出来,也不要在"说了要问却没问"的情况下花钱)。 - **URL 过滤不是完整的 DNS 出站隔离**:当前检查 URL 主机名与 IP 字面量, 不做 DNS 解析校验;不可信上游的域名解析仍需由部署环境的网络策略限制。 - **`/image` 引用索引不是持久存储**:配置更新导致重新挂载或进程重启后, 旧 `fetchUrl` 会返回 404。长期保存请用 `includeData=1`。 - **另存的是附件里的版本**:图片附件可能经过平台规范化(缩放/重编码), 自动落盘保存的才是上游原图。 - **改图的原图只能来自会话或工作目录**:不接受远程 URL(那等于让模型指挥服务端去请求 任意地址)。要改远程图,先把它下载进工作目录。 工作目录内的路径会做**词法 + `realpath` 双重校验**,符号链接/junction 指向盘外时会被拒绝。 - **改图的 `mask` 只做软校验**:OpenAI 约定 mask 必须是 PNG、与原图同尺寸、透明处为编辑区; 本插件在**不是 PNG 时会给一句提示,但不会替你拦下** —— 不同中继的接受度差别很大, 硬拦反而挡住了能用的路径。另外**原图与 mask 的尺寸一致性由上游判定**, 这里不做像素级比对(那需要引入图像库)。 - **`/edit` 的 HTTP 调用必须自带 `cwd`**:会话工作目录在 HTTP 路径上并不存在, 而"哪些路径允许读"必须有一个边界,插件不会拿进程当前目录去猜。 - **`--set` 的值里不能有前导 `--`**:参数解析把 `--` 开头当作下一个 flag。 值里真需要时用 `--set key=--value` 形式(带 `=` 的那种解析路径不受影响)。 ---
