Skip to content

Releases: ChenRuoT/dsh-sidebar-qa

v1.2.1

Choose a tag to compare

@github-actions github-actions released this 19 Oct 11:23

[1.2.1] - 2026-10-19

修 DSH 0.2.1 平台上的两个 P0:/sidebarqa/api 信任围栏退化(LAN / --trusted-host 恒 403),以及追问面板不再流式、轮次失败没有任何提示。同时把类型桩升到 0.2.1-rc.2、装载闸测试改成「0.2.0 peer / 0.2.1+ engines」两代语义。

Fixed

  • 信任围栏迁移到 webStartup(host 半改动,需重启 dsh web / 桌面应用):DSH 0.2.1-alpha.1 删除了 webRuntime 服务;src/index.ts 仍只读它,回退读到 loader row 里未求值的 !!js 表达式,Array.isArray 判否后围栏静默退化为 loopback-only——dsh web --host 10.0.0.7 或 --trusted-host app.example 的浏览器访问 /sidebarqa/api 全部 403(config / context / title / catalog 一起失效),且没有任何报错。
    • trustedHostsOf 现在按 webStartup.trustedHosts(0.2.1+)→ webRuntime.trustedHosts(旧宿主)→ loader 的 id: connection 行字面量顺序读;服务存在即以其值为准(空列表表示 loopback-only,不再回退到别的来源)。
    • 新增 bindHostOf / bindProtocolOf(读 webServer.host / .protocol),围栏按上游 packages/client/connection/src/api-request-trust.ts 接受监听 bind IP、按 http(s) 规范化默认端口、拒绝 cross-site 与不匹配的 Origin。
    • webServer 镜像补 host / protocol,webStartup 镜像补上出处;webRuntime 保留为旧宿主回退。
    • 回归:新增 tests/trust-fence.spec.ts(17 例)与 tests/host-route.spec.ts(9 例,用 fake host 驱动真实 apply 路由:webStartup 优先、bind IP、旧 face 回退、malformed 值不抛、403/200、Origin 与 cross-site)。
  • 追问恢复流式;失败轮次不再永久停在「生成中…」(client 半改动,浏览器硬刷新即可):DSH 0.2.x 的 agent loop 不再写持久化的 assistant/chunk——成功提交 assistant/message,失败/中断提交 assistant/attempt(含 compact stream),实时增量改为 opt-in 的 follow({ assistantStream: true })。插件原实现两者都没接,回答只在结束时整段出现,模型报错时面板没有任何提示。
    • followSession 显式传 assistantStream: true,转发 start / chunk / end 帧与重连 snapshot 的 assistantStream.activeAttempt。
    • answer.ts 新增 foldAssistantStreamRecords / assistantAttemptOf / liveStreamOf / applyAssistantStreamFrame,把文本增量、失败原因(finish.reason.failure)与旧格式 assistant/chunk 统一折叠;assistant/attempt 成为带 failure 的 transcript 行(保留已生成的部分文本)。
    • AskPanel 维护 live 行:首 token 起逐段渲染,durable 事件落地后替换;失败轮次显示「本轮回答失败:」。MarkdownText 的 labels 仍按 locale memo。
    • 新增文案键 askTurnFailed(zh/en);回归:tests/answer.spec.ts(新增 9 例)、tests/session-wire.spec.ts(新增 follow 帧转发用例)。

Changed

  • 装载闸叙事与测试对齐 0.2.1 的新语义:DSH 0.2.1-alpha.3+ 的 evaluatePluginCompatibility 只要 manifest 有 engines.dsh 就只按它判、完全忽略 peer(0.2.0 仍只看 peer)。tests/dsh-compat.spec.ts 重写为两代闸门(14 例):两代区间都必须是纯下限、反向检测器覆盖「peer 天花板」与「engines 天花板」、engines.dsh 存在时忽略 peer、并新增 package.json ↔ dsh.plugin.json 的 version / engines.dsh 同步守卫。
  • README / README_EN / AGENTS / CLAUDE 修正:配置面板是 8 个常用键(schema 共 12 字段);测试规模更新为 30 文件 / 443 用例;engines.dsh 不再是「DSH 不读」的纯声明;安装/升级补充 0.2.1-alpha.2+ 的 remove → add 规则;平台种子词与 webStartup 的出处同步。
  • pnpm-workspace.yaml 的 peerDependencyRules.allowedVersions 随桩的 cordis peer 从 4.0.4 升到 4.0.5(与该 checkout 的 vendored cordis 一致)。

Dependencies

  • 类型桩精确钉到 0.2.1-rc.2:@deepseek-ai/dsh-client-locale、@deepseek-ai/dsh-client-ui-primitives。
  • 构建期打包的 schema 库同步到宿主版本:@deepseek-ai/schemastery@3.18.5(精确钉,noExternal 打进 lib/index.js)。
  • 升级需重新 pnpm install。

部署提醒:host 半(信任围栏)需重启宿主;client 半(流式/失败行)只需硬刷新浏览器。桌面版请完全退出应用后重启 launcher。

Full Changelog: v1.2.0...v1.2.1

v1.2.0

Choose a tag to compare

@github-actions github-actions released this 15 Oct 12:44

[1.2.0] - 2026-10-15

修 issue #21「设置保存失败」:配置改为声明在插件自己的 Config schema 上、并按 profile 条目 id 寻址——DSH ≥ 0.1.7(含 0.2.x)上「追问」设置页从「只读默认值」变成可保存。

