deepseek-harness-background 0.5.4 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/README.zh.md +8 -6
- package/lib/client.js +117 -72
- package/lib/client.js.map +1 -1
- package/lib/index.js +281 -19
- package/package.json +85 -85
package/README.md
CHANGED
|
@@ -51,14 +51,15 @@ The look (fixed wallpaper layer + theme-aware scrim + translucent glass panels d
|
|
|
51
51
|
- **Third-party glass registry** — any plugin can register its own panels into the same frosted-glass system through the published bridge (`window.__DSH_BACKGROUND_GLASS__` global + the `dsh-background-glass:ready` event): *token* mode adds the missing sheen + blur chain when the panel already fills with an overridden `--dsw-*` token, *fill* mode takes the fill over as well; every rule sits under the `data-dsh-bg-glass` gate so it toggles with the glass automatically. Consumers take zero dependencies and degrade gracefully when this plugin is absent; the whole bridge tears down with it. See [docs/GLASS_API.md](docs/GLASS_API.md).
|
|
52
52
|
- **Conversation timeline** — the DeepSeek-web turn-navigation rail at the right edge of long conversations, one tick per question, with a hover/focus preview of that turn's prompt. Two frontends, one backend, chosen by what the running kernel supports:
|
|
53
53
|
- **dsh ≥ 0.1.2-rc.1 (enhancement)** — the kernel ships this rail already, so the plugin renders nothing of its own and only fixes its behaviour (a capability check on the rail's own published metrics, never a version compare). Clicks on a **loaded** mark become a **smooth glide** instead of the stock instant jump (ease-in-out, distance-paced, cancelled the moment the reader scrolls, `prefers-reduced-motion` places directly). The rail's full ladder (`turnOutline` outline + loaded window) leaves **unloaded** marks to the kernel's own loadThrough jump — and while one of those kernel jumps is still paging (the mark pulses `aria-busy`) the plugin stands down entirely. Because the official hover preview card paints an opaque fill, it joins the glass sheet under the wallpaper gate instead (same explicit-fill recipe as the composer card, driven by the glass-blur slider); the tick column carries the DeepSeek-web edge dissolve (paint layer only, hit-testing untouched). The rail's active-mark state stays the kernel's own — the glide scrolls the real scrollport, so the stock scroll handler keeps updating it and the persisted scroll position. The bottom-follow state is detached one frame before the glide (streaming growth / turn-end re-renders cannot yank it back to the floor). Toggle it off with the timeline switch in the row.
|
|
54
|
-
- **Persisted in the official settings document
|
|
54
|
+
- **Persisted in the official settings document**, waits out restarts — the `ui-background` namespace in `$DSH_HOME/settings.yaml` on dsh ≤ 0.1.6, and this plugin's profile entry in the active profile's patch from dsh 0.1.7 on (a pre-0.1.7 section is adopted once, and the settings row says so).
|
|
55
55
|
- **Clean teardown** — disabling, clearing or uninstalling restores the original background exactly; the plugin only ever removes what it wrote.
|
|
56
56
|
|
|
57
57
|
## Version compatibility
|
|
58
58
|
|
|
59
59
|
| Plugin release | Supported dsh versions |
|
|
60
60
|
| --- | --- |
|
|
61
|
-
| **
|
|
61
|
+
| **0.5.5** | **dsh 0.1.2-rc.1 and 0.1.3-alpha.x (verified on alpha.2), plus 0.1.5-alpha.1/alpha.2/rc.1/rc.2 (verified on rc.2), 0.1.6-alpha.1/alpha.2 and 0.1.7-alpha.1** |
|
|
62
|
+
| 0.5.3 – 0.5.4 | dsh 0.1.2-rc.1 and 0.1.3-alpha.x, plus 0.1.5-alpha.1/alpha.2/rc.1/rc.2 and 0.1.6-alpha.1/alpha.2 |
|
|
62
63
|
| 0.5.2 | dsh 0.1.1-rc.2 and 0.1.2-alpha.1 ~ alpha.5 |
|
|
63
64
|
|
|
64
65
|
⚠️ **On older dsh (0.1.1-rc.2, 0.1.2-alpha.x or earlier) install an older
|
|
@@ -121,7 +122,7 @@ dsh --profile web
|
|
|
121
122
|
- The **settings row** lives in the official General settings section (`settings.general.item` slot), next to the Appearance row. Its chrome uses only `--dsw-alias-*` design tokens (buttons / pills / segmented control / slider track match the official shell); sliders are native `input[type=range]` with 5% / 1–2px steps and release-commit.
|
|
122
123
|
- The plugin's own host routes (`/api/bg-wallpaper/*`: `settings`, `upload`, `image/<id>`) read/write the section and serve uploads with same-origin + size caps + MIME/signature checks + a path-escape fence. A custom route family is used because the api-proxy settings allowlist does not expose third-party namespaces over the settings RPC.
|
|
123
124
|
- The background is drawn as a fixed `z-index:-2` wallpaper layer plus a `z-index:-1` scrim on `body`, toggled by the `data-dsh-bg` attribute; the scrim switches white/black by `data-ds-dark-theme` in the injected stylesheet. Frosted glass is whitelist-scoped: only the whitelisted surfaces get `--dsw-*` surface-token overrides, while everything else is painted by explicit `data-dsh-bg-glass`-gated rules carrying the FULL recipe (fill + sheen + blur chain): the three chrome buttons, the load-earlier history button, the composer dock family (agent task strips TodoPanel / GoalBar / QueueDock and their takeover panels — approval, question, plan review — whose tokens turn translucent and need the blur added), the subagent lineage popover, the home hero preview badge and the sidebar build badge — every other official token and reading surface (menus, dialogs, tooltips, toasts) stays untouched.
|
|
124
|
-
- The **timeline** is registered into the `conversation.input.dock` slot (per-session lifecycle). Detection is a capability check on the slot props rather than a version compare: the official rail is rendered from the very index `ui-chat` publishes as a session hook (`useChat(s => s.navigation.items())`, dsh >= 0.1.2), so the presence of that hook *is* the presence of the official rail — and it survives pre-releases, forks and deployments that mount a different conversation target. With the hook the plugin renders nothing and intercepts clicks on the official rail's **loaded** marks in the **capture** phase (React 18 dispatches `onClick` from the root container during the bubble phase, so a capture listener on the rail runs first and `stopImmediatePropagation()` keeps the stock handler from ever firing) — resolving the click index against the merged ladder the kernel actually renders (`turnOutline` outline + loaded window, mirroring `mergeTurnRailItems` in ui-chat), with marks outside the loaded window (no anchor key) left to the kernel's own load-through jump — and while one of those kernel jumps is still paging (a mark pulses `aria-busy`) the plugin stands down entirely, because the kernel's loaded branch cancels its own pending jump before landing and an interception would bypass that cancellation. The official hover preview joins the glass sheet under the wallpaper gate (same explicit fill recipe as the composer card), and the tick column carries the DeepSeek-web edge dissolve. Supported baseline: dsh >= `0.1.2-rc.1`; older dsh (0.1.2-alpha.x and 0.1.1-rc.2 or earlier) installs an older plugin release (see Version compatibility).
|
|
125
|
+
- The **timeline** is registered into the `conversation.input.dock` slot (per-session lifecycle). Detection is a capability check on the slot props rather than a version compare: the official rail is rendered from the very index `ui-chat` publishes as a session hook (`useChat(s => s.navigation.items())`, dsh >= 0.1.2), so the presence of that hook *is* the presence of the official rail — and it survives pre-releases, forks and deployments that mount a different conversation target. With the hook the plugin renders nothing and intercepts clicks on the official rail's **loaded** marks in the **capture** phase (React 18 dispatches `onClick` from the root container during the bubble phase, so a capture listener on the rail runs first and `stopImmediatePropagation()` keeps the stock handler from ever firing) — resolving the click index against the merged ladder the kernel actually renders (`turnOutline` outline + loaded window, mirroring `mergeTurnRailItems` in ui-chat), with marks outside the loaded window (no anchor key) left to the kernel's own load-through jump — and while one of those kernel jumps is still paging (a mark pulses `aria-busy`) the plugin stands down entirely, because the kernel's loaded branch cancels its own pending jump before landing and an interception would bypass that cancellation. The official hover preview joins the glass sheet under the wallpaper gate (same explicit fill recipe as the composer card), and the tick column carries the DeepSeek-web edge dissolve. Two rail generations are handled by capability, never by version compare: the frame-style rail (dsh 0.1.2-rc.1 … 0.1.6), whose marks are mapped by geometry over the metrics it publishes inline, and the virtualized rail (dsh 0.1.7+), whose rendered marks carry their own ladder index and which mounts only a window of them at a time. Supported baseline: dsh >= `0.1.2-rc.1`; older dsh (0.1.2-alpha.x and 0.1.1-rc.2 or earlier) installs an older plugin release (see Version compatibility).
|
|
125
126
|
- The **third-party glass registry** (`src/client/glass-registry.ts`) publishes its bridge on client apply — before any repaint can race it: `register({ plugin, selectors, mode })` is idempotent per (plugin, mode, selector) triple and synthesizes explicit `body[data-dsh-bg-glass]`-gated recipe rules into a dedicated `<style data-plugin-css>` tag; selectors are structurally validated first (no `{ } ; @ < > ,`, no backslashes, 500-char cap) with per-selector warn-and-drop that never blocks valid siblings; disposing the client fiber retracts the whole bridge (stylesheet, entries, window key). Contract docs in `docs/GLASS_API.md` / `GLASS_API.zh.md`; behavior locked by `tests/glass-registry.spec.ts`.
|
|
126
127
|
- Uploads live under `$DSH_HOME/deepseek-harness-background/` (content-addressed ids). Switching to a new image or clearing the background deletes the superseded upload file, so the directory does not accumulate dead images in normal use. (An upload that is never saved into the section — e.g. the tab closes right after an upload — can leave one orphaned file behind.) Disable / uninstall leaves nothing behind.
|
|
127
128
|
|
|
@@ -140,9 +141,10 @@ deepseek-harness-background/ # the plugin repo (package name stays the
|
|
|
140
141
|
├── cordis.patch.yml # inserts the deepseek-harness-background row into the web roster
|
|
141
142
|
├── tsdown.config.ts # official clientBundle preset
|
|
142
143
|
├── src/
|
|
143
|
-
│ ├── index.ts # host half:
|
|
144
|
+
│ ├── index.ts # host half: settings namespace + API routes
|
|
144
145
|
│ ├── routes.ts # /api/bg-wallpaper/{settings,upload,image/<id>}
|
|
145
|
-
│ ├──
|
|
146
|
+
│ ├── migrate.ts # one-shot adoption of a pre-0.1.7 settings section
|
|
147
|
+
│ ├── schema.ts # host-side schemastery schema (+ the volatile Config)
|
|
146
148
|
│ ├── settings.ts # constants/types shared with the client
|
|
147
149
|
│ ├── harness-home.ts # $DSH_HOME / ~/.dsh resolution
|
|
148
150
|
│ └── client/
|
|
@@ -154,7 +156,7 @@ deepseek-harness-background/ # the plugin repo (package name stays the
|
|
|
154
156
|
│ │ ├── index.tsx # dock entry: official-rail capability probe + re-exports
|
|
155
157
|
│ │ ├── official-enhance.tsx # dsh>=0.1.2-rc.1: smooth-jump interception for loaded marks
|
|
156
158
|
│ │ ├── jump.ts # shared jump engine (paging + glide)
|
|
157
|
-
│ │ ├── rail-pointer.ts #
|
|
159
|
+
│ │ ├── rail-pointer.ts # rail tick resolution (data-index / frame geometry) & full-ladder merge
|
|
158
160
|
│ │ └── types.ts # shared shapes
|
|
159
161
|
│ ├── SettingsRow.tsx # the General-settings row (preview surface + stepped sliders)
|
|
160
162
|
│ ├── SettingsRow.module.css # row styles (official tokens)
|
package/README.zh.md
CHANGED
|
@@ -50,14 +50,15 @@
|
|
|
50
50
|
- **毛玻璃(白名单制)** —— 启用背景后,只有以小卡片/小按钮形态悬浮在壁纸上的表面才会变成半透明玻璃(顶部白色高光渐变 + `backdrop-filter`):输入框卡片与消息气泡、代码块 / 终端 / diff / 工具 IO 卡 / 技能与 MCP 调用卡与行内代码、agent 任务条及其接管面板(审批 / 提问 / 计划评审)、三个铬件按钮(新会话、输入框加号、回到底部)、「加载更早」历史按钮、标题栏展开的子代理列表面板、侧栏构建徽标,以及首页右上角的「预览版」徽标——每块玻璃面都带完整配方(填充 + 高光 + 模糊),绝无"只透明不磨砂"的残缺面。阅读型表面——对话框、设置界面、菜单、Tooltip、Toast、悬停填充与所有强调色(发送键保持品牌蓝)——一律保留**官方不透明样式**,保证可读性(唯一例外:时间线导航轨的悬浮预览卡,它是画在壁纸上的导航铬件,加入玻璃配方)。模糊半径由「毛玻璃模糊」滑块驱动;「面板不透明度」调至 100% 时白名单表面也恢复官方原样。
|
|
51
51
|
- **第三方毛玻璃接口** —— 内置毛玻璃注册表(`window.__DSH_BACKGROUND_GLASS__` 全局 + `dsh-background-glass:ready` 事件):任何插件都可把自家面板的选择器注册进来,套上与内置表面完全一致的配方——`token` 模式为已使用被覆盖 `--dsw-*` 填充的面板补齐高光+模糊链,`fill` 模式连填充一并接管;规则统一挂在 `data-dsh-bg-glass` 门控下随玻璃自动开关。消费方零依赖、未安装本插件时优雅降级,本插件卸载时整桥拆除。详见 [docs/GLASS_API.zh.md](docs/GLASS_API.zh.md)。
|
|
52
52
|
- **会话时间线** —— 长会话右缘的 DeepSeek 官网风格轮次导航轨:每一轮一个刻度,悬停或聚焦时预览该轮的问题。 本插件**不渲染任何自己的界面**——从 dsh 0.1.2-rc.1 起内核自带官方导航轨,插件只增强其行为(按导航轨自己发布的度量做能力探测,绝不比较版本号): 对**已加载**轮次的点击由官方的瞬时跳转改为**平滑滑动**(缓入缓出、按距离定时长、读者一滚动立刻接管、`prefers-reduced-motion` 下直接定位); 官方轨的全量阶梯(`turnOutline` 大纲 + 已加载窗口)中,**未加载**轮次的刻度交给内核自己的穿越加载跳转,且当内核跳转仍在翻页(`aria-busy` 脉冲)时插件整体让位; 官方悬浮预览卡是实心底,在壁纸门控下改为与输入卡同配方的毛玻璃(受「毛玻璃模糊」滑块驱动); 刻度列加上 DeepSeek 网页版式的上下渐隐(仅绘制层,不影响命中测试)。 导航轨的高亮状态仍归内核自己维护——滑动走的是真实滚动容器,官方滚动处理会持续更新活动轮次与持久化滚动位置; 滑动前都会先解除宿主的底部跟随状态(流式增长、轮次结束重渲染都不会把视图拽回底部)。用设置行里的时间线开关可关闭。
|
|
53
|
-
- **持久化到官方设置文档** —— 存于 `$DSH_HOME/settings.yaml
|
|
53
|
+
- **持久化到官方设置文档** —— 跨重启保留:dsh ≤ 0.1.6 存于 `$DSH_HOME/settings.yaml` 的 `ui-background` 命名空间,dsh 0.1.7 起存于当前 profile patch 中本插件的 entry(旧版 dsh 写下的段会一次性迁移过来,并在设置行给出提示)。
|
|
54
54
|
- **干净卸载** —— 关闭、清除或卸载后完整恢复原背景;插件只移除自己写过的内容。
|
|
55
55
|
|
|
56
56
|
## 版本兼容
|
|
57
57
|
|
|
58
58
|
| 本插件版本 | 支持的 dsh 版本 |
|
|
59
59
|
| --- | --- |
|
|
60
|
-
|
|
|
60
|
+
| **0.5.5** | **dsh 0.1.2-rc.1 与 0.1.3-alpha.x(已在 alpha.2 验证),另支持 0.1.5-alpha.1 / alpha.2 / rc.1 / rc.2(已在 rc.2 验证)、0.1.6-alpha.1 / alpha.2 与 0.1.7-alpha.1** |
|
|
61
|
+
| 0.5.3 – 0.5.4 | dsh 0.1.2-rc.1 与 0.1.3-alpha.x,另支持 0.1.5-alpha.1 / alpha.2 / rc.1 / rc.2 与 0.1.6-alpha.1 / alpha.2 |
|
|
61
62
|
| 0.5.2 | dsh 0.1.1-rc.2 与 0.1.2-alpha.1 ~ alpha.5 |
|
|
62
63
|
|
|
63
64
|
⚠️ **使用旧版 dsh(0.1.1-rc.2、0.1.2-alpha.x 或更早)请安装本插件的旧版本**
|
|
@@ -117,7 +118,7 @@ dsh --profile web
|
|
|
117
118
|
## 原理
|
|
118
119
|
|
|
119
120
|
- **设置行**位于官方「通用」设置分区的 `settings.general.item` 槽中,紧挨「外观」行。控件样式全部使用 `--dsw-alias-*` 设计 token(按钮 / 胶囊 / 分段控件 / 滑块轨道与官方 chrome 一致),滑块为原生 `input[type=range]` 的 5% / 1–2px 步进 + 松手提交。
|
|
120
|
-
- **会话时间线**注册进 `conversation.input.dock` 槽位(绑定每会话生命周期)。判定是对槽位 props 的能力探测,而不是比较版本号: 官方导航轨正是由 `ui-chat` 以会话 hook 形式发布的同一份索引渲染的(`useChat(s => s.navigation.items())`,dsh ≥ 0.1.2), 所以这个 hook 存在**就是**官方导航轨存在 —— 而且它能扛住预发布版、fork 以及挂载了其它会话目标的部署。 hook 存在时插件什么都不渲染,只在**捕获阶段**拦截官方导航轨**已加载刻度**的点击(React 18 在冒泡阶段由根容器派发 `onClick`, 所以导航轨上的捕获监听先执行,`stopImmediatePropagation()` 让官方处理器根本收不到事件)——点击索引按内核实际渲染的合并阶梯解析(`turnOutline` 大纲 + 已加载窗口,与 `ui-chat` 的 `mergeTurnRailItems` 同构),已加载窗口之外(无锚键)的刻度交给内核自己的穿越加载跳转——且当内核跳转仍在翻页(标记以 `aria-busy` 脉冲)时插件整体让位:内核的已加载分支落点前会先取消自己的在途跳转,拦截会绕过这一取消。 官方导航轨的悬浮预览在壁纸门控下加入毛玻璃配方(与输入卡片同一显式填充配方),刻度列带 DeepSeek 网页版式上下渐隐。 支持基线为 dsh ≥ `0.1.2-rc.1`;更旧的 dsh(0.1.2-alpha.x 与 0.1.1-rc.2 及更早)请安装本插件旧版本(见「版本兼容」)。
|
|
121
|
+
- **会话时间线**注册进 `conversation.input.dock` 槽位(绑定每会话生命周期)。判定是对槽位 props 的能力探测,而不是比较版本号: 官方导航轨正是由 `ui-chat` 以会话 hook 形式发布的同一份索引渲染的(`useChat(s => s.navigation.items())`,dsh ≥ 0.1.2), 所以这个 hook 存在**就是**官方导航轨存在 —— 而且它能扛住预发布版、fork 以及挂载了其它会话目标的部署。 hook 存在时插件什么都不渲染,只在**捕获阶段**拦截官方导航轨**已加载刻度**的点击(React 18 在冒泡阶段由根容器派发 `onClick`, 所以导航轨上的捕获监听先执行,`stopImmediatePropagation()` 让官方处理器根本收不到事件)——点击索引按内核实际渲染的合并阶梯解析(`turnOutline` 大纲 + 已加载窗口,与 `ui-chat` 的 `mergeTurnRailItems` 同构),已加载窗口之外(无锚键)的刻度交给内核自己的穿越加载跳转——且当内核跳转仍在翻页(标记以 `aria-busy` 脉冲)时插件整体让位:内核的已加载分支落点前会先取消自己的在途跳转,拦截会绕过这一取消。 官方导航轨的悬浮预览在壁纸门控下加入毛玻璃配方(与输入卡片同一显式填充配方),刻度列带 DeepSeek 网页版式上下渐隐。 两代导航轨都按能力(而非版本号)识别:**框架式轨道**(dsh 0.1.2-rc.1 … 0.1.6)把内联度量发布在 `<nav>` 上,刻度按几何换算;**虚拟化轨道**(dsh 0.1.7+)不发布任何内联度量,且只挂载可见窗口的刻度,每个刻度自带阶梯下标。 支持基线为 dsh ≥ `0.1.2-rc.1`;更旧的 dsh(0.1.2-alpha.x 与 0.1.1-rc.2 及更早)请安装本插件旧版本(见「版本兼容」)。
|
|
121
122
|
- 插件自有的 host 路由(`/api/bg-wallpaper/*`:`settings`、`upload`、`image/<id>`)负责读写设置与提供上传图片,带同源校验、大小上限、MIME/签名校验与路径穿越防护。使用自定义路由族,是因为 api-proxy 的 settings 白名单不向第三方命名空间开放 settings RPC。
|
|
122
123
|
- 背景以 `body` 上一张固定的 `z-index:-2` 壁纸层 + `z-index:-1` 遮罩绘制,由 `data-dsh-bg` 属性开关;遮罩在注入样式表里按 `data-ds-dark-theme` 切换白/黑纱帘。毛玻璃为白名单制:仅对输入/气泡/代码/任务条等白名单表面覆盖 `--dsw-*` surface token,其余表面通过 `data-dsh-bg-glass` 门控的显式规则补齐整套配方(填充 + 高光 + 模糊滤镜链):三个 chrome 按钮、「加载更早」历史按钮、composer 坞列家族——agent 任务条(TodoPanel / GoalBar / QueueDock)与接管面板(审批 / 提问 / 计划评审,token 变半透明后由这里补上模糊)、子代理列表弹出层、首页「预览版」徽标、侧栏构建徽章——全部官方 token 与阅读型界面(菜单/对话框/tooltip/toast)保持原样。
|
|
123
124
|
- **第三方玻璃注册表**(`src/client/glass-registry.ts`):客户端 apply 时即在 `window.__DSH_BACKGROUND_GLASS__` 发布注册 api 并派发 `dsh-background-glass:ready`;`register({ plugin, selectors, mode })` 按 `(plugin, mode, selector)` 三元组幂等登记,把 `body[data-dsh-bg-glass]` 门控的显式配方规则合成进独立的 `<style data-plugin-css>` 标签;选择器先做结构性校验(禁 `{} ; @ < > ,` 与反斜杠、500 字符上限),违规条目逐条警告并丢弃、不影响兄弟条目;fiber dispose 时整桥拆除(样式表、条目、window 键全清)。契约文档见 `docs/GLASS_API.md` / `GLASS_API.zh.md`,行为由 `tests/glass-registry.spec.ts` 锁定。
|
|
@@ -138,9 +139,10 @@ deepseek-harness-background/ # 插件仓库(包名保留 npm 风格 i
|
|
|
138
139
|
├── cordis.patch.yml # 向 web 插件名册插入 deepseek-harness-background 一行
|
|
139
140
|
├── tsdown.config.ts # 官方 clientBundle 预设
|
|
140
141
|
├── src/
|
|
141
|
-
│ ├── index.ts # host
|
|
142
|
+
│ ├── index.ts # host 半部:设置命名空间 + API 路由
|
|
142
143
|
│ ├── routes.ts # /api/bg-wallpaper/{settings,upload,image/<id>}
|
|
143
|
-
│ ├──
|
|
144
|
+
│ ├── migrate.ts # 一次性迁移 0.1.7 之前的设置段
|
|
145
|
+
│ ├── schema.ts # host 侧 schemastery schema(含 volatile 的 Config)
|
|
144
146
|
│ ├── settings.ts # 两端共享的常量/类型
|
|
145
147
|
│ ├── harness-home.ts # $DSH_HOME / ~/.dsh 解析
|
|
146
148
|
│ └── client/
|
|
@@ -152,7 +154,7 @@ deepseek-harness-background/ # 插件仓库(包名保留 npm 风格 i
|
|
|
152
154
|
│ │ ├── index.tsx # 停靠入口:官方轨能力探测与再导出
|
|
153
155
|
│ │ ├── official-enhance.tsx # dsh>=0.1.2-rc.1:已加载刻度平滑跳转拦截
|
|
154
156
|
│ │ ├── jump.ts # 共享跳转引擎(翻页 + 滑动)
|
|
155
|
-
│ │ ├── rail-pointer.ts #
|
|
157
|
+
│ │ ├── rail-pointer.ts # 刻度解析(data-index / 帧式几何)与全量阶梯合并
|
|
156
158
|
│ │ └── types.ts # 共享类型契约
|
|
157
159
|
│ ├── SettingsRow.tsx # 通用设置中的设置行(预览卡 + 阻尼滑块)
|
|
158
160
|
│ ├── SettingsRow.module.css # 设置行样式(官方 token)
|
package/lib/client.js
CHANGED
|
@@ -161,19 +161,13 @@ window.__ModuleLoader__.load({
|
|
|
161
161
|
|
|
162
162
|
/* The sidebar build badge paints with the label-ink token — a TEXT token we
|
|
163
163
|
must not override globally — so it gets a theme-aware translucent ink. */
|
|
164
|
-
body[data-dsh-bg] [class*="
|
|
164
|
+
body[data-dsh-bg] [class*="_buildVersion"] {
|
|
165
165
|
background-color: rgba(15, 17, 21, 0.62);
|
|
166
166
|
}
|
|
167
|
-
body[data-ds-dark-theme][data-dsh-bg] [class*="
|
|
167
|
+
body[data-ds-dark-theme][data-dsh-bg] [class*="_buildVersion"] {
|
|
168
168
|
background-color: rgba(249, 250, 251, 0.62);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
/* The empty-state hero glow asset would wash out the wallpaper behind the
|
|
172
|
-
welcome message — dim it so the art stays visible. */
|
|
173
|
-
body[data-dsh-bg] [class*="_heroGlow"] {
|
|
174
|
-
opacity: 0.2;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
171
|
/* ---- Whitelisted chrome buttons --------------------------------------
|
|
178
172
|
These three buttons' official fills ride button-* tokens shared with
|
|
179
173
|
unrelated surfaces, so instead of overriding the tokens they get explicit
|
|
@@ -279,7 +273,7 @@ window.__ModuleLoader__.load({
|
|
|
279
273
|
/* Sidebar build badge: translucent ink already, but it sat directly on
|
|
280
274
|
the wallpaper without frost. Join the shared blur chain under the same
|
|
281
275
|
gate (its theme-aware ink fills from the active block above). */
|
|
282
|
-
body[data-dsh-bg-glass] [class*="
|
|
276
|
+
body[data-dsh-bg-glass] [class*="_buildVersion"] {
|
|
283
277
|
-webkit-backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
284
278
|
backdrop-filter: blur(var(--bg-glass-blur, 16px)) saturate(var(--bg-glass-saturate, 1.42)) brightness(var(--bg-glass-brightness, 1)) contrast(1.01);
|
|
285
279
|
}
|
|
@@ -961,7 +955,9 @@ window.__ModuleLoader__.load({
|
|
|
961
955
|
"background.uploadFailed": "上传失败,请重试",
|
|
962
956
|
"background.saveFailed": "保存失败,请重试",
|
|
963
957
|
"background.timelineEnhance": "会话时间线增强",
|
|
964
|
-
"background.timelineEnhanceNarrowHint": "为官方会话时间线的已加载轮次补上平滑跳转"
|
|
958
|
+
"background.timelineEnhanceNarrowHint": "为官方会话时间线的已加载轮次补上平滑跳转",
|
|
959
|
+
"background.migratedNotice": "已从旧版 dsh 的设置中恢复你的背景设置",
|
|
960
|
+
"background.migratedDismiss": "知道了"
|
|
965
961
|
};
|
|
966
962
|
/** English copy. */
|
|
967
963
|
const en = {
|
|
@@ -990,7 +986,9 @@ window.__ModuleLoader__.load({
|
|
|
990
986
|
"background.uploadFailed": "Upload failed, try again",
|
|
991
987
|
"background.saveFailed": "Save failed, try again",
|
|
992
988
|
"background.timelineEnhance": "Conversation timeline enhancement",
|
|
993
|
-
"background.timelineEnhanceNarrowHint": "Adds smooth jumps for the rail's loaded turns"
|
|
989
|
+
"background.timelineEnhanceNarrowHint": "Adds smooth jumps for the rail's loaded turns",
|
|
990
|
+
"background.migratedNotice": "Restored your background settings from the previous dsh version",
|
|
991
|
+
"background.migratedDismiss": "Got it"
|
|
994
992
|
};
|
|
995
993
|
//#endregion
|
|
996
994
|
//#region node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
|
|
@@ -1046,7 +1044,8 @@ window.__ModuleLoader__.load({
|
|
|
1046
1044
|
if (!body.ok || body.value === void 0) throw new Error("unexpected payload");
|
|
1047
1045
|
this.snapshot = {
|
|
1048
1046
|
status: "ready",
|
|
1049
|
-
value: body.value
|
|
1047
|
+
value: body.value,
|
|
1048
|
+
...body.migrated === void 0 ? {} : { migrated: body.migrated }
|
|
1050
1049
|
};
|
|
1051
1050
|
} catch {
|
|
1052
1051
|
this.snapshot = { status: "error" };
|
|
@@ -1075,7 +1074,8 @@ window.__ModuleLoader__.load({
|
|
|
1075
1074
|
if (seq !== this.saveSeq) return "superseded";
|
|
1076
1075
|
this.snapshot = {
|
|
1077
1076
|
status: "ready",
|
|
1078
|
-
value: body.value
|
|
1077
|
+
value: body.value,
|
|
1078
|
+
...this.snapshot.migrated === void 0 ? {} : { migrated: this.snapshot.migrated }
|
|
1079
1079
|
};
|
|
1080
1080
|
this.notify();
|
|
1081
1081
|
return "ok";
|
|
@@ -1115,7 +1115,7 @@ window.__ModuleLoader__.load({
|
|
|
1115
1115
|
const settingsClient = new SettingsClient();
|
|
1116
1116
|
//#endregion
|
|
1117
1117
|
//#region \0dsh-css:D:\Project\deepseek-harness-background\src\client\SettingsRow.module.css.mjs
|
|
1118
|
-
const css = ".-ozqdq_row{border-bottom:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:14px;padding:16px 0;display:flex}.-ozqdq_header{flex-direction:column;gap:4px;display:flex}.-ozqdq_titleRow{justify-content:space-between;align-items:center;gap:12px;min-height:22px;display:flex}.-ozqdq_clearBtn{border-radius:12px;flex:none;height:24px;padding:0 10px;font-size:12px;line-height:24px}.-ozqdq_title{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.-ozqdq_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.-ozqdq_preview{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;height:132px;position:relative;overflow:hidden}.-ozqdq_previewImg{object-fit:var(--bg-object-fit,cover);width:100%;height:100%;opacity:var(--bg-opacity,1);filter:blur(var(--bg-wallpaper-blur,0px));transform:scale(var(--bg-wallpaper-scale,1));display:block;position:absolute;inset:0}.-ozqdq_previewScrim{background:rgba(255, 255, 255, var(--bg-scrim,.25));position:absolute;inset:0}body[data-ds-dark-theme] .-ozqdq_previewScrim{background:rgba(0, 0, 0, var(--bg-scrim,.25))}.-ozqdq_previewGlass{background:var(--bg-preview-glass,#ffffff24);width:44%;height:46px;backdrop-filter:blur(var(--bg-glass-blur,16px)) saturate(var(--bg-glass-saturate,1.42)) brightness(var(--bg-glass-brightness,1));border:1px solid #ffffff38;border-radius:10px;justify-content:center;align-items:center;display:flex;position:absolute;bottom:16px;left:16px;box-shadow:inset 0 1px #ffffff4d}.-ozqdq_previewGlassText{color:#0f172ac7;text-shadow:0 1px 2px #fff6;white-space:nowrap;font-size:11px;line-height:1}body[data-ds-dark-theme] .-ozqdq_previewGlassText{color:#ffffffd9;text-shadow:0 1px 2px #00000059}.-ozqdq_previewEmpty{color:var(--dsw-alias-label-tertiary);justify-content:center;align-items:center;font-size:12px;line-height:1.5;display:flex;position:absolute;inset:0}.-ozqdq_section{flex-direction:column;gap:8px;display:flex}.-ozqdq_sectionLabel{color:var(--dsw-alias-label-tertiary);letter-spacing:.01em;font-size:12px;font-weight:500;line-height:18px}.-ozqdq_sourceRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.-ozqdq_urlRow{align-items:center;gap:8px;display:flex}.-ozqdq_urlInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);min-width:0;height:32px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 10px;font-size:13px;line-height:1.5}.-ozqdq_urlInput::placeholder{color:var(--dsw-alias-label-dimmed)}.-ozqdq_urlInput:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.-ozqdq_hint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.-ozqdq_enabledBadge{white-space:nowrap;background:var(--dsw-alias-state-success-tertiary);color:var(--dsw-alias-state-success-primary);border-radius:999px;align-items:center;gap:4px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.-ozqdq_btn{border:1px solid var(--dsw-alias-border-l2);height:28px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;background:0 0;border-radius:14px;justify-content:center;align-items:center;padding:0 12px;font-size:12px;line-height:18px;transition:background-color .15s,border-color .15s,color .15s;display:inline-flex}.-ozqdq_btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.-ozqdq_btn:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.-ozqdq_btn:disabled{opacity:.45;cursor:default}.-ozqdq_btnPrimary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:#0000}.-ozqdq_btnPrimary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.-ozqdq_btnDanger{color:var(--dsw-alias-label-error)}.-ozqdq_btnDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.-ozqdq_sliderRow{align-items:center;gap:10px;display:flex}.-ozqdq_sliderLabel{color:var(--dsw-alias-label-primary);flex:0 0 96px;font-size:13px;line-height:1.5}.-ozqdq_slider{-webkit-appearance:none;appearance:none;cursor:pointer;background:0 0;flex:1;min-width:0;height:18px;margin:0}.-ozqdq_slider::-webkit-slider-runnable-track{background:linear-gradient(90deg, var(--dsw-alias-brand-primary) var(--bg-fill,0%), var(--dsw-alias-border-l3) var(--bg-fill,0%));border-radius:2px;height:4px}.-ozqdq_slider::-moz-range-track{background:var(--dsw-alias-border-l3);border-radius:2px;height:4px}.-ozqdq_slider::-moz-range-progress{background:var(--dsw-alias-brand-primary);border-radius:2px;height:4px}.-ozqdq_slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;border:2px solid var(--dsw-alias-brand-primary);width:14px;height:14px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), 0 1px 3px #00000047;background:#fff;border-radius:50%;margin-top:-5px}.-ozqdq_slider::-moz-range-thumb{border:2px solid var(--dsw-alias-brand-primary);width:14px;height:14px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), 0 1px 3px #00000047;background:#fff;border-radius:50%}.-ozqdq_slider:hover::-webkit-slider-thumb{box-shadow:0 0 0 5px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent), 0 1px 4px #0000004d}.-ozqdq_slider:hover::-moz-range-thumb{box-shadow:0 0 0 5px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent), 0 1px 4px #0000004d}.-ozqdq_slider:active::-webkit-slider-thumb{box-shadow:0 0 0 7px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent), 0 1px 5px #00000052;transform:scale(1.12)}.-ozqdq_slider:active::-moz-range-thumb{box-shadow:0 0 0 7px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent), 0 1px 5px #00000052;transform:scale(1.12)}.-ozqdq_slider:focus-visible{outline:none}.-ozqdq_slider:focus-visible::-webkit-slider-thumb{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_slider:focus-visible::-moz-range-thumb{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_sliderValue{text-align:right;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary);flex:0 0 52px;font-size:13px;line-height:1.5}.-ozqdq_segRow{align-items:center;gap:10px;display:flex}.-ozqdq_segLabel{color:var(--dsw-alias-label-primary);flex:0 0 96px;font-size:13px;line-height:1.5}.-ozqdq_segGroup{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:9px;flex:1;gap:2px;min-width:0;padding:2px;display:inline-flex}.-ozqdq_segBtn{height:24px;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:7px;flex:1;padding:0 16px;font-size:12px;line-height:24px}.-ozqdq_segBtn:hover:not(.-ozqdq_segActive){color:var(--dsw-alias-label-primary)}.-ozqdq_segActive{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font-weight:500}.-ozqdq_error{color:var(--dsw-alias-label-error);font-size:12px;line-height:1.5}.-ozqdq_clearRow{align-items:center;gap:10px;display:flex}.-ozqdq_switch{background:var(--dsw-alias-border-l3);cursor:pointer;border:none;border-radius:11px;flex:none;width:40px;height:22px;padding:0;transition:background-color .15s;position:relative}.-ozqdq_switch[aria-checked=true]{background:var(--dsw-alias-brand-primary)}.-ozqdq_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_switchKnob{background:#fff;border-radius:50%;width:16px;height:16px;transition:transform .15s;position:absolute;top:3px;left:3px;box-shadow:0 1px 3px #00000047}.-ozqdq_switch[aria-checked=true] .-ozqdq_switchKnob{transform:translate(18px)}@media (prefers-reduced-motion:reduce){.-ozqdq_btn,.-ozqdq_switch,.-ozqdq_switchKnob{transition:none}}";
|
|
1118
|
+
const css = ".-ozqdq_row{border-bottom:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:14px;padding:16px 0;display:flex}.-ozqdq_header{flex-direction:column;gap:4px;display:flex}.-ozqdq_titleRow{justify-content:space-between;align-items:center;gap:12px;min-height:22px;display:flex}.-ozqdq_clearBtn{border-radius:12px;flex:none;height:24px;padding:0 10px;font-size:12px;line-height:24px}.-ozqdq_title{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.-ozqdq_desc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.-ozqdq_notice{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;justify-content:space-between;align-items:center;gap:12px;padding:8px 12px;display:flex}.-ozqdq_noticeText{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:18px}.-ozqdq_noticeBtn{color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;flex:none;padding:0;font-size:12px;line-height:18px;text-decoration:underline}.-ozqdq_noticeBtn:hover{color:var(--dsw-alias-label-primary)}.-ozqdq_preview{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:12px;height:132px;position:relative;overflow:hidden}.-ozqdq_previewImg{object-fit:var(--bg-object-fit,cover);width:100%;height:100%;opacity:var(--bg-opacity,1);filter:blur(var(--bg-wallpaper-blur,0px));transform:scale(var(--bg-wallpaper-scale,1));display:block;position:absolute;inset:0}.-ozqdq_previewScrim{background:rgba(255, 255, 255, var(--bg-scrim,.25));position:absolute;inset:0}body[data-ds-dark-theme] .-ozqdq_previewScrim{background:rgba(0, 0, 0, var(--bg-scrim,.25))}.-ozqdq_previewGlass{background:var(--bg-preview-glass,#ffffff24);width:44%;height:46px;backdrop-filter:blur(var(--bg-glass-blur,16px)) saturate(var(--bg-glass-saturate,1.42)) brightness(var(--bg-glass-brightness,1));border:1px solid #ffffff38;border-radius:10px;justify-content:center;align-items:center;display:flex;position:absolute;bottom:16px;left:16px;box-shadow:inset 0 1px #ffffff4d}.-ozqdq_previewGlassText{color:#0f172ac7;text-shadow:0 1px 2px #fff6;white-space:nowrap;font-size:11px;line-height:1}body[data-ds-dark-theme] .-ozqdq_previewGlassText{color:#ffffffd9;text-shadow:0 1px 2px #00000059}.-ozqdq_previewEmpty{color:var(--dsw-alias-label-tertiary);justify-content:center;align-items:center;font-size:12px;line-height:1.5;display:flex;position:absolute;inset:0}.-ozqdq_section{flex-direction:column;gap:8px;display:flex}.-ozqdq_sectionLabel{color:var(--dsw-alias-label-tertiary);letter-spacing:.01em;font-size:12px;font-weight:500;line-height:18px}.-ozqdq_sourceRow{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.-ozqdq_urlRow{align-items:center;gap:8px;display:flex}.-ozqdq_urlInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);min-width:0;height:32px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 10px;font-size:13px;line-height:1.5}.-ozqdq_urlInput::placeholder{color:var(--dsw-alias-label-dimmed)}.-ozqdq_urlInput:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.-ozqdq_hint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}.-ozqdq_enabledBadge{white-space:nowrap;background:var(--dsw-alias-state-success-tertiary);color:var(--dsw-alias-state-success-primary);border-radius:999px;align-items:center;gap:4px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px;display:inline-flex}.-ozqdq_btn{border:1px solid var(--dsw-alias-border-l2);height:28px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;white-space:nowrap;background:0 0;border-radius:14px;justify-content:center;align-items:center;padding:0 12px;font-size:12px;line-height:18px;transition:background-color .15s,border-color .15s,color .15s;display:inline-flex}.-ozqdq_btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.-ozqdq_btn:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.-ozqdq_btn:disabled{opacity:.45;cursor:default}.-ozqdq_btnPrimary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:#0000}.-ozqdq_btnPrimary:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.-ozqdq_btnDanger{color:var(--dsw-alias-label-error)}.-ozqdq_btnDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.-ozqdq_sliderRow{align-items:center;gap:10px;display:flex}.-ozqdq_sliderLabel{color:var(--dsw-alias-label-primary);flex:0 0 96px;font-size:13px;line-height:1.5}.-ozqdq_slider{-webkit-appearance:none;appearance:none;cursor:pointer;background:0 0;flex:1;min-width:0;height:18px;margin:0}.-ozqdq_slider::-webkit-slider-runnable-track{background:linear-gradient(90deg, var(--dsw-alias-brand-primary) var(--bg-fill,0%), var(--dsw-alias-border-l3) var(--bg-fill,0%));border-radius:2px;height:4px}.-ozqdq_slider::-moz-range-track{background:var(--dsw-alias-border-l3);border-radius:2px;height:4px}.-ozqdq_slider::-moz-range-progress{background:var(--dsw-alias-brand-primary);border-radius:2px;height:4px}.-ozqdq_slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;border:2px solid var(--dsw-alias-brand-primary);width:14px;height:14px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), 0 1px 3px #00000047;background:#fff;border-radius:50%;margin-top:-5px}.-ozqdq_slider::-moz-range-thumb{border:2px solid var(--dsw-alias-brand-primary);width:14px;height:14px;box-shadow:0 0 0 3px color-mix(in srgb, var(--dsw-alias-brand-primary) 14%, transparent), 0 1px 3px #00000047;background:#fff;border-radius:50%}.-ozqdq_slider:hover::-webkit-slider-thumb{box-shadow:0 0 0 5px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent), 0 1px 4px #0000004d}.-ozqdq_slider:hover::-moz-range-thumb{box-shadow:0 0 0 5px color-mix(in srgb, var(--dsw-alias-brand-primary) 18%, transparent), 0 1px 4px #0000004d}.-ozqdq_slider:active::-webkit-slider-thumb{box-shadow:0 0 0 7px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent), 0 1px 5px #00000052;transform:scale(1.12)}.-ozqdq_slider:active::-moz-range-thumb{box-shadow:0 0 0 7px color-mix(in srgb, var(--dsw-alias-brand-primary) 22%, transparent), 0 1px 5px #00000052;transform:scale(1.12)}.-ozqdq_slider:focus-visible{outline:none}.-ozqdq_slider:focus-visible::-webkit-slider-thumb{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_slider:focus-visible::-moz-range-thumb{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_sliderValue{text-align:right;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary);flex:0 0 52px;font-size:13px;line-height:1.5}.-ozqdq_segRow{align-items:center;gap:10px;display:flex}.-ozqdq_segLabel{color:var(--dsw-alias-label-primary);flex:0 0 96px;font-size:13px;line-height:1.5}.-ozqdq_segGroup{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:9px;flex:1;gap:2px;min-width:0;padding:2px;display:inline-flex}.-ozqdq_segBtn{height:24px;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border:none;border-radius:7px;flex:1;padding:0 16px;font-size:12px;line-height:24px}.-ozqdq_segBtn:hover:not(.-ozqdq_segActive){color:var(--dsw-alias-label-primary)}.-ozqdq_segActive{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font-weight:500}.-ozqdq_error{color:var(--dsw-alias-label-error);font-size:12px;line-height:1.5}.-ozqdq_clearRow{align-items:center;gap:10px;display:flex}.-ozqdq_switch{background:var(--dsw-alias-border-l3);cursor:pointer;border:none;border-radius:11px;flex:none;width:40px;height:22px;padding:0;transition:background-color .15s;position:relative}.-ozqdq_switch[aria-checked=true]{background:var(--dsw-alias-brand-primary)}.-ozqdq_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.-ozqdq_switchKnob{background:#fff;border-radius:50%;width:16px;height:16px;transition:transform .15s;position:absolute;top:3px;left:3px;box-shadow:0 1px 3px #00000047}.-ozqdq_switch[aria-checked=true] .-ozqdq_switchKnob{transform:translate(18px)}@media (prefers-reduced-motion:reduce){.-ozqdq_btn,.-ozqdq_switch,.-ozqdq_switchKnob{transition:none}}";
|
|
1119
1119
|
const tagId = "deepseek-harness-background/SettingsRow.module.css";
|
|
1120
1120
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
1121
1121
|
const tag = document.createElement("style");
|
|
@@ -1125,41 +1125,44 @@ window.__ModuleLoader__.load({
|
|
|
1125
1125
|
document.head.appendChild(tag);
|
|
1126
1126
|
}
|
|
1127
1127
|
var SettingsRow_module_css_default = {
|
|
1128
|
-
"enabledBadge": "-ozqdq_enabledBadge",
|
|
1129
|
-
"previewImg": "-ozqdq_previewImg",
|
|
1130
|
-
"btnPrimary": "-ozqdq_btnPrimary",
|
|
1131
|
-
"hint": "-ozqdq_hint",
|
|
1132
|
-
"segActive": "-ozqdq_segActive",
|
|
1133
|
-
"clearRow": "-ozqdq_clearRow",
|
|
1134
|
-
"segBtn": "-ozqdq_segBtn",
|
|
1135
1128
|
"previewGlassText": "-ozqdq_previewGlassText",
|
|
1129
|
+
"title": "-ozqdq_title",
|
|
1130
|
+
"switchKnob": "-ozqdq_switchKnob",
|
|
1131
|
+
"sliderValue": "-ozqdq_sliderValue",
|
|
1132
|
+
"error": "-ozqdq_error",
|
|
1133
|
+
"urlRow": "-ozqdq_urlRow",
|
|
1136
1134
|
"btn": "-ozqdq_btn",
|
|
1137
|
-
"
|
|
1135
|
+
"sliderLabel": "-ozqdq_sliderLabel",
|
|
1136
|
+
"slider": "-ozqdq_slider",
|
|
1138
1137
|
"clearBtn": "-ozqdq_clearBtn",
|
|
1138
|
+
"preview": "-ozqdq_preview",
|
|
1139
1139
|
"urlInput": "-ozqdq_urlInput",
|
|
1140
|
-
"btnDanger": "-ozqdq_btnDanger",
|
|
1141
|
-
"urlRow": "-ozqdq_urlRow",
|
|
1142
|
-
"switchKnob": "-ozqdq_switchKnob",
|
|
1143
1140
|
"segRow": "-ozqdq_segRow",
|
|
1141
|
+
"enabledBadge": "-ozqdq_enabledBadge",
|
|
1142
|
+
"titleRow": "-ozqdq_titleRow",
|
|
1143
|
+
"sectionLabel": "-ozqdq_sectionLabel",
|
|
1144
|
+
"sourceRow": "-ozqdq_sourceRow",
|
|
1145
|
+
"segBtn": "-ozqdq_segBtn",
|
|
1146
|
+
"row": "-ozqdq_row",
|
|
1147
|
+
"noticeBtn": "-ozqdq_noticeBtn",
|
|
1148
|
+
"previewImg": "-ozqdq_previewImg",
|
|
1149
|
+
"switch": "-ozqdq_switch",
|
|
1150
|
+
"btnDanger": "-ozqdq_btnDanger",
|
|
1144
1151
|
"segLabel": "-ozqdq_segLabel",
|
|
1145
1152
|
"previewGlass": "-ozqdq_previewGlass",
|
|
1153
|
+
"previewEmpty": "-ozqdq_previewEmpty",
|
|
1154
|
+
"noticeText": "-ozqdq_noticeText",
|
|
1146
1155
|
"header": "-ozqdq_header",
|
|
1147
|
-
"sectionLabel": "-ozqdq_sectionLabel",
|
|
1148
|
-
"sliderLabel": "-ozqdq_sliderLabel",
|
|
1149
|
-
"desc": "-ozqdq_desc",
|
|
1150
|
-
"sliderValue": "-ozqdq_sliderValue",
|
|
1151
1156
|
"section": "-ozqdq_section",
|
|
1152
|
-
"titleRow": "-ozqdq_titleRow",
|
|
1153
|
-
"previewEmpty": "-ozqdq_previewEmpty",
|
|
1154
|
-
"sliderRow": "-ozqdq_sliderRow",
|
|
1155
1157
|
"previewScrim": "-ozqdq_previewScrim",
|
|
1156
|
-
"
|
|
1158
|
+
"desc": "-ozqdq_desc",
|
|
1159
|
+
"notice": "-ozqdq_notice",
|
|
1160
|
+
"sliderRow": "-ozqdq_sliderRow",
|
|
1157
1161
|
"segGroup": "-ozqdq_segGroup",
|
|
1158
|
-
"
|
|
1159
|
-
"
|
|
1160
|
-
"
|
|
1161
|
-
"
|
|
1162
|
-
"switch": "-ozqdq_switch"
|
|
1162
|
+
"hint": "-ozqdq_hint",
|
|
1163
|
+
"btnPrimary": "-ozqdq_btnPrimary",
|
|
1164
|
+
"segActive": "-ozqdq_segActive",
|
|
1165
|
+
"clearRow": "-ozqdq_clearRow"
|
|
1163
1166
|
};
|
|
1164
1167
|
//#endregion
|
|
1165
1168
|
//#region src/client/SettingsRow.tsx
|
|
@@ -1331,6 +1334,7 @@ window.__ModuleLoader__.load({
|
|
|
1331
1334
|
const [uploading, setUploading] = (0, react.useState)(false);
|
|
1332
1335
|
const [urlText, setUrlText] = (0, react.useState)("");
|
|
1333
1336
|
const [error, setError] = (0, react.useState)("");
|
|
1337
|
+
const [noticeDismissed, setNoticeDismissed] = (0, react.useState)(false);
|
|
1334
1338
|
const fileInput = (0, react.useRef)(null);
|
|
1335
1339
|
const previewRef = (0, react.useRef)(null);
|
|
1336
1340
|
const draftRef = (0, react.useRef)(DEFAULTS);
|
|
@@ -1513,6 +1517,19 @@ window.__ModuleLoader__.load({
|
|
|
1513
1517
|
children: t("background.description")
|
|
1514
1518
|
})]
|
|
1515
1519
|
}),
|
|
1520
|
+
snapshot.migrated !== void 0 && !noticeDismissed && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1521
|
+
className: SettingsRow_module_css_default.notice,
|
|
1522
|
+
role: "status",
|
|
1523
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1524
|
+
className: SettingsRow_module_css_default.noticeText,
|
|
1525
|
+
children: t("background.migratedNotice")
|
|
1526
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1527
|
+
type: "button",
|
|
1528
|
+
className: SettingsRow_module_css_default.noticeBtn,
|
|
1529
|
+
onClick: () => setNoticeDismissed(true),
|
|
1530
|
+
children: t("background.migratedDismiss")
|
|
1531
|
+
})]
|
|
1532
|
+
}),
|
|
1516
1533
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1517
1534
|
className: SettingsRow_module_css_default.preview,
|
|
1518
1535
|
ref: previewRef,
|
|
@@ -1740,12 +1757,20 @@ window.__ModuleLoader__.load({
|
|
|
1740
1757
|
/**
|
|
1741
1758
|
* Resolve the gesture that produced a rail click to an entry index.
|
|
1742
1759
|
*
|
|
1743
|
-
*
|
|
1744
|
-
*
|
|
1745
|
-
*
|
|
1746
|
-
*
|
|
1747
|
-
*
|
|
1748
|
-
*
|
|
1760
|
+
* Two rail generations answer here, told apart by capability:
|
|
1761
|
+
*
|
|
1762
|
+
* - The virtualized rail (dsh 0.1.7+) tags every RENDERED mark with its own
|
|
1763
|
+
* ladder index (`data-index`), so the gesture resolves by data. This is the
|
|
1764
|
+
* robust path: the virtualizer mounts only a window of marks, and their DOM
|
|
1765
|
+
* order is not the ladder order.
|
|
1766
|
+
* - The frame-style rail tags nothing and paints marks with
|
|
1767
|
+
* `pointer-events: none`, so a MOUSE gesture arrives at the `<nav>` with
|
|
1768
|
+
* coordinates and resolves through the rail geometry over the published
|
|
1769
|
+
* `--turn-scroll-top`; a KEYBOARD gesture activates the focused mark button,
|
|
1770
|
+
* recovered by its position among its siblings.
|
|
1771
|
+
*
|
|
1772
|
+
* Returns -1 when neither applies (a keyboard target outside the rail, or a
|
|
1773
|
+
* rail of an unsupported generation, which the kernel's own handler then owns).
|
|
1749
1774
|
*
|
|
1750
1775
|
* Assumption: the mark ticks are the ONLY buttons under the rail — the
|
|
1751
1776
|
* official rail renders marks exclusively and its preview tooltip carries
|
|
@@ -1758,6 +1783,11 @@ window.__ModuleLoader__.load({
|
|
|
1758
1783
|
function indexForEvent(rail, event) {
|
|
1759
1784
|
const target = event.target;
|
|
1760
1785
|
if (target instanceof Element) {
|
|
1786
|
+
const mark = target.closest("[data-index]");
|
|
1787
|
+
if (mark !== null && rail.contains(mark)) {
|
|
1788
|
+
const tagged = Number(mark.getAttribute("data-index"));
|
|
1789
|
+
if (Number.isSafeInteger(tagged) && tagged >= 0) return tagged;
|
|
1790
|
+
}
|
|
1761
1791
|
const button = target.closest("button");
|
|
1762
1792
|
if (button !== null && rail.contains(button)) {
|
|
1763
1793
|
const index = Array.from(rail.querySelectorAll("button")).indexOf(button);
|
|
@@ -1858,33 +1888,36 @@ window.__ModuleLoader__.load({
|
|
|
1858
1888
|
* turn navigator (dsh >= 0.1.2-rc.1, `TurnNavigator` in dsh-client-ui-chat).
|
|
1859
1889
|
*
|
|
1860
1890
|
* This component renders NOTHING. It borrows the official rail exactly as the
|
|
1861
|
-
* kernel painted it and fixes its behaviour, scoped to what the
|
|
1862
|
-
*
|
|
1863
|
-
* apart by capability, never by version compare:
|
|
1891
|
+
* kernel painted it and fixes its behaviour, scoped to what the running rail
|
|
1892
|
+
* generation still lacks — told apart by capability, never by version compare:
|
|
1864
1893
|
*
|
|
1865
1894
|
* Smooth jump. The official `navigateToTurn` is one assignment
|
|
1866
1895
|
* (`el.scrollTop += flowTop(row, el) - 24`); a click across a long transcript
|
|
1867
1896
|
* teleports. Clicks on LOADED marks are intercepted in the capture phase and
|
|
1868
|
-
* re-run through the shared glide instead.
|
|
1869
|
-
*
|
|
1870
|
-
*
|
|
1871
|
-
*
|
|
1872
|
-
*
|
|
1873
|
-
*
|
|
1874
|
-
*
|
|
1875
|
-
*
|
|
1876
|
-
*
|
|
1897
|
+
* re-run through the shared glide instead. Both generations also render marks
|
|
1898
|
+
* for turns OUTSIDE the loaded window (fed by the whole-log `turnOutline`
|
|
1899
|
+
* projection); those jumps page history through the kernel's own loadThrough
|
|
1900
|
+
* machinery — marks without an anchor key are left to it, and the click index
|
|
1901
|
+
* is resolved against the same merged ladder the kernel renders. While one of
|
|
1902
|
+
* those kernel jumps is still paging (a mark pulses `aria-busy`), the plugin
|
|
1903
|
+
* stands down entirely: the kernel's loaded branch cancels its own pending
|
|
1904
|
+
* jump before landing, and an interception would bypass that cancellation.
|
|
1905
|
+
*
|
|
1906
|
+
* Two rail generations are supported, discovered by {@link findOfficialRail}:
|
|
1907
|
+
* the frame-style rail of dsh 0.1.2-rc.1 … 0.1.6 (inline frame metrics, marks
|
|
1908
|
+
* mapped by geometry) and the virtualized rail of dsh 0.1.7+ (no inline
|
|
1909
|
+
* metrics, marks tagged `data-index`, only a window of them mounted at once).
|
|
1877
1910
|
*
|
|
1878
1911
|
* State-ownership note (why intercepting the official click loses nothing):
|
|
1879
1912
|
* the kernel's scrollport (`data-conversation-scroll`, ChatView's
|
|
1880
1913
|
* `onScrollRef` handler) treats every unaccounted scrollTop assignment as a
|
|
1881
1914
|
* reader move and on each frame (a) flips its own at-bottom machinery,
|
|
1882
|
-
* (b) `chatScroll.save(position)` for view-tab restore, and (c)
|
|
1883
|
-
*
|
|
1884
|
-
*
|
|
1885
|
-
*
|
|
1886
|
-
*
|
|
1887
|
-
*
|
|
1915
|
+
* (b) `chatScroll.save(position)` for view-tab restore, and (c) re-derives
|
|
1916
|
+
* the rail's active mark. The glide animates the real scrollport, so all three
|
|
1917
|
+
* keep converging to the target row while it runs — the only thing the
|
|
1918
|
+
* interception skips is the official handler's synchronous active-mark
|
|
1919
|
+
* assignment, which its own scroll-driven derivation re-settles by the time
|
|
1920
|
+
* the glide lands.
|
|
1888
1921
|
*
|
|
1889
1922
|
* The jump goes through the shared backend (jump.ts).
|
|
1890
1923
|
*
|
|
@@ -1892,20 +1925,32 @@ window.__ModuleLoader__.load({
|
|
|
1892
1925
|
* root container during the BUBBLE phase. A capture listener on the rail
|
|
1893
1926
|
* itself therefore runs first, and `stopImmediatePropagation()` there prevents
|
|
1894
1927
|
* the event from ever reaching React's root — the official handler never
|
|
1895
|
-
* fires. The rail owns pointer input for its whole column (marks
|
|
1896
|
-
* `pointer-events: none`)
|
|
1928
|
+
* fires. The frame-style rail owns pointer input for its whole column (marks
|
|
1929
|
+
* carry `pointer-events: none`); the virtualized rail's marks are real
|
|
1930
|
+
* buttons. Both arrive at the same capture listener on the rail.
|
|
1897
1931
|
*
|
|
1898
1932
|
* Nothing here touches the official DOM: no nodes are injected into a
|
|
1899
1933
|
* React-owned subtree and no official class or paint is overridden.
|
|
1900
1934
|
*/
|
|
1901
1935
|
/**
|
|
1902
|
-
*
|
|
1903
|
-
*
|
|
1904
|
-
*
|
|
1905
|
-
*
|
|
1906
|
-
*
|
|
1936
|
+
* Find the official turn rail, in either supported generation.
|
|
1937
|
+
*
|
|
1938
|
+
* Identity comes from the SEAT, not from a rendered mark: the rail is the only
|
|
1939
|
+
* `<nav>` inside the conversation scrollport, and dsh 0.1.7's virtualizer
|
|
1940
|
+
* mounts its marks lazily — measured on the real rail, the `<nav>` exists with
|
|
1941
|
+
* an EMPTY marks container until the virtualizer has layout. Requiring a
|
|
1942
|
+
* rendered `button[data-index]` would therefore miss the rail exactly when it
|
|
1943
|
+
* first appears.
|
|
1944
|
+
*
|
|
1945
|
+
* The generation is then told apart by capability where it matters: the click
|
|
1946
|
+
* resolver reads a mark's own `data-index`, and only falls back to the legacy
|
|
1947
|
+
* frame geometry for a rail that publishes `--turn-scroll-top`.
|
|
1948
|
+
* @param root - the tree to search (defaults to the document).
|
|
1949
|
+
* @returns the rail element, or null when the conversation shows none.
|
|
1907
1950
|
*/
|
|
1908
|
-
|
|
1951
|
+
function findOfficialRail(root = document) {
|
|
1952
|
+
return root.querySelector("[data-conversation-scroll] nav");
|
|
1953
|
+
}
|
|
1909
1954
|
/**
|
|
1910
1955
|
* Rails claimed by an enhancer instance, keyed by the owning instance's
|
|
1911
1956
|
* claim token. One session-scoped enhancer mounts per session; without a
|
|
@@ -1941,7 +1986,7 @@ window.__ModuleLoader__.load({
|
|
|
1941
1986
|
const claimToken = react.default.useMemo(() => Symbol("dsh-bg-timeline-claim"), []);
|
|
1942
1987
|
react.default.useEffect(() => {
|
|
1943
1988
|
const check = () => {
|
|
1944
|
-
const found =
|
|
1989
|
+
const found = findOfficialRail();
|
|
1945
1990
|
if (found === null) {
|
|
1946
1991
|
setRail(null);
|
|
1947
1992
|
return;
|
|
@@ -2356,7 +2401,7 @@ window.__ModuleLoader__.load({
|
|
|
2356
2401
|
order: 45,
|
|
2357
2402
|
locale: "ui-background",
|
|
2358
2403
|
inject: (sessionId) => ({ jumpToAnchor: (anchorKey) => {
|
|
2359
|
-
const scrollport =
|
|
2404
|
+
const scrollport = findOfficialRail()?.closest("[data-conversation-scroll]") ?? null;
|
|
2360
2405
|
return jumpToMessage(ctx.sessions, sessionId, anchorKey, {
|
|
2361
2406
|
followZonePx: 24,
|
|
2362
2407
|
targetTop: officialTargetTopFor,
|