Skip to content

v0.3.4 — Conflict-safe settings saves and composer UI refinements

Choose a tag to compare

@hytime hytime released this 26 Sep 13:31
· 85 commits to main since this release

修复 / 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 models array 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-settings as 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 whole models array 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 off only (issue #15): that configuration is refused by validateLevels() (the Host likewise rejects a model declaring only off), 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 映射本地化名称(zh DeepSeek 账号、en DeepSeek Account、ja DeepSeek アカウント、ko DeepSeek 계정),与 DSH 自带模型菜单的规则一致;其他供应商(含用户自建的网关)继续使用其注册名,不被替换。

  • Fix the model menu showing an English provider heading in a Chinese UI (issue #17): the heading rendered the provider's registered displayName, and deepseek-account registers the English DeepSeek Account, so the plugin effectively localized the name into English. The signed-in account route is now mapped by provider id (zh DeepSeek 账号, en DeepSeek Account, ja DeepSeek アカウント, ko DeepSeek 계정), 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 on body by 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 resolves left: 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 background shorthand 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: 0 pins 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 with background-image instead 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: stable now fixes the content width. The menu also adopts the host's own scrollbar tokens (--dsh-scrollbar-thumb pointed 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, which dsh-client-ui-theme declares on body, 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-within to the button's own :focus-visible (the former also fires on a mouse press, framing the whole row so it read as a text input), and the model row's chevron turns up while its second-level menu is open.