Fixed

  • 设置面板在 DSH ≥ 0.1.7 上可以保存了(host 半改动,需重启 dsh web):dsh-settings@0.1.7-alpha.1 起没有 register,可编辑字段改为从插件自报的 Config schema 派生(volatileForm 只认标了 volatile() 的字段),describe / update 接受的是 profile 条目 id(cordis.patch.yml 里那一行的 id,本插件是 sidebar-qa),而不是插件声明的命名空间。1.1.0 的接缝只会注册命名空间,于是在这类宿主上 configFace 恒为 undefined——每一次保存都回 503「this host exposes no sidebarqa settings namespace」(正是 #21 截图里那行红字),面板只能显示默认值。
    • host 半现在导出 export const Config = SidebarqaPrefsSchema,12 个字段全部 volatile();apply(ctx, config) 拿到的是每字段一个活引用,新增的 src/live-config.ts 负责把它读成普通配置(字段缺失或读抛错只回落该字段的默认值,绝不让一次读失败打掉整个路由)。
    • src/settings-face.ts 的接缝现在有两形、互斥:宿主有 register(≤ 0.1.6,低于本包声明下限)走原来的命名空间;没有就按条目 id(取 ctx.fiber.entry.options.id)打开同一个 revision 守卫的 describe / update 面。id 取不到、或服务连 describe/update 都没有时给出带原因的拒绝(no-entry / no-form),503 文案由 settingsRefusalMessage 按原因生成,不再是一句「可能缺服务、也可能缺注册」的含糊话。
    • 保存的值经 loader 的 volatile 提交(updateVolatile / loader/volatile-update)直接写进运行中的引用,插件不重挂;摘要与标题路由下一次调用读到的就是新值。
    • 新增 claimOwnSettingsCard:在同代宿主上用 settings.configure({ auto: false }, ctx.fiber) 抑制宿主按 schema 自动生成的表单——本插件自己已有一整页设置卡(settings.section),同一份配置不该出现两个入口(结构探测;宿主没有该方法时静默跳过,且 disposer 挂在 effect 上随插件卸载)。
  • 配置的落点变了(≥ 0.1.7):写在插件自己的 profile 行(cordis.patch.yml 里 id: sidebar-qa 的 config:),不再写 settings.yaml 的 sidebarqa 段(那一代宿主本来也没有该命名空间)。老宿主行为与 1.1.0 一字不变。
  • 回归:新增 tests/live-config.spec.ts(12 例:活引用识别全有全无、读永远给出完整普通配置、坏引用只降级单个字段);tests/config.spec.ts 增加「每个字段必须 volatile()、根不可 volatile」(漏一个字段 = 宿主表单少一项且写入被 Config field "…" is not volatile 拒绝)与「解析结果就是运行期能就地更新的活引用」;tests/settings-face.spec.ts 重写(21 例)——两形接缝、条目 id 寻址、描述符值解引用(活引用直接上线会 JSON.stringify 成 {},面板全空)、畸形宿主不抛、拒绝文案逐原因唯一,以及接线守卫(profileEntryIdOf(ctx);src/index.ts 不得再出现 no-register)。
  • 实测(本机 checkout DSH 0.2.1-alpha.3,只读):用真实的 SettingsForms + volatileForm / isVolatilePath + loader 的 volatile 提交原语,驱动本插件构建产物的 apply 与 /sidebarqa/api 路由处理器(config editor 换成内存假件,不写用户 profile):config.get → 200 / revision 0 / 12 个字段;config.update → 200(#21 里这是 503)/ revision 1 / 值落进行 config;活引用立刻读到新值;stale 写入 → 409 settings-conflict;未声明键 → 400;非 loopback Host → 403。同一路径上「按命名空间寻址」仍然失败(No configurable plugin entry "sidebarqa"),反向钉住了这个修法的必要性。

Dependencies

  • schemastery → @deepseek-ai/schemastery@3.18.4(devDependency,精确钉):volatile() 只存在于 DSH 的分叉(npm schemastery 停在 3.18.0),而宿主只读 schema 的 meta / dict / toJSON(),所以这份 schemastery 由构建期打包进 lib/index.js(tsdown.config.ts 的 noExternal)——运行期不依赖宿主那一份,也就不会与它漂移。dependencies 因此变空(npm schemastery 不再被引用)。升级需要重新 pnpm install。

Full Changelog: v1.1.0...v1.2.0

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 29 Sep 06:44

[1.1.0] - 2026-09-29

修复 DSH 0.2.0 上插件整个不加载:peer 区间写成了闸门会拒的「天花板形」,而 DSH 0.2.0 新增了一道启动期 peer 兼容闸。

Fixed

  • peer 区间从「^锚点」改成「纯下限」,插件重新能在 0.2.x 上加载(host 半改动,需重启 dsh web):DSH 0.2.0 的 boot 在装载每个 profile bundle 前先跑 packages/boot/app-boot/src/plugin-compatibility.ts 的 evaluatePluginCompatibility——对 manifest 里每一个 @deepseek-ai/dsh / @deepseek-ai/dsh-* peer 区间做 semver.satisfies(runtimeVersion, range, { includePrerelease: true })。只要有一个不满足,loadProfileDirectory 就把这个 bundle 的整个 patch 层丢掉(skippedBundles),只在 stderr 打一行 dsh: skipping profile bundle "…"——host 半不加载、client bundle 不组装,插件像没装一样。不是降级,是消失。
    • 本插件的 peer 写的是 @deepseek-ai/dsh-client-locale: ^0.1.0-rc.8。带预发布的 caret 不是下限而是「下限 + 天花板」:validRange('^0.1.0-rc.8') = >=0.1.0-rc.8 <0.2.0-0。运行时的 0.2.0-rc.1 已经越过 <0.2.0-0,于是每个 0.2.x 宿主上插件全层被跳过——这正是「升级 0.2.0 后侧边栏追问没了」的样子。
    • 现改为纯下限:@deepseek-ai/dsh-client-locale: >=0.1.0-rc.8、@deepseek-ai/dsh-client-ui-primitives: >=0.1.7-alpha.1。这条修法本身就是新版本生成上线时插件再次消失的通解:不带天花板,任何将来的 0.x.y / 0.x.y-pre 运行时都满足;带天花板的区间(含 ^ 落在 0.1.0 预发布上、以及任何 >=a <b 组合)都只是在预测下一个版本号。
    • 豁免通道(各 profile 一个 compatibility.json,dsh plugin allow-version)没有采用:那是给「明知不兼容仍要跑」的逃生门,改手改用户的 profile,不是第三方插件的修法。
    • 附带把 engines.dsh 从 >=0.1.2-alpha.1 抬到 >=0.1.7-alpha.1(如实反映 1.0.1 起就依赖的 SettingsForms 世代与 1.0.2 的图标改名世代;DSH 不校验 engines,它只是声明)。
    • dsh.plugin.json 的 engines.dsh 同步更新、version 对齐 package.json(此前它一直停留在 1.0.0;随本次 pnpm version minor 一起到 1.1.0)。

Changed

  • 类型桩钉到 0.2.0-rc.1 世代(dev-only):@deepseek-ai/dsh-client-locale 与 @deepseek-ai/dsh-client-ui-primitives 两个 devDependency 均精确钉 0.2.0-rc.1,pnpm-workspace.yaml 的 peerDependencyRules.allowedVersions 随之更新(两个桩 peer 的是 @deepseek-ai/cordis@~4.0.4,本包从不链接)。client 半源码零改动(随包发布的 lib/client.js / lib/client-registry.js 重新构建过一次,内容与 1.0.2 等价)。升级后 tsc --noEmit 零报错通过——client 半对 0.2.0 API 世代的全部调用(MarkdownText.labels / Tooltip / Menu / iconOf 的 7 个 glyph / conversation.input.for(actx).setDraft / locale.register(ns, locale, dict) / sidebarRightTabs 三阶段注册)都在新桩上重新校验过一遍。
  • pnpm-workspace.yaml 的 minimumReleaseAgeExclude 改为作用域通配符(dev-only,装机 prerequisite):pnpm ≥ 11 默认开启 24h minimumReleaseAge 供应链接入闸,而 @deepseek-ai/* 的 rc 发布总是「当天发、当天被本类插件钉上」,name@version 形式的旧条目在 pnpm 11 上已不再生效,pnpm install 会以 ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION 直接失败。改为 '@deepseek-ai/*' 一条(范围仅限 devDependency 的类型桩:不随包发布、运行期不链接、且全部精确钉),旧的 rc.6 条目保留作溯源注释。
  • 0.2.0 兼容性逐点核对结论(无源码改动):右侧栏类型注册表(SidebarRightGuideEntry 的 id + order + 可选 icon、title: (address) => string)、sidebar.right.pane.tab / .title 两个 keyed 席位、session-controller 的远端动词(rename / fork / prompt / page / follow / create / selectModel / modelCatalog)、session-query 的 SessionSurfaceSnapshot、llm 的 GenerateOptions、webserver 的 WebRoute、WebRuntimeValues.trustedHosts(信任围栏读的那个服务面)、PLATFORM_MODULES 九个平台种子词、SettingsForms(无 register → 设置接缝安静降级,与 1.0.1 的行为一致)——v0.1.7-rc.2 → v0.2.0-rc.1 两档之间这些文件的源码 diff 为空,仅版本号变化。因此本次没有源码层适配工作,唯一的根因就是 peer 区间。
  • 新回归 tests/dsh-compat.spec.ts(7 例):在 node 里逐行复刻 0.2.0 的闸门——(1)插件声明的每一档 DSH 运行时(0.1.7-alpha.1 / 0.1.7-rc.2 / 0.2.0-rc.1 / 0.2.0 / 0.3.0-rc.1)都必须通过;(2)「旧区间 ^0.1.0-rc.8 在 0.2.0-rc.1 上必须被判不兼容」这条检测器反向钉住本套测试能抓到这个故障;(3)每个 gated peer 区间不得含 < 天花板(semver.validRange 归一化后不含 <);(4)装了 DSH checkout 时直接读它 app-boot 的版本再跑一遍闸门;(5)每个 @deepseek-ai/* devDependency 必须是精确钉(semver.valid)且与 node_modules 里装好的副本逐字一致。
  • tests/primitives.spec.ts 的桩世代判定改为从装好的桩自身读(Regular/Medium 后缀 = 改名后世代,否则为改名前),不再假定「桩一定在旧世代」;两个世代的解析链仍各自全量覆盖。
  • 新回归在 node 里复刻 DSH 闸门需要同一个 semver 判定器,故 devDependency 增加 semver + @types/semver(仅 tests 使用,不进 client bundle、纯度门不受影响)。
  • tests/markdown-labels.spec.ts 的说明改为指向新的钉子(精确钉 + 纯下限 peer),语义不变。

Full Changelog: v1.0.2...v1.1.0

v1.0.2

Choose a tag to compare

@github-actions github-actions released this 24 Sep 07:32

[1.0.2] - 2026-09-24

修「打开侧面板就报 面板渲染出错:Minified React error #130 … but got: undefined」:宿主在 0.1.7-alpha.1 重命名了整套图标,而本插件按名 import 的那些 glyph 在运行期就是 undefined。

Fixed

  • 宿主图标改为按名解析,不再按名 import(仅 client 半改动,浏览器硬刷新即可):feat(web): unify the client visual language(首个发布 0.1.7-alpha.1)把宿主整套图标从「尺寸后缀」改成「字重后缀」——IconQuestionOutline14 / IconCheckOutline16 → IconQuestionOutlineRegular / IconQuestionOutlineMedium——且不留任何别名(packages/client/ui-primitives/src/icons/index.tsx 里旧名字已彻底删除)。
    • 症状:面板输入区(ModelSelect / StrategySelect 的 chevron、勾选、警告 glyph)在本插件的 containment 边界内抛错,于是整块面板被替换成那条可重试的崩溃说明条;tab chip 的 glyph 在边界之外(活标题席位)抛错,由宿主的 per-entry 边界接管——代价是整个标题注册被 retire(页面上 tab 标题丢失)。两处都是同一个根因。(那条说明条本身按设计工作:以前这种情况是整块变白且无法恢复。)
    • 为什么 tsc 拦不住:本包的类型桩精确钉在 0.1.6-alpha.2(改名前的世代),旧名字在桩里仍然声明;而运行期交给插件的是宿主自己的模块命名空间,于是这些绑定就是 undefined——React 对 undefined 的答复是 error #130(Element type is invalid … but got: undefined,URL 里 args[]=undefined&args[]= 正是它)。
    • 新增 src/client/primitives.ts(纯规则,node 可测):pickExport / iconIn / Glyph——解析链 Regular → Medium → <base><legacySize>;「名字在但不是组件」的值会被跳过;三种名字都没有时返回 undefined,由 Glyph 渲染为空(素材缺失是降级,不是故障)。
    • 新增 src/client/host-primitives.ts:唯一 value-import @deepseek-ai/dsh-client-ui-primitives 的模块,把宿主命名空间绑给上面那条规则(iconOf)。平台模块表在任何 bundle factory 运行前就已冻结,所以在模块作用域读取是安全的——这与 cordis 服务「必须在调用点现场探测」的规则不同。
    • 调用点全部改走 iconOf + Glyph:index.tsx(两个 tab 的 glyph)、ModelSelect.tsx(4 个)、StrategySelect.tsx、HistoryPanel.tsx。SidebarTab.icon 变成可选;guide 条目在拿不到 glyph 时不写 icon 键(把宿主的方块占位留给宿主自己画);titleFor 经 Glyph 渲染,绝不 createElement(undefined, …)。
    • MarkdownText / Tooltip / Menu 仍是按名 import:它们是有类型的 API 面,宿主跨版本保留;会被随意改名的只有图标素材。
    • 回归:tests/primitives.spec.ts(解析链 / 非组件值 / 两种世代 / 接线守卫「只有 host-primitives.ts 能 value-import 宿主命名空间」「任何 client 文件都不得再按名 import Icon*」/ 装了 DSH 源码 checkout 时直接核对真机导出表);tests/panel-icons.spec.ts(用只有 0.1.7 名字的宿主 mock 渲染 StrategySelect——旧代码在这条用例上会抛 #130);tests/sidebar-native.spec.ts 新增「宿主没有这个 glyph 时」的注册 + 标题渲染用例。

Full Changelog: v1.0.1...v1.0.2

v1.0.1

Choose a tag to compare

@github-actions github-actions released this 24 Sep 05:38

[1.0.1] - 2026-09-24

修 issue #19:在 @deepseek-ai/dsh@0.1.7-alpha.1+ 上启动不再打 settings registration failed: TypeError: settingsService.register is not a function。

Fixed

  • settings 命名空间改为按结构探测,不再假定 register 存在(host 半,需重启 dsh web):@deepseek-ai/dsh-settings 在 0.1.7 把服务从 SettingsProvider(有公开 register(ns, schema, options))换成 SettingsForms——服务同名、没有 register(0.1.7-alpha.1 / 0.1.7-alpha.2 的 npm tarball 逐字节核对过,无兼容入口),可编辑字段改由插件自报的 Config schema 派生、describe / update 按 profile 条目 id 寻址。此前 src/index.ts 直接调用 settingsService.register(...),在没有该方法的宿主上每次启动抛 TypeError;外层 catch 让它只是降级(回落 SIDEBARQA_DEFAULTS、追问链路照常)而不是崩溃,但日志里永远多一行失败。
    • 新增 src/settings-face.ts:openSettingsSeam(service, ns, schema) 用 typeof …register === 'function' 判定(结构校验,不是版本比较——与 client 半对 sidebarRightTabs / slots 的规则一致),返回 { ok: true, scope, face } 或带原因的拒绝 { ok: false, reason: 'service-missing' | 'no-register' | 'register-failed', error? };探测本身绝不抛(它跑在 cordis inject 回调里,抛出即启动期故障)。describe / update 也各自探测,并补 Array.isArray 校验。
    • 宿主没有 register 时只记一条 console.info(说明该宿主把可编辑字段交给插件 Config schema、本插件因此走默认值),不再是 warn + 堆栈;只有 register 真的被拒(命名空间重复等)才 warn。
    • config.update 的 503 文案改为如实描述:原来的「the settings service is not mounted in this deployment」在 0.1.7 上是误导——服务在,缺的是 register。
    • src/context-types.ts 的 SidebarqaSettingsService 镜像补上出处与「0.1.7+ 没有 register」的说明,避免下一个人再按版本假设这个成员存在。
    • 0.1.7+ 上设置页仍不可写(回落默认值):保留设置卡需要按新模型重做(导出带 volatile 的 Config 并按条目 id 寻址),属于单独一条,不在本次范围。
    • 回归用例 tests/settings-face.spec.ts(12 例):0.1.7 形状必须被判成 no-register 且不触碰 describe / update;provider 形状必须转发 ns/schema、读回 value + revision、把 expectedRevision 透传下去;describe 返回非数组 / 无该命名空间 / 缺 update 都必须降级而不是抛;另有一条接线守卫——src/index.ts 必须走 openSettingsSeam,且不得再出现 settingsService.register。
  • engines.dsh 已是 >=0.1.2-alpha.1(issue #14 的建议早已落地),#19 里「建议顺带补 engines.dsh」那句属过时信息。

Full Changelog: v1.0.0...v1.0.1

v1.0.0

Choose a tag to compare

@github-actions github-actions released this 20 Sep 10:51

[1.0.0] - 2026-09-20

首个 1.x:只注册进 DSH 自带右侧栏,零额外依赖。 走 major 的原因只有一条——移除了 dsh-better-sidebar 后端(### Removed 一节):升级后不再需要任何 peer 侧边栏基座,装 dsh-sidebar-qa 一个包即可;此前依赖 better-sidebar 的部署请一并卸掉它。

Added

  • 只注册进 DSH 自带右侧栏(@deepseek-ai/dsh-client-ui-sidebar-right,DSH ≥ 0.1.5-alpha.1):本版本移除 dsh-better-sidebar 兼容,插件只有一个侧边栏后端,且不需要任何额外依赖。
  • 三阶段注册,共用一个实现 id:① 类型进 ctx.sidebarRightTabs.register({ id, kind, priority: 'extension', title, guide })(页面类型:无 patterns、无 multiple);② body 进 keyed 席位 sidebar.right.pane.tab;③ 活的标题进 keyed 席位 sidebar.right.pane.tab.title。后两者都是 ctx.slots.inject(name, () => ctx.slots.register({ name, key: id }, Component))——席位按实现 id 分发,不是按 kind;打开走 ctx.sidebarRight.openTab(kind, { params })。
  • 标题席位是新增能力:DSH 的 tab 标题只在打开时刻求值一次并写进布局记录、之后永不改写(上游也明确「没有标题注册时使用打开时捕获的文本」),所以以前已打开的 tab 会冻结在打开时的语言。注册一个组件到标题席位后,它订阅语言 revision 并在原处重渲染——已打开 tab 的标题现在跟随语言切换。宿主不声明该席位时回退为那个冻结字符串(陈旧但无害)。
  • +(guide)条目仍是可发现性的唯一来源:原生侧边栏的 + 控件只打开 guide 页,注册的类型靠 guide 条目暴露成可点胶囊;本插件为两个 tab 各注册一个条目(标题/说明按语言实时读取),新增 askGuideDesc / histGuideDesc 文案。
  • 配置面板有了归宿:迁入 DSH 官方设置页。它注册成一个 settings.section(注册逻辑在 src/client/settings-slot.ts,纯模块、可测;页面组件 src/client/settings-section.tsx 渲染 ConfigPanel),因此设置页左侧导航新增一整页「追问 / Follow-up」(文案键 cfgNavLabel / cfgSectionTitle / cfgSectionDesc),order: 30 —— 排在 DSH 自带各页(general 0 / models 10 / plugins 15 / agent-presets 20 / archived-sessions 25)之后。不再有齿轮弹窗。
    • 注册形态:ctx.slots.inject('settings.section', () => ctx.slots.register({ name: 'settings.section', id: 'sidebar-qa', order: 30, label: () => t('cfgNavLabel') }, ConfigSection));插槽注册表仍是 ctx.get() 探测(src/client/slots.ts,与侧边栏模块共用同一个探针)。
    • 为什么不是 plugins.item:该席位的契约明文写着它留给 ui-settings-plugins 那些 host-plane 配置页,并要求 bundle 的配置走 plugins.bundle.config;而那个插件页在没有受管 profile 的部署上整页不可用,会把配置入口一起带走。settings.section 永远可达。
  • 新增 client 纯模块 src/client/ask-mode.ts(resolveAskMode:面板视图模式;自 meta-quote.ts 搬出,后者随 better-sidebar 一起删除)与 src/client/show-session.ts(showSessionFirst:用 ctx.uiWorkspace.openSession 把目标会话切到屏幕上)。
  • 回归用例:tests/sidebar-native.spec.ts(重写)、tests/ask-mode.spec.ts(新增)、tests/settings-section.spec.ts(新增)。

Changed

  • inject 收窄为 ['sessions', 'remote', 'remote.session', 'workspaces'],betterSidebar 不再出现(它此前是硬依赖:任何没装 dsh-better-sidebar 的部署都会让整个插件不激活)。侧边栏服务 sidebarRightTabs / sidebarRight / slots 一律 ctx.get() 探测 + 监听 internal/service 重探,绝不写进 cordis inject——cordis 没有可选依赖,注入一个宿主不提供的服务会让 fiber 停在 PENDING,而 boot-client.ts 会让整个 web boot 抛错(白屏,不是降级)。三件套齐备才落定:只有注册表没有席位,tab 会出现但 body 渲染不出来。全都缺失时插件仍激活(浮层 + 「添加到对话」),只记一条 console.warn。
  • 面板不再感知侧边栏:AskPanel / HistoryPanel 删掉了「推 tab 标题」与「面板自愈展开」两个 effect(前者由标题席位承担,后者原生 openTab 自己会展开栏位),也删掉了 onTabActivated 订阅(原生路径上本来就是死代码)。面板现在只消费一个中性的「出现实例」SidebarqaTabOccurrence:{ tabId, revision, takeQuote(), openHistory(scope) }(src/context-types.ts)。revision 就是 navigation.revision——每次被导航到都递增,是「再次打开」唯一的信号(一次外部打开 = 一个新的出现实例,所以引文能重新递送)。
  • 跨会话手势统一走 src/client/show-session.ts:原生 openTab 只作用于已挂载的会话 surface(无 surface 时抛 no session surface is mounted),而导航后会话绑定要到下一次 React commit 才由 seat 的 useEffect 重新发布——同 tick 的 openTab 会静默打到刚离开的会话。现在先 uiWorkspace.openSession 切屏,随后用 openTabIn(sessionId, …)(DSH 自己 Tab 域的路径,静默但绝不会落错会话)跨帧重发并以 active() 确认;宿主没有 openTabIn 时退回跨帧 openTab,且检查期间没有更晚的导航接管。
  • id 与 kind 是同一个 SidebarTab 对象上的两个字段,打开时从被注册的那个对象读回 kind。「注册 ask 却打开 dsh-sidebar-qa:ask」这类分叉(placeTab 会抛 no tab type is registered as "…")因此不可表达。
  • engines.dsh 仍是 >=0.1.2-alpha.1(浏览器侧 RPC 走 ctx.remote.session 的下限),但 DSH 完全不校验 engines,所以它只是声明、不是闸门;真正的前置是侧边栏 tab 需要 DSH ≥ 0.1.5-alpha.1。更早的 DSH 上插件仍然激活,只是不注册侧边栏 tab。
  • dsh.client.inject(包名依赖边)保留:它是纯信息性的声明,不决定加载顺序,缺失会被静默跳过,不是版本硬约束。
  • src/context-types.ts 随之收敛:删掉端口/桥/两后端相关类型,SidebarqaTabComponentProps 只保留 tab.id + 可选的 sidebar 出现实例,新增原生侧边栏、slots、uiWorkspace、webRuntime 的服务面镜像并挂 Context augmentation;与上游的漂移仍然只收敛在这一个文件。

Removed

  • peer 依赖 dsh-better-sidebar 及其 peerDependenciesMeta 条目(package.json)。
  • pnpm-workspace.yaml:两条 dsh-better-sidebar 的 minimumReleaseAgeExclude,以及整个 allowBuilds 块(node-pty / protobufjs 只因 better-sidebar 才在依赖图里);pnpm-lock.yaml 重生成后二者已完全消失。
  • 源文件:src/client/sidebar-port.ts(端口契约 + 后端探测)、sidebar-install.ts(后端选择与安装)、sidebar-better-sidebar.ts(适配器)、ensure-panel.ts(面板收起自愈——原生 openTab 自己展开栏位)、tab-activation.ts(onActivate 桥——navigation.revision 取代)、meta-quote.ts(resolveAskMode 搬到 ask-mode.ts,引文形状校验改在 sidebar-native.ts 的 quoteOfNavParams 里)。
  • 测试:tests/sidebar-port.spec.ts、sidebar-seam.spec.ts、sidebar-better-sidebar.spec.ts、ensure-panel.spec.ts、tab-activation.spec.ts、meta-quote.spec.ts。
  • 文档:docs/better-sidebar-expand-feature-request.md(该功能请求随 better-sidebar 一起作废)。
  • 随旧后端一起作废的还有 issue #16(PR #17 曾按「panelOpen 缺席 = 原生时代」修过这条路径):那个 bug 出在 ensure-panel.ts 的宽屏判定上——better-sidebar ≥ 0.19 把右栏交给 DSH 原生 Sidebar 后,插件只剩底部工作台一棵树,而它的 activePane 恒为底部叶子,于是每次「提问」都会在原生侧栏之外再强行打开底部面板。1.0.0 已不存在任何旧面板自愈(ensure-panel.ts / tab-activation.ts 一并删除),该问题在结构上不可能再出现;这段记录是说明为什么不把 #17 的补丁带进来,而不是漏合。

Fixed

  • 侧边栏的 tab 图标没了:+ 页(guide)的胶囊画的是宿主的方块占位,tab 条上只有裸文字。原生改造(1.0.0 的重构)把图标整个丢了——旧的 better-sidebar 注册里写着 icon: (size) => <IconQuestionOutline14 size={size} />(追问)与 IconQueueOutline14(追问记录),而新的 SidebarTab 描述里没有这个字段。宿主的两处放置都会在缺省时回退到别的东西(guide 胶囊 → 自己的方块占位 GuideBody.tsx:48,59;tab chip → 裸标题),所以缺图标不是「朴素」,而是别人家的占位符。现修:
    • SidebarTab 新增必填 icon: ComponentType<IconProps>,index.tsx 两个 tab 分别用回 IconQuestionOutline14 / IconQueueOutline14(宿主自带图标集,走平台模块表,不引入其它特性插件的值)。
    • guide 胶囊:guide[].icon 直接传该 glyph。
    • tab chip:布局记录里的标题只是字符串,图标不可能随标题捕获,所以 glyph 由活标题席位渲染——titleFor 现在返回 Fragment(glyph, title)(与宿主自己的 chip 标题 GuideTitle.tsx 同构),glyph 的样式在新的 src/client/tab-title.module.css(flex: none + color: var(--dsw-alias-label-tertiary),与宿主一致)。
    • 顺带修掉一处镜像漏声明(同一类:镜像自己就是唯一声明,漏了编译器不会报,运行时静默丢):context-types.ts 的 SidebarqaSidebarRightGuideEntry 没有 icon(上游 tab-registry.ts:79),所以即便传了也无处安放。现已补上并注明出处;IconProps 直接从宿主包里 import type,不再二次镜像。
    • useLocaleRevision 的 useSyncExternalStore 补上第三个参数(server snapshot):缺它时任何服务端渲染都会抛 Missing getServerSnapshot,也让标题席位在 node 环境无法验收。活动语言 id 是稳定原语,正是服务端渲染该读的值。
    • 回归用例:tests/sidebar-native.spec.ts(guide 条目必须带 tab 的 glyph;活标题席位必须渲染「glyph 在前、标题在后」)。
  • 「全量继承」追问会让面板全白且不可恢复(本轮实测发现,根因是一条上游 prop 改名)。MarkdownText 的本地化文案 prop 从 codeLabels 改名成了 labels(MarkdownLabels = { code: { copyLabel, copiedLabel }, footnotes },改名发生在 DSH 0.1.2-alpha.2 之前),而宿主渲染器读 labels.code.copyLabel 时没有任何守卫(ui-primitives/src/markdown/render.tsx:400)。本插件一直在传已退役的 codeLabels,于是 labels 为 undefined —— 任何一条含围栏代码块的消息只要被渲染就抛 TypeError。这解释了为什么它看起来是「全量继承特有的」:继承会把主导对话的整段历史(写代码的对话,满是代码块)画进面板,而普通追问的回答常常是纯文字。异常逃出席位后被 abdicate(ui-slots/src/index.ts:1541),本插件的 tab body 因此在整页所有会话上被永久摘除——只能刷新。
    • 现在传 labels(AskPanel 的 markdownLabels,按 locale memo:MarkdownText 以它的引用身份缓存流式渲染),新增文案键 mdFootnotes(脚注小节标题),退役的 codeLabels 从代码里彻底删除。
    • 为什么此前 tsc 报不出来:类型来自 devDependency 桩 @deepseek-ai/dsh-client-ui-primitives,其范围写的是 ^0.1.0-rc.8,而带预发布的 semver 区间永远匹配不到另一个 patch 的预发布版本(0.1.6-alpha.2 不满足 ^0.1.0-rc.8,也不满足 >=0.1.2-alpha.2)——桩因此被永久冻结在改名之前的 API 上,编译器一直拿旧契约校验新代码。现把 devDependency 精确钉到 0.1.6-alpha.2(与运行中的 DSH 一致),peer 只声明下限 >=0.1.2-alpha.2;pnpm-workspace.yaml 新增 peerDependencyRules.allowedVersions(该桩 peer 了一个本包从不链接的 @deepseek-ai/cordis 副本,cordis 由平台模块表提供)。lock 随之去掉旧桩那条重依赖图(katex / micromark / mdast 一族,约 860 行),新桩自身零依赖。
    • 回归用例:tests/markdown-labels.spec.ts 直接钉住装好的桩(必须声明 labels:、必须不再有 codeLabels: 属性),把「范围悄悄退回预发布旧版 → 类型检查重新放行」这条路堵死。
  • 面板里的任何渲染错误都不再可能让 tab body 整页失效:新增本插件自己的错误边界(src/client/panel-boundary.tsx,挂在 sidebar-native.ts 的 bodyFor 最外层):崩溃被就地渲染成一条可重试的说明条(errPanelCrashed / panelCrashHint / 复用 commonRetry),标签页本身留着;切换会话(resetKey = sessionId)会自动清掉崩溃面。containPanel(resetKey, Panel, props) 接收组件而不是现成元素,因此「把面板当普通函数调用」这种会让边界失效的写法(本节第一条修 bug 时我自己就先写成了这样)变成类型错误;测试另有一道 wiring 守卫(tests/panel-boundary.spec.ts:bodyFor 必须 return containPanel(props.sessionId, tab.component, bodyProps),且不得再出现 tab.component(bodyProps))。注:React 的服务端渲染器不咨询错误边界(直接 rethrow),因此containment 在 node 环境以元素结构断言,而非渲染。
  • 在「追问」页点到一条已被归档 / 已删除的追问,会让面板内容整块消失、而且再也调不出来(本轮实测发现)。根因是插件自己维护的 localStorage 父子映射不会随 DSH 侧的归档/删除清理:切换条里的陈旧行照旧可点,点下去就是把面板切到一段读不出内容的会话上(正文永远停在「生成中…」);更糟的是这类 id 一旦被拿去导航,uiWorkspace.openSession 会先把它 retain 成主视图,DSH 自己的导航策略随后再把它丢掉(ui-workspace/src/client/navigation.ts:287-301 的 clearArchivedCurrent → clearMain),主视图与整个右栏一起失效——用户正在读的面板随之消失。三处一起修(均为 client 半):
    • 切换条逐条分类:新增纯函数 followUpAvailability / isFollowable / lastFollowableFollowUp(src/client/history-scope.ts)。已归档 / 已删除的追问保留可见(映射行还在,DSH 侧恢复归档后立刻可用)但置灰不可点,并标注「已归档 / 已删除」——与「追问记录」的陈旧行同一套语言。面板的默认选中也改为「最新一条可读的追问」,不再默认落到一条读不出的会话上。
    • 选中项在阅读时被归档:正文改为明确的说明文案 + 「移除」(只清插件自己的映射,DSH 侧会话不动),输入框、策略、模型座与发送键一并停用。不再有「面板开着却什么都没有、也不知道为什么」的状态。
    • 导航入口补围栏:sidebar-native.ts 切屏前先读 workspaces.list 的 archivedSessionIds(isArchivedTarget),命中则只记一条 warn 并放弃这次手势,绝不把已归档会话 retain 成主视图;读不到 archive 集时一律当作「未归档」,围栏不会因为读不到输入而开始拒绝打开。
    • 分类特意不复用「追问记录」的 sessionStatus:行标签可以立刻把「feed 里还没有」写成「已删除」,而切换条一旦照此禁用,冷启动(phase !== 'ready')时就会把全部追问锁死。followUpAvailability 因此多出一个 unknown(feed 尚未 hydrate,按可用来处理)。
  • 宿主 useTabInfo 抛错会让本插件的 tab body 在整页范围内永久失效。DSH 的 keyed 席位错误边界对崩溃条目的处理是 abdicate(ui-slots/src/index.ts:1541:abdicated.add(entry))——把这条注册从席位上永久摘除,于是所有会话的这个 tab 一起变空白,重新打开也回不来(只能刷新页面),正是「内容完全消失且不能再调出」。而 tab-info.ts:35 抛的 tab "<id>" is not committed in session "<id>" 是宿主自己就可能瞬时产生的状态(布局提交与渲染不一致)。现在 body 读取该 h...
Read more

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 29 Aug 08:26

[0.5.0] - 2026-08-28

Added

  • 划选浮层由一个按钮拆成两个(issue #11):
    • 「添加到对话」(新增):把划选文本以 Markdown > 引用块追加进当前会话的主输入框(composer),聚焦并把光标停在引用块下方的空行——不新建会话、不打开也不展开侧边栏。适合「引用这段话,我就在主对话里接着说」,与开一个独立追问会话互为轻重两条路。
    • 「提问」:文案与行为逐字节不变(存 pending 引文 + openTab({ type: 'dsh-sidebar-qa:ask' }))。之所以没有按 issue 原文改名「侧边聊天」,是因为 dsh-better-sidebar 0.16.x 自己就有一个叫 Side Chat / 侧边聊天的视图,改名会与上游功能撞车。
    • 引用块格式:逐行加 > 前缀(选区内的空行渲染成裸 >,否则一个引用块会被截断成两个);块尾留一个空行,所以光标落在引用块外面——紧贴 > x 下一行写字在 Markdown 里属于 lazy continuation,会被吸进引用块里。
    • 追加而非覆盖:输入框里已有的内容一个字都不动,引用块空行分隔接在后面;连点两次会追加两个引用块(刻意不做幂等)。
    • 走 DSH ui-conversation 的 conversation 服务(ctx.get('conversation') → input.for(scope).setDraft),与 dsh-better-sidebar 资源管理器的 @ 文件引用是同一条路径,没有任何 DOM hack。
    • 新增纯模块 src/client/quote-draft.ts(引用块格式化 + 草稿合并)与薄接线模块 src/client/draft-insert.ts,各自带单测(tests/quote-draft.spec.ts 21 例、tests/draft-insert.spec.ts 12 例)。

Changed

  • src/context-types.ts 增补 conversation 服务的结构化镜像(SidebarqaConversationService / SidebarqaSessionInput)并挂上 Context augmentation——与上游的漂移仍然只收敛在这一个文件里。声明它同时让 ctx.get('conversation') 返回有类型的服务面而不是 any(cordis 把 get 定义为 <K extends string & keyof this>(name: K) => this[K] | undefined)。
  • 新增文案键 askAddToConversation(zh 添加到对话 / en Add to chat)。askPopoverButton 与三条提到「提问」的空状态提示均未改动。

降级契约

conversation 服务缺失(没装 ui-conversation 的部署)、会话 scope 解析不到、或调用链上任意一处抛错 → 「添加到对话」记一条 console.warn 后什么都不做,并且保留划选与浮层,用户可以改点「提问」。插件本身、浮层、以及原有的追问流程都不受影响;conversation 没有进 inject,所以它的缺席不会让插件不激活。

部署提醒:仅 client 半改动,浏览器硬刷新即可,无需重启 dsh web。
已知限制:输入框里已有的 @ 引用 chip 会在这次写入中被降级成纯文本——setDraft 是 composer 唯一的公开写入路径,它按纯文本重建整棵节点树(dsh-better-sidebar 的 appendToDraft 有同样的行为)。输入框为空时(最常见路径)完全不受影响。

Full Changelog: v0.4.2...v0.5.0

v0.4.2

Choose a tag to compare

@github-actions github-actions released this 28 Aug 16:39

[0.4.2] - 2026-08-28

Changed

  • package.json 新增 engines.dsh: ">=0.1.2-alpha.1"(issue #14):0.4.1 起浏览器侧 RPC 走 DSH 的 Remote 服务(ctx.remote.session),该服务首次落地于上游 dsh-v0.1.2-alpha.1。此前这个前置条件只写在 release notes 里,机器读不到;现在成为清单里的显式声明,供市场 / CLI / CI 在安装前校验(配套提案见 dsh-market#404)。

    注意这是声明而非闸门:npm / pnpm 的 engines 只校验 node(及包管理器自身),未知键会被忽略;dsh plugin --profile web add 又是 pnpm 的薄转发。真正的安装前拦截需要市场 / CLI 侧消费该字段。在此之前,早于 0.1.2-alpha.1 的 DSH 上本插件因 inject 解析不到 remote 而静默不激活(无 UI、无报错),请留在 0.4.0。

  • dsh.plugin.json(plugin-registry 渠道清单)的 engines.dsh 由 >=0.0.1 同步为 >=0.1.2-alpha.1:该字段此前是一条陈旧声明(写于插件还没有任何宿主版本要求的时候),按 registry 清单做校验的消费方会读到「任何版本都行」,与 package.json 的声明互相矛盾。两份清单现在给出同一个下限。
  • dsh-better-sidebar peer 依赖由 ^0.16.0 放宽为 >=0.16.0:caret 对 0.x 只放行同一 minor(>=0.16.0 <0.17.0),而上游迭代快于本插件——better-sidebar 发到 0.17.0 时本插件会平白无故解析失败,尽管并没有任何已知不兼容。改为只声明下限,若将来某个版本确实破坏兼容再收窄上限。

部署提醒:本版仅清单与依赖声明改动(engines.dsh、peer 范围),无运行时代码变化;已安装用户无需重启。但早于 DSH 0.1.2-alpha.1 的宿主上插件会静默不激活(与 0.4.1 行为相同),请留在 dsh-sidebar-qa@0.4.0。

Full Changelog: v0.4.1...v0.4.2

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 28 Aug 12:17

[0.4.1] - 2026-08-28

Fixed

  • 版本兼容(issue #12):dsh-better-sidebar peer 依赖由 ^0.14.0 调整为 ^0.16.0,正式声明兼容 0.16.x(本次 Remote 迁移正源于该版本线的上游重构);0.14.x / 0.15.x 不再被 peer 解析。

  • 追问面板整块报错 dsh-better-sidebar: Cannot read properties of undefined (reading 'sessions'):DSH 上游把浏览器侧 RPC 从 ctx.connection.api 迁到了类型化 Remote 服务 ctx.remote(refactor(connection): own RPC transport contracts 删掉了 ConnectionHandle.api;refactor(client): consume migrated Remote namespaces 把各命名空间挂成独立 cordis 服务)。本插件的 11 处调用点全部落在那个已消失的对象上,其中 ModelSelect 的挂载 effect 是同步取值,因此直接被 better-sidebar 的单 tab 错误边界捕获、整块渲染成错误条。现已全量迁移到新接口:

    旧 新
    connection.api.sessions.create / fork / rename / selectModel / prompt ctx.remote.session.*(信封由 {result:{ok,…}} 改为扁平 {ok,…};prompt 新增必填 requestId,由客户端生成 UUID v4)
    connection.api.sessions.models({sessionId}) ctx.remote.session.modelCatalog()(Host 级目录,无会话地址)+会话的 modelSelection projection(当前选择改为订阅而非轮询,主对话或 /model 改模型会自动同步到座位)
    connection.api.sessions.history({sessionId}) 每 1.2s 轮询 ctx.remote.session.follow() 实时流(开窗 + 增量帧)+ session.page() 向上翻页。追问回答现在是真流式,不再等轮询节拍
  • inject 增补 remote / remote.session,并且两个 tab 组件改为接收本插件自己的 ctx(此前用的是 better-sidebar 传下来的 ctx——cordis 只解析各自 plugin 注入过的服务,而 better-sidebar 并未注入 remote,沿用会再次拿到 undefined)。

Added

  • 新增纯模块 src/client/session-wire.ts(含 tests/session-wire.spec.ts,20 例):Remote 信封拆封、requestId 生成、把 wire 上打包的 assistant delta run(chunkrow/text-chunks 等)还原成逐 seq 的 assistant/chunk 事件——因此 answer.ts 的折叠逻辑与其全部单测保持零改动——以及重开 follow 时按 seq 合并窗口(避免覆盖已向上翻页的继承历史)。
  • projection 读取抽成共享的 src/client/use-projection.ts,上下文占用环与模型座位共用一条路径。

部署提醒:仅 client 半改动,浏览器硬刷新即可,无需重启 dsh web。
前置条件:本版本要求 DSH 已包含上述 Remote 迁移(0.16.x 系 DSH);在更早的 DSH 上请留在 0.4.0。
已知上游问题:dsh-better-sidebar 0.16.1 的 Side Chat 视图仍在调用 ctx.connection.api.sessions.history,在同一版 DSH 上打开该 tab 会报同样的错——那是上游代码,不在本插件范围内。

Full Changelog: v0.4.0...v0.4.1

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 21 Aug 12:56

[0.4.0] - 2026-08-21

Added

  • 中英双语(i18n):界面文案与模型侧提示词都跟随 DSH 的语言设置(locale.preference > 浏览器语言 > en)实时切换,无需刷新。
    • 界面词表在 src/client/locales.ts(zh 为键集基准,en 由 Record<CopyKey, string> 类型标注锁定;单测另有键集平价、空值与占位符一致性检查),并通过 ctx.locale 注册进 DSH 的 sidebarQa 命名空间。locale 服务为软依赖:缺失时插件照常工作,回退浏览器语言。
    • 模型侧词表在 src/prompt-locale.ts:追问引导语、上下文压缩与标题系统提示,以及提示词指名引用的结构标记(用户:/助手:、【背景】、问题:)作为一个原子单元同进同退(单测断言这一配对)。
    • 已打开的 tab 标题同样跟随切换:better-sidebar 的 tab 标题是持久化定值,面板改为在语言变化时回推 updateTab 自愈。
  • 明确的回答语言策略:提示词现在显式要求「用与用户提问相同的语言作答;问题语言不明确时跟随划选文本」——回答语言跟内容走,不跟界面语言走(与 DSH 官方 session-title 同款策略)。此前得到中文回答只是「提示词恰好是中文」的副作用。

Changed

  • 追问会话标题去掉「追问」二字:❓追问·<主题> → ❓<主题>。emoji 本身已足够标记追问会话,去掉后该处不再需要翻译,也不会因切换语言而出现混合语言前缀。已有会话的标题不会被追溯重命名。
  • 占位主题的截断预算按文种自适应:含 CJK 取 12 字,纯拉丁取 24 字(TOPIC_MAX_LEN / TOPIC_MAX_LEN_LATIN)——12 个拉丁字符只有两三个词,此前会截在词中间。判定依据是被划选文本的文种,不是界面语言。
  • /sidebarqa/api/context 与 /sidebarqa/api/title 新增可选 locale 字段('zh' | 'en'):host 侧没有语言信号,由 client 下发当前 DSH 语言。字段缺省等价于 zh,旧版 client 打到新 host 行为与今日逐字节一致;无法识别的语言一律落 en,永不抛错。压缩摘要缓存键加入 locale 维度,切换语言后不会继续命中旧语言的摘要。
  • 面板内的宿主错误提示改为「本地化前缀 + 原始英文详情」(追问失败 / 保存失败 / 模型加载失败),此前直接裸露英文原文。

Fixed

  • 追问记录的相对时间标签此前恒为中文;现在跟随语言(en 使用 5m / 3h / 2d 等紧凑缩写,规避复数形态)。

部署提醒:host 半与 client 半都有改动——需重启 dsh web,再硬刷新浏览器。只刷新不重启会短暂得到「英文引导语 + 中文压缩提示词」的混合状态(功能正常,仅提示词语言不一致)。
已知外观差异:dsh-better-sidebar 插件目录中对本插件的描述仍写作 ❓追问,属上游只读文案,不影响功能。

Full Changelog: v0.3.2...v0.4.0