Repository navigation
Releases: hytime/dsh-thinking-effort
Release list
v0.3.11 — Subagent default effort now overrides the inherited parent level
修复 / Fixed
- 修复子 agent 默认档位在请求已带父会话继承档位时被忽略:旧逻辑把任何已存在的档位当作显式指定而直接返回,导致父会话已选定档位、沿用其路由的子 agent 不使用配置值。未配置默认档位时仍不改动请求。
- Apply the configured subagent default effort to subagent requests that already carry the parent session's effort by inheritance: the guard treated any present effort as an explicit user choice, so a child that inherited a named effort on the same route never used the setting. An unset default still leaves the request untouched.
- 设置页配色改为优先使用 DSH 主题令牌(
--dsw-alias-*/--dsw-shadow-*),并在宿主未提供令牌时回退到原有 iOS 配色,因此启用主题插件后设置页不再与整体界面割裂。新增foreground令牌用于主按钮文字与开关滑块,避免在深色主题下用写死的白色。 - The settings page now prefers DSH theme tokens (
--dsw-alias-*/--dsw-shadow-*) and falls back to the previous iOS palette when the host exposes none, so it no longer clashes with the rest of the interface once a theme plugin is enabled. A newforegroundtoken drives primary-button text and the switch knob instead of a hard-coded white, which keeps them legible on dark themes.
文档 / Documentation
- 在「重要限制」补充说明:档位发送的值不一定代表 token 预算。部分网关把它当作提示词指令,会把
high/max/xhigh折叠成同一行为、把medium当作不附加说明,或在参数缺失时回退到自己的默认值;这类网关通常要把off填成none才真正关闭思考。 - Document that a level's value is not necessarily a token budget: some gateways treat it as a prompt instruction, fold
high/max/xhighonto one behaviour, treatmediumas saying nothing, or fall back to their own default when the parameter is absent. On those gateways anoffvalue ofnoneis usually what actually disables thinking.
本页在发布后补记了设置页主题令牌适配(PR #41)。该改动随本版本发布,但当时的 CHANGELOG 条目遗漏,此处补上以免升级者找不到外观变化的来源。
This page was amended after publication to record the settings-page theme-token change (PR #41). The change shipped in this version, but its changelog entry was missed at the time; it is recorded here so anyone wondering about the appearance change can trace it.
v0.3.10 — Session projection gap keeps the confirmed model and effort
修复 / Fixed
- 修复 Composer 在会话模型投影暂缺时回退到全局默认模型、导致档位刻度跳变及档位操作提交错误模型的问题;支持公开会话投影的宿主会保留已确认选择,主动切换仍立即生效。
- Fix Composer falling back to the global default model during session-selection projection gaps, which changed the effort scale and could submit an effort change for the wrong model. Hosts exposing the public session projection retain the confirmed selection while explicit switches remain immediate.
v0.3.9 — Model panel UX, first-open flash fix, and mobile layout
修复 / Fixed
- 修复首次展开模型选择面板时的定位闪现:面板打开时会用绝对定位元素替换原本参与布局的触发器,而定位 effect 原先用
useEffect,浏览器已经绘制了初始left: 0帧后才测量并写入补偿偏移,于是首帧会在触发器原来的右侧短暂闪现。改用useLayoutEffect,在绘制前完成测量。第二次打开时测量结果已存在,所以此前通常不会再现。 - Fix the composer model panel flashing at the wrong position the first time it opens: opening replaces the laid-out trigger with an absolutely positioned panel, and the positioning effect ran in
useEffect, so the browser had already painted an initialleft: 0frame before the measurement and compensating offset were written. It now usesuseLayoutEffect, which measures before paint. A second open rarely showed it because the measurement was already available. - 设置卡片在窄屏(手机竖屏)下溢出卡片边界、需要横向拖动才能看全:版面原先全部写成内联
style,而内联样式无法携带媒体查询,固定宽度与多列网格在窄屏不会重排。现在设置页的布局改为settings.module.css,按dsh-web-mobile使用的同一组断点重排:≤1023px 取消徽标区的固定轨道,≤767px 成对的字段降为单列、1M 开关移到字段下方独占一行,≤480px 标签与控件全部纵向堆叠、136/140/180px 的固定下限与 154px 徽标轨道一并释放。实测把卡片钉到 280px 宽时,原先越界的上下文长度行与输入能力行不再越界;320px 及以上与改动前一致。只作用于本插件自己的类,未使用!important,以免与dsh-web-mobile等改动核心 UI 的插件互相干扰。 - Fix the settings card overflowing its bounds on narrow screens, which needed horizontal dragging to read: the layout was written entirely as inline
styleobjects, and an inline style cannot carry a media query, so the fixed widths and multi-column grids never reflowed. The settings layout now lives insettings.module.cssand reflows on the same breakpointsdsh-web-mobileuses: ≤1023px releases the badge cluster's fixed track, ≤767px collapses paired fields to one column and gives the 1M switch its own row, and ≤480px stacks every label above its control and drops the 136/140/180px floors and the 154px badge track. Pinned to a 280px card the context-length and input-capability rows — the two that used to stick out — now fit, and 320px and above are unchanged. The rules only ever touch this plugin's own classes and use no!important, so they cannot fightdsh-web-mobileor any other plugin that rewrites the core UI.
变更 / Changed
- 「模型能力与档位」面板保存后不再强制跳回页面顶部:保存触发的重新读取会保留当前模型列表(仅在首次读取、列表尚未加载时才显示加载占位),因此滚动位置和刚编辑的行保持不变。
- 成功提示改为钉在设置面板右上角的浮层,不再内联嵌在标题栏顶部;用
position: sticky实现——横向锁在面板内、纵向钉在视口顶部,面板里滚到哪里都一直可见,并在约 3 秒后自动消失(任何字段编辑都会清掉提示,所以再次保存会重新显示并重新计时)。 - 上下文长度输入现在接受用
k(大小写均可)按 1024 倍换算,例如64k等于65536;存储的仍是整数,错误提示已同步更新。 - The model capability panel (模型能力与档位) no longer jumps to the top after a save: the refresh a save triggers keeps the current model list mounted (the loading placeholder now appears only on the first read, before anything is loaded), so the scroll position and the row you just edited stay in place.
- The success notice is now a floating badge anchored to the settings panel's top-right corner instead of an inline pill in the page title. It uses
position: stickyso it stays pinned to the panel's right edge and visible no matter how far you scroll within the panel, and it fades out on its own after about 3 seconds (any field edit clears it, so a later save re-shows it and restarts the countdown). - The context length field now accepts
k(any case) as a ×1024 multiplier, so64kmeans65536; the stored value is still an integer and the validation message was updated to match.
v0.3.8 — pnpm toolchain, DSH 0.2.1 compatibility window, and audit fix
兼容性 / Compatibility
- 版本映射最新窗口的上界由
0.2.1-0扩展到0.2.2-0,使 DSH0.1.7至0.2.1落在同一个已验证窗口内。0.2.1-alpha.1相对0.2.0-rc.2逐一核对过插件读取的每个 API:设置控制器、configForms、plugin-compatibility、语言包、模型目录、conversation.input.model座位契约(仍是{ locked })以及modelDirectories/remote.session两个面均逐字节相同,pi-ai 仍为 0.87.1 且各 gate 的 offer 集合不变(completions 19 / responses 4 / anthropic 7 / bedrock 1,新增的mistral-conversations依旧 offer 0 个字段)。该版本的破坏性变更也不触及本插件:不导入任何./invariant入口、不注册输入区统计扩展,且以包根说明符而非子路径说明符被配置(新规则下只有包根说明符会读取其导出的package.json)。此前0.2.1落在窗口之外(未映射),插件仍可工作但会退化为跟随运行时报告的能力;现在它与0.1.7走同一条已验证路径。 - Extended the newest version-map window's upper bound from
0.2.1-0to0.2.2-0, so DSH0.1.7through0.2.1resolve inside one verified window. Every API this plugin reads was checked file by file against0.2.0-rc.2: the settings controller,configForms,plugin-compatibility, the locale pack, the model directory, theconversation.input.modelseat contract (still{ locked }) and themodelDirectories/remote.sessionfaces are byte-identical, pi-ai stays at 0.87.1 with identical per-gate offered field sets (completions 19, responses 4, anthropic 7, bedrock 1; the addedmistral-conversationsgate still offers none). The release's breaking changes also miss this plugin: it imports no./invariantentry, registers no input-stats extension, and is configured as a package-root specifier rather than a subpath specifier, which under the new rule is the only form that still reads its exportedpackage.json. Previously0.2.1fell outside every window (unmapped): the plugin still worked, but degraded to following the capabilities the running host reports. It now takes the same verified path as0.1.7.
变更 / Changed
- 仓库工具链从 npm 迁移到 pnpm:
package-lock.json移除,改提交pnpm-lock.yaml与pnpm-workspace.yaml,CI 与发布 workflow 改用pnpm install --frozen-lockfile、pnpm run ...、pnpm pack、pnpm audit,setup-node的缓存改为pnpm,锁文件缓存与审计门禁保持不变。工作流守卫test:release也加入 PR 阶段的 CI,使发布 workflow 的结构断言在合并前就被检查。 - Migrated the repository toolchain from npm to pnpm:
package-lock.jsonis removed in favour of committedpnpm-lock.yamlandpnpm-workspace.yaml, and CI and the publish workflow now usepnpm install --frozen-lockfile,pnpm run ...,pnpm pack, andpnpm audit, withsetup-nodecaching switched topnpm; the lockfile cache and the audit gate are unchanged. Thetest:releaseworkflow guards now also run in pull-request CI, so the publish workflow's structural assertions are checked before merge.
安全 / Security
- 迁移后在 pnpm 下重跑审计,把
source-map-js从 1.2.1 提升到 1.2.2(由开发依赖jsdom间接引入),并把vitest从 3.2.7 升到 4.1.11 —— 后者不再依赖tinypool,消除 2 条 critical 公告;pnpm audit --audit-level high现为 0 条。undici在迁移前已是 7.30.0,本次没有改动它。这些都在 devDependencies 内,不进发布包的运行时依赖图(发布包只依赖schemastery与yaml)。可选的--provenance与 OIDC 发布路径由 pnpm 11 原生实现并已在 workflow 中保留。 - After the migration, re-ran the audit under pnpm: raised
source-map-jsfrom 1.2.1 to 1.2.2 (pulled in transitively by the dev dependencyjsdom) andvitestfrom 3.2.7 to 4.1.11, which no longer depends ontinypooland so removes the 2 critical advisories;pnpm audit --audit-level highnow reports 0.undiciwas already 7.30.0 before the migration and is unchanged here. All of them sit in devDependencies and stay out of the published package's runtime dependency graph (which is onlyschemasteryandyaml). The optional--provenanceand OIDC publishing path is implemented natively by pnpm 11 and is preserved in the workflow.
v0.3.7 — Narrow-screen panel clamp, DSH 0.2.0 compatibility window, and audit fix
修复 / Fixed
- 修复 Composer 思考面板在窄屏上定位出界:面板锚定触发器右边缘向左展开 336px,手机上模型按钮贴着屏幕左边缘,面板大半被推出屏幕、滑杆基本点不到;CSS 的
min(336px, 100vw - 32px)只限宽度、限不了起始位置。现在面板打开时量一次触发器实际位置:原锚点位置放得进屏幕就保持不动(桌面行为完全不变),放不下时才把面板 clamp 到[16px, 视口宽 - 16px]区间内,窗口 resize 与页面滚动时重算。 - Fix the composer thinking panel overflowing the viewport on narrow screens: the panel is anchored to the trigger's right edge and opens 336px leftward, so on phones — where the model button sits flush against the left edge of the screen — most of the panel lands off-screen and the slider is essentially untappable; the CSS
min(336px, 100vw - 32px)bounds the width but not the starting position. The panel now measures the trigger's actual position on open: the original anchor is kept whenever it fits the viewport (desktop behavior is unchanged), and only when it overflows is the panel clamped into[16px, viewport width - 16px], recomputed on window resize and page scroll.
安全 / Security
- 把开发依赖
jsdom间接引入的undici从 7.29.0 提升到 7.30.0,修复npm audit报出的高危项(含 TLS 证书校验绕过 GHSA-w293-vg96-wgc3 等 2026-09-29 批次公告)。这些是 devDependencies,不进发布包的运行时依赖图(发布包只依赖schemastery与yaml),因此对插件使用者没有暴露面;但 CI 的npm audit --audit-level=high在qualityjob 内,publish依赖它,不修会挡住下一次发布。@vitest/mocker的 2 个 moderate 仍在,修复需要vitest@5(破坏性变更),故不在本次范围内。 - Raised
undici— pulled in transitively by the dev dependencyjsdom— from 7.29.0 to 7.30.0, clearing the high-severity findingsnpm auditreported (including the TLS certificate-validation bypass GHSA-w293-vg96-wgc3, part of the 2026-09-29 advisory batch). These are devDependencies and do not enter the published package's runtime dependency graph (which is onlyschemasteryandyaml), so there is no exposure for plugin users; butnpm audit --audit-level=highruns inside CI'squalityjob, whichpublishdepends on, so leaving it unfixed would block the next release. The two moderate@vitest/mockerfindings remain, since fixing them requiresvitest@5, a breaking change, and are out of scope here.
兼容性 / Compatibility
- 版本映射的最新窗口上界由
0.1.8-0扩展到0.2.1-0,使 DSH0.1.7至0.2.0整段落在同一个已验证的窗口内。0.2.0-rc.2相对0.2.0-rc.1逐一核对过插件依赖的 API:设置控制器、configForms、plugin-compatibility、语言包与模型目录等文件逐字节相同,pi-ai 的compatProfile亦未变;该版本新增的mistral-conversations协议在COMPAT_GATES中提供 0 个字段,且不在llm-pi-ai的PROTOCOLS里,用户路由无法声明它,因此不改动插件的 18 字段集合。此前0.2.0落在窗口之外(未映射),插件仍可工作但会退化为跟随运行时报告的能力;现在它与0.1.7走同一条已验证路径。 - Extended the newest version-map window's upper bound from
0.1.8-0to0.2.1-0, so DSH0.1.7through0.2.0all resolve inside one verified window. Against0.2.0-rc.1,0.2.0-rc.2was checked file by file on every API this plugin depends on: the settings controller,configForms,plugin-compatibility, the locale pack and the model directory are byte-identical, and the pi-aicompatProfileis unchanged; the one protocol that release adds (mistral-conversations) offers no field inCOMPAT_GATESand is absent fromllm-pi-ai'sPROTOCOLS, so a configured route cannot name it and the plugin's 18-field set is untouched. Previously0.2.0fell outside every window (unmapped): the plugin still worked, but degraded to following the capabilities the running host reports. It now takes the same verified path as0.1.7.
v0.3.6 — DSH 0.1.7 API alignment and gateway compat fields
新增 / Added
- DSH
0.1.3-alpha.2新增三个网关兼容字段:thinkingTokenBudgetField(completions)、数值型vllmPriority(completions)和supportsMaxOutputTokens(Responses)。插件现在会像其它 compat 字段一样暴露并写入它们,因此 0.1.3-alpha.2 及更高版本可配置的标量字段由 15 个增加到 18 个。由于supportsMaxOutputTokens只在 Responses 协议下提供,openai-completions不再提供全部字段:它支持除该字段以外的 17 个。 - DSH
0.1.3-alpha.2added three gateway compat fields:thinkingTokenBudgetField(completions), the numericvllmPriority(completions), andsupportsMaxOutputTokens(Responses). The plugin now surfaces and writes them like every other compat field, which takes the configurable scalar fields from 15 to 18 on0.1.3-alpha.2and later. BecausesupportsMaxOutputTokensis offered only on the Responses protocols,openai-completionsno longer offers every field: it supports the 17 others. - 设置页的写入在 DSH
0.1.7及更高版本上改走ctx.configForms的官方串行化写入队列与 revision 护栏。此前面板自行维护「冲突后重读并重试一次」的逻辑;官方表单服务本身已带串行队列、版本护栏与拒绝后的重读,首次写入因此不再由面板用挂载时读到的 revision 自己围栏(表单按它自己跟踪的 revision 判断),但重建仍需要表单快照不具备的完整描述符(库存的value.providers、可编辑 compat 字段的schema),所以写入被拒绝后仍会重读并重建一次。0.1.0-rc.7到0.1.6等更早的宿主没有该服务,仍走原来的describe/mutate路径,行为完全不变(含原有的冲突重试)。新路径上写入被拒绝时界面显示通用的「保存失败」文案:表单的mutate只返回一个布尔值,没有可原样呈现的宿主消息,编造原因或假装成功都不如实报告。 - Settings writes on DSH
0.1.7and later now go throughctx.configForms's official serialized write queue and its revision fence. The panel previously carried its own "re-read and retry once after a conflict" logic; the official form service already owns a serialized queue, a revision fence and a post-refusal re-read, so the first write is no longer fenced by the panel against the revision it read at mount (the form fences against the revision IT tracks); a rebuild still needs a full descriptor the form snapshot does not carry (value.providersfor the inventory,schemafor the editable compat fields), so a refused write is still re-read and rebuilt ONCE. Older hosts —0.1.0-rc.7through0.1.6— expose no such service and keep the originaldescribe/mutatepath with unchanged behaviour, retry included. On the new path a refused write surfaces the generic "save failed" text, because the form'smutateanswers with a bare boolean: there is no host message to render verbatim, and inventing a reason or pretending success would be less honest than reporting the failure.
兼容性 / Compatibility
- 在
peerDependencies声明@deepseek-ai/dsh >=0.1.0-rc.7(与既有engines.dsh同范围)并标为optional。这是唯一被 DSH 运行时读取的版本兼容声明:dsh-app-boot的evaluatePluginCompatibility只检查@deepseek-ai/dsh/@deepseek-ai/dsh-*形式的 peer,且不兼容时会在启动路径上抛错。此前插件没有任何这类 peer,该检查直接返回undefined,等于没有版本声明。标optional不影响该判定(判定函数不读peerDependenciesMeta),但缺少它时 npm 会尝试解析整个 DSH CLI 依赖树,实测会挂起超过 300 秒。 - Declared
@deepseek-ai/dsh >=0.1.0-rc.7(the same range as the existingengines.dsh) inpeerDependencies, markedoptional. This is the only version-compatibility declaration the DSH runtime reads:dsh-app-boot'sevaluatePluginCompatibilityinspects only@deepseek-ai/dsh/@deepseek-ai/dsh-*peers and throws on the startup path when they are incompatible. The plugin previously declared no such peer, so that check returnedundefined— no version declaration at all. Theoptionalflag does not weaken that verdict (the check never readspeerDependenciesMeta), but without it npm tries to resolve the whole DSH CLI dependency tree, which was measured hanging beyond 300 seconds.
文档 / Documentation
- 修正 Composer 座位优先级的描述:
conversation.input.model是单占位槽,胜者按优先级升序取第一个,因此priority: -10是有意压过官方模型选择器,而非「让位」给后者。原注释与 README 的表述方向相反,代码行为一直正确,本次只改文字以免后人按错误注释改动优先级。 - Fix the composer seat's priority description:
conversation.input.modelis a single slot whose winner is the FIRST entry in ascending priority order, sopriority: -10deliberately shadows the shipped model selector rather than yielding to it. The comment and README said the opposite; the behaviour was always correct, and only the wording changes so nobody "fixes" the priority into a behaviour change.
v0.3.5 — Fix the reasoning range allowing only one step per drag
修复 / Fixed
- 修复推理等级滑块一次只能拖动一格:官方模型目录的
select()是async函数,在第一个await之前就同步把状态置为selecting,面板把这个状态计入「忙」并禁用了原生 range,浏览器随即停止上报本次拖动的后续输入。服务本身是为连续选择设计的——每次select()取一个 generation,只有最新一次响应会生效,失败与成功两条路径都会清空pending——所以禁用一个连续控件属于 UI 层的语义错配。现在只有面板被锁定或根本没有select时才会禁用滑块,离散控件(模型行与选项)保留原有的忙态。滑块是受控输入,因此位置改读目录 store 的pending:那是select()同步写入的、宿主已接受但尚未确认的选择,在早于该字段的目录上回落到current;只做前一步会让滑块在拖动中途弹回宿主的旧值。面板只读pending而从不写入它,仍是宿主 store 的一个视图。 - Fix the reasoning range allowing only one step per drag: the official model directory's
select()is anasyncfunction, so it sets the status toselectingsynchronously at the top, before the firstawait, and the seat counted that as busy and disabled the native range — at which point the browser stops reporting the rest of the drag. The service is built for continuous selection: everyselect()takes a generation, only the newest response is applied, and both the success and the failure path clearpending. Disabling a continuous control was therefore a UI-layer mismatch. The range is now disabled only when the seat is locked or has noselectat all, while the discrete controls — the model row and its options — keep their busy state. The range is a controlled input, so its position now reads the directory store'spendingselection: written synchronously byselect(), holding what the Host has accepted but not yet confirmed, and falling back tocurrenton directories that predate the field. Without that second half the thumb snaps back to the Host's stale answer mid-drag. The seat only readspending, never writes it, and stays a view of the Host's store.
v0.3.4 — Conflict-safe settings saves and composer UI refinements
修复 / Fixed
-
修复上一版引入的保存重试会丢弃并发改动的问题:为修复 issue #16 加入的「冲突后重试」会原样重放写入操作,而模型档位/能力写入携带的是按面板打开时快照重建的整个
models数组。若冲突期间其他写入改动了同一数组(宿主的默认档位补齐新增了一个模型、另一个窗口编辑了同路由下的兄弟模型),重试会用自己的旧数组覆盖文档,静默删掉或回退对方的结果——比原来「拒绝写入」更糟。现在重试只对「叶子路径」写入直接重放(provider / 模型 compat 单字段、OpenCode 会话开关、subagentEffort),携带整个容器的写入必须用重试时重新读取的分区重建数组;重建后没有任何目标模型时如实报错而不是假装成功。 -
Fix a save retry from the previous release discarding concurrent changes: the "retry after a conflict" added for issue #16 replayed the write's ops verbatim, and a model-levels/capability write carries a whole
modelsarray rebuilt from the inventory the panel read at mount. When another writer changed that same array during the conflict — the Host's default-levels fill adding a model, or another window editing a sibling model on the same route — the retry overwrote the document with its stale array, silently deleting or reverting the other writer's result, which is worse than the original refusal. A retry now replays only leaf-path writes directly (provider/model compat fields, the OpenCode session toggle,subagentEffort); a write carrying a whole container must rebuild it from the section re-read at retry time, and a rebuild that leaves no target model reports the conflict instead of claiming success. -
修复设置页保存被过期 revision 永久卡死(issue #16):面板挂载时读一次 revision 并在每次成功写入后更新,外部写入(切换默认模型、宿主的默认档位补齐、另一个窗口)不会同步,因此面板打开后只要别处写过一次,之后每次「保存更改」都会被
dsh-settings以版本冲突拒绝,且面板不会重新读取,用户侧表现为「设置再也保存不了」。现在写入被判定为冲突时会重新读取该分区并重试一次:只写入单个路径的操作(provider / 模型 compat 单字段、OpenCode 会话开关、subagentEffort)直接重放,携带整个models数组的写入则按重试时重新读取的分区重建,因此并发改动不会被覆盖。第二次仍冲突则如实报错,避免持续争抢时无限重试。 -
Fix settings saves being fenced forever by a stale revision (issue #16): the panel read the revision once at mount and updated it only after its own successful writes, so an external write (a default-model switch, the Host's own default-levels fill, another window) was never observed. Once anything else had written, every later Save was refused by
dsh-settingsas a version conflict and the panel never re-read, which the user experienced as "settings can no longer be saved". A write refused as a conflict now re-reads that section and retries once: a leaf-path write (a provider/model compat field, the OpenCode session toggle,subagentEffort) is replayed directly, while a write carrying a wholemodelsarray is rebuilt from the section re-read at retry time, so a concurrent change is never overwritten. A second conflict is reported as-is rather than retried again, so a persistently losing writer cannot spin. -
修复思考档位只勾
off时「保存更改」点击后毫无反馈(issue #15):该配置被validateLevels()拒绝(宿主侧同样拒绝只声明off的模型),但拒绝只把错误横幅渲染在页面标题下方,即整页最顶部,用户在下方模型卡片处操作时完全看不到,且按钮状态不变、不转圈、不发请求,只能判定为「按钮失灵」。现在保存按钮在校验不通过时直接禁用,并把原因(如「至少需要一个思考档位」)就近显示在按钮下方;写入路径与按钮可见性共用同一个校验函数,两者不会对「能否保存」给出不同答案。 -
Fix the Save button appearing dead when a model's thinking levels are reduced to
offonly (issue #15): that configuration is refused byvalidateLevels()(the Host likewise rejects a model declaring onlyoff), but the refusal rendered its banner below the page title — the very top of the page — so a user working in a model card below never saw it, while the button neither changed state nor showed progress nor sent a request. The Save button is now disabled on exactly that validation failure and the reason ("Select at least one reasoning effort") is shown beside it. The write path and the button's affordance read one shared predicate, so they cannot disagree about what is savable. -
修复中文界面下模型菜单把供应商分组标题显示成英文(issue #17):分组标题此前直接渲染供应商注册的
displayName,而deepseek-account注册的是英文DeepSeek Account,等于插件替 DSH 做了英文本地化。现在按 provider id 映射本地化名称(zhDeepSeek 账号、enDeepSeek Account、jaDeepSeek アカウント、koDeepSeek 계정),与 DSH 自带模型菜单的规则一致;其他供应商(含用户自建的网关)继续使用其注册名,不被替换。 -
Fix the model menu showing an English provider heading in a Chinese UI (issue #17): the heading rendered the provider's registered
displayName, anddeepseek-accountregisters the EnglishDeepSeek Account, so the plugin effectively localized the name into English. The signed-in account route is now mapped by provider id (zhDeepSeek 账号, enDeepSeek Account, jaDeepSeek アカウント, koDeepSeek 계정), matching DSH's own model menu. Every other provider — including a user-declared gateway — keeps its registered name. -
修复模型座位面板与模型菜单半透明、下层文字直接透出(issue #14):两者此前使用
--dsw-specific-menu,而该令牌是 DSH 核心的 58% 半透明菜单材质,核心只把它与--dsw-menu-backdrop-filter一起使用,单独使用等于没有底衬,面板后面的档位文字会 1:1 透上来。现在改用不透明且随主题切换的表面令牌--dsw-alias-bg-layer-1(面板)与--dsw-alias-bg-layer-2(浮在其上的菜单);这两个令牌在全部受支持的 DSH 版本(0.1.0-rc.7 起)都声明在body上,因此不依赖任何模糊效果或核心内部属性。 -
Fix the composer seat's panel and model menu being translucent with the page text readable through them (issue #14): both painted
--dsw-specific-menu, which is DSH core's 58%-translucent menu material and is only ever used together with--dsw-menu-backdrop-filter. Painted bare it provides no backing, so the effort labels behind the panel showed through it one-to-one. They now use the opaque, theme-aware surface tokens--dsw-alias-bg-layer-1(panel) and--dsw-alias-bg-layer-2(the menu floating over it). Both tokens are declared onbodyby every supported DSH release (0.1.0-rc.7 and later), so the fix depends on neither a blur effect nor a core-internal attribute. -
修复推理等级刻度与滑块始终对不齐、且滑块拖不到两端:刻度行此前用 flex 均分,而圆点按
i/(n-1)定位,首尾两个刻度因此各自内缩半格;两行现在读同一分数并改为绝对定位。更关键的是原生 range 的 thumb 必须整体留在轨道内,其圆心只能到达[半个 thumb 宽, 宽度 - 半个 thumb 宽],所以 thumb 永远够不到轨道两端(实测圆心偏差 −3.5…−21.5px);现在轨道、填充与刻度行都按半个 thumb 内缩,偏差收敛到 1px 以内。刻度行的内缩用 margin 而非 padding:绝对定位子元素的left: N%基准是包含块的 padding box,父元素上的 padding 对它完全不起作用,用 padding 时每个刻度仍会偏离自己的圆点 2-3px。首尾两个刻度改为按朝外的边锚定到各自圆点的外边缘、文字向内展开——端点圆点只内缩 9px(半个 18px thumb,浏览器硬下限)而 "Max" 半宽 12.2px,居中会超出内容区 3.2px,且面板内边距在这个比较中会相消(12/20/28px 实测外溢都是 3.18px)、缩字号要压到 9.6px 才装得下,低于宿主定义的最小档。 -
修复模型菜单分组标题吸顶时半透明、展开分组时行尾三角位移:标题此前不吸顶,滚动后 provider 名称直接丢失;且
background简写把不透明底色替换成了 8% 白的半透明令牌(#ffffff14),吸顶时下方选项透出。现在标题吸顶并偏移一个自身内边距以覆盖菜单的 padding(top: 0只钉在 scrollport 即菜单的 padding box,菜单自身的 padding 区仍会漏出下层),悬停色改用background-image叠加在不透明底色之上而非替换它。展开某个 provider 时列表变长,Windows 上经典滚动条占布局宽度导致内容变窄、每行尾部三角整体左移,现由scrollbar-gutter: stable固定内容宽度;菜单同时采用宿主自己的滚动条令牌(--dsh-scrollbar-thumb指向 L2),使其读起来属于菜单而非页面。 -
推理面板与模型菜单对齐 DSH 整体设计:面板内边距改为 12px(与官方 composer 浮层一致),两个浮层圆角统一用
--dsw-radius-lg(此前是 8px 与 6px,而 6px 不在宿主的圆角阶梯上),菜单与面板共用同一个内边距令牌以保持与内容边缘齐平(绝对定位子元素的 inset 相对父元素 padding box 解析,之前的 16px 内缩使菜单比内容边缘还内缩 4px)。面板字号改读宿主内容级联--dsh-content-font-size-secondary(由dsh-client-ui-theme定义在body上),因此跟随设置里的字号偏好;菜单项为 34px 居中行、分组标题为 11px/16px 字重 500,均对齐官方模型菜单。模型行的焦点框从:focus-within收窄到按钮自身的:focus-visible(前者鼠标按下也触发,整行画框看起来像一个输入框),模型行的三角在二级菜单展开时翻转为向上。 -
Fix the reasoning scale never lining up with its slider, and the slider not reaching either end: the labels were divided evenly across the row while the pips were positioned at
i/(n-1), so the first and last labels each sat half a step inside; both rows now read the same fraction and the labels are absolutely positioned against it. More fundamentally, a native range keeps the thumb's whole box inside the track, so the thumb's centre can only travel between half a thumb at each end and could never reach the track's ends (measured at −3.5 to −21.5px). The track, the fill and the scale row are now inset by half a thumb, bringing the error under a pixel. The scale row is inset with a margin, not a padding: an absolutely positioned child resolvesleft: N%against the containing block's padding box, so padding on the parent does not move it at all, and with a padding every label still sat 2-3px off its own pip. The two end labels are now anchored by their outward edge to the outer edge of their own pip, growing inward — an end pip only sits 9px in (half an 18px thumb, the browser's own limit) while "Max" is 12.2px half its width, so centring overran the content box by 3.2px, and the panel's padding cancels out of that comparison (12, 20 and 28px all leave the same 3.18px overrun) while shrinking the label to fit would mean 9.6px, below the smallest step the host defines. -
Fix the model menu's provider heading going see-through while stuck, and row chevrons shifting when a group is expanded: the heading did not stick at all, so scrolling a long list lost the provider name, and the
backgroundshorthand replaced its opaque fill with an 8% white token (#ffffff14), letting the options underneath show through. The heading now sticks, offset by one of the menu's own paddings so it covers the padding area (top: 0pins to the scrollport, which is the menu's padding box, leaving the padding itself uncovered), and the hover colour is layered on top of the fill withbackground-imageinstead of substituting for it. Expanding a provider grew the list, a classic scrollbar took layout width on Windows, the content box narrowed and every row's trailing chevron shifted left;scrollbar-gutter: stablenow fixes the content width. The menu also adopts the host's own scrollbar tokens (--dsh-scrollbar-thumbpointed at L2) so its thumb reads as part of the menu rather than of the page. -
Bring the composer seat panel and model menu onto the host's own design: the panel pads by 12px like the official composer surface, both floating surfaces round with
--dsw-radius-lg(they carried 8px and 6px, and 6px is not on the host's radius scale), and the menu and panel read one shared padding token so they stay flush with the content edges — an absolute child's insets resolve against the parent's padding box, so the old hardcoded 16px left the menu 4px inside the content edges. The panel takes its type from the host's content scale,--dsh-content-font-size-secondary, whichdsh-client-ui-themedeclares onbody, so it moves with the Settings font-size preference; the menu's cells are 34px centred rows and its group headings run 11px on 16px at weight 500, both matching the official model menu. The model row's focus frame is narrowed from:focus-withinto th...
v0.3.3 — Legacy migration buttons styled like the rest of the plugin
修复 / Fixed
- 修复新增功能的按钮样式:启动提示的三个按钮与设置页的「重新扫描旧数据」此前渲染成未主题化的默认按钮,与旁边同类的按钮明显不一致。它们现在统一使用插件自己的按钮原语(28px 高、8px 圆角、按主次分级:迁移为主按钮、不再询问为次按钮、稍后为无边框),启动提示还在视觉上对齐了 DSH 自己的弹窗(24px 圆角、模糊遮罩、同一标题层级),候选行改为等宽字体并保留来源标签。
- Fix the new feature's buttons: the startup prompt's three controls and the settings page's "Rescan legacy data" rendered as untinted default buttons, visibly unlike the equivalent buttons beside them. They now use the plugin's own button primitive (28px tall, 8px radius, ranked by weight: Migrate is the filled action, Don't ask again an ordinary one, Later borderless), and the prompt follows DSH's own dialog treatment (24px radius, blurred mask, same title scale), with candidate rows in a monospace face and the provenance label kept alongside.
v0.3.2 — DSH 0.1.7 support and automatic legacy-data migration
变更 / Changed
- 发布前的兼容矩阵新增
dsh-v0.1.7-alpha.1(entry-config 设置模型)作为第五个官方能力代表,0.1.7 根节点上会验证插件确实加载成功、其设置分区被发布,以及宿主的三条行为(llm-pi-ai的providers仍为 volatile;路径写入仍基于用户原始层;默认档位补齐自己的写入能够落盘)。 - The pre-publish compatibility matrix adds
dsh-v0.1.7-alpha.1(the entry-config settings model) as a fifth official capability representative; the 0.1.7 root verifies that the plugin loads, that its settings section is published, and that three host behaviours hold (llm-pi-ai'sprovidersstays volatile; a path write is still derived from the raw user layer; the provider-defaults fill's own write lands). - 修复 0.1.7 上默认档位补齐无法写回的问题:该版本把设置变更事件放在写入事务内部触发,插件在事务里再发起写入会被宿主以
HMR transactions cannot be nested拒绝,而事务上下文会随AsyncLocalStorage传播到任何延迟调用。补齐现在从一个在插件加载时创建的执行上下文中发起写入,因此新增模型时会正常补上默认档位,无需重启。 - Fix the provider-defaults fill being unable to write back on 0.1.7: that release raises the settings-change event from inside its own write transaction, so a write started from the listener is refused with
HMR transactions cannot be nested— and the transaction context travels withAsyncLocalStorageinto anything the listener defers. The fill now starts its write from an execution context created while the plugin is applied, so a newly added model gets its default levels without a restart. - 默认档位补齐改为只写入用户层:由组合 base 或 schema 默认值提供的模型不会被补全(0.1.7 的 entry-config 设置服务会把整棵解析后的子树落盘,为它们补全会把
input、compat、headers、thinkingBudgets、defaultContextWindow等 schema 默认值钉进你的设置文档)。跳过的模型会在宿主日志中报出数量。 - The provider-default fill now writes through the user layer only: a model a composition base or a schema default supplies is left unfilled (under the 0.1.7 entry-config settings service a resolved subtree lands on disk whole, so filling those models pinned
input,compat,headers,thinkingBudgets,defaultContextWindowand other schema defaults into your settings document). The Host logs how many models it skipped.
新增 / Added
-
设置页新增「会话值生成器」卡片,可在 UI 中读写
opencodeSession.format的全部字段(生成模式、时间戳来源、模板 / 表达式 / 脚本路径、校验正则与校验失败策略),无需再手写设置文档。卡片按当前模式只显示相关字段,并在写入前校验:非法正则、空模板 / 表达式 / 脚本、相对脚本路径,以及无法解析或引用了不存在名字的表达式,都会被拦下并给出原因——这些取值在宿主侧会静默退化(正则失效为「不校验」、其余回退为派生值),UI 里看不到就会误导。表达式校验与宿主共用同一份解析代码。写入按字段进行,不覆盖同命名空间的其他配置。 -
Add a "Session value generator" card to the settings page that reads and writes every
opencodeSession.formatfield (mode, timestamp source, template / expression / script path, validation regex, and the on-invalid policy), so the settings document no longer has to be edited by hand. The card shows only the fields the current mode uses and validates before writing: an invalid regex, an empty template / expression / script, a relative script path, and an expression that does not parse or names something that does not exist are refused with a reason — each of those silently degrades on the Host side (the regex to "no validation at all", the rest to the derived value), so leaving them invisible in the UI would mislead. Expression validation shares one parser with the Host. Writes are field-level, so nothing else in the namespace is overwritten. -
支持 DSH 0.1.7 的 entry-config 设置模型:插件现在导出根节点
.volatile()的Config,设置页表单才能在该版本上出现(此前插件在 0.1.7 上会以register is missing加载失败)。0.1.7及以后设置分区使用 Loader 条目 IDthinking-effort,0.1.0-rc.7至0.1.6仍使用注册的 namespacedsh-thinking-effort,客户端按宿主实际发布的那一个解析。subagentEffort随之迁入本插件自己的设置分区;在 0.1.7 上旧的llm-pi-ai位置既不可写也不可读(该 schema 只声明providers,写入其他路径会被整批拒绝,用户层投影也会丢掉未声明的键),所以升级前设在那里的默认值会显示为未设置,需要在插件设置卡片里重新选择。导入旧快照时插件会把llm-pi-ai里的这个键迁移到自己的分区,同一批次的 providers 也才能被接受。0.1.7及以后的设置保存在当前 profile 的cordis.patch.yml,而不再是~/.dsh/settings.yaml(0.1.7会重命名旧文件并尝试导入;对这个分区而言该导入会被拒绝并只留下警告,旧值仅保留在settings.yaml.imported中)。 -
Support the DSH 0.1.7 entry-config settings model: the plugin now exports a root-
.volatile()Config, which is what makes its settings form appear on that release at all (before, the plugin failed to load there withregister is missing). On0.1.7+ the settings section is the Loader entry idthinking-effort, while0.1.0-rc.7through0.1.6keep the registered namespacedsh-thinking-effort, and the Client resolves whichever the running host publishes.subagentEffortmoves into this plugin's own settings section; on 0.1.7 the oldllm-pi-ailocation is neither writable nor readable (that schema declares onlyproviders, so a write to any other path is refused for the whole batch and the user layer drops undeclared keys), which means a default set there before the upgrade reads as unset and has to be chosen again in the plugin's settings card. Importing an older snapshot migrates that key out ofllm-pi-aiinto the plugin's own section, which is also what lets its providers import. Settings are now stored in the active profile'scordis.patch.ymlinstead of~/.dsh/settings.yaml, which0.1.7renames and tries to import; for this section that import is refused with only a warning, so the old value survives insettings.yaml.importedalone. -
新增旧数据自动检测与迁移:DSH 0.1.7 把
settings.yaml重命名并只导入一次,而旧版本插件在该版本上加载失败,因此你此前的思考档位与模型开关只留在settings.yaml.imported里。插件现在会在启动时扫描该文件(以及尚未重命名的settings.yaml与活的llm-pi-ai用户层),发现可迁移项后在设置页上方弹出询问,你确认后才把这些旧数据值写入插件自己的设置分区。迁移只补齐你尚未设置的值,绝不覆盖;写入前会先把当时的设置存进「配置备份与方案」的回滚槽(autoBackup,来源标记为migration),且快照与迁移值在同一批写入中落盘,因此不会出现「有快照却没有迁移」的中间状态。选择「不再询问」后,仅当旧数据发生变化才会再次提示。 -
Add automatic detection and migration of stranded legacy data: DSH 0.1.7 renames and imports
settings.yamlexactly once, and older plugin releases failed to load on that version, so a user's thinking levels and model toggles survive only insidesettings.yaml.imported. On startup the plugin now scans that file (plus a not-yet-renamedsettings.yamland the livellm-pi-aiuser layer) and, when it finds migratable values, asks above the settings page before writing any of those legacy values into its own settings section. The migration only fills in values you have not set and never overwrites; before writing it saves the then-current settings into the Backup and profiles rollback slot (autoBackup, markedsourceProfile: migration), and the snapshot rides the same write batch as the migrated values, so there is no state in which a rollback copy exists without the migration. After you choose not to be asked again, it re-prompts only when the legacy data changes.
修复 / Fixed
- 修复两处只有真实宿主才会暴露的问题:迁移成功后弹窗不关闭(宿主尚未落地时的一次读取把提示重新打开,而重新打开后就不再轮询,于是过期候选与可用按钮一直留在屏幕上);以及重启后对已迁移的值重复提示(宿主自己的分区尚未发布时扫描,
declared()看到的用户层为空,于是整批又被当作未迁移)。 - Fix two problems only a real host exposed: the prompt not closing after a successful migration (a read taken before the host had acted reopened it, and a reopened prompt stops polling, so stale candidates and live buttons stayed on screen), and a restart re-offering values that were already migrated (a scan taken before the plugin's own section was published saw an empty user layer, so
declared()treated the whole set as unmigrated).