dsh-claude-style 0.13.2 → 0.13.3
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/CHANGELOG.md +20 -0
- package/docs/FEATURES.en.md +1 -0
- package/docs/FEATURES.md +1 -0
- package/docs/SETTINGS.en.md +3 -1
- package/docs/SETTINGS.md +3 -1
- package/docs/decisions/D12-fail-fast.md +2 -0
- package/docs/decisions/D45-testing.md +1 -1
- package/docs/decisions/D64-custom-brand.md +29 -0
- package/docs/decisions/README.md +1 -0
- package/lib/assets/84b3319c06fb.js.br +0 -0
- package/lib/assets/91558108acf4.js.map.br +0 -0
- package/lib/assets/manifest.json +4 -4
- package/lib/client.js +6 -6
- package/lib/client.js.map +4 -4
- package/lib/host/brand.js +136 -0
- package/lib/host/http.js +74 -0
- package/lib/host/routes.js +13 -73
- package/lib/host/settings.js +3 -0
- package/lib/model-descriptions.json +84 -0
- package/package.json +1 -1
- package/lib/assets/abf0547f08a4.js.br +0 -0
- package/lib/assets/ba68f60ecc71.js.map.br +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ All notable changes to `dsh-claude-style` are documented here, newest first.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.13.3] - 2026-10-12
|
|
8
|
+
|
|
9
|
+
[中文](#cn-0.13.3) | [English](#en-0.13.3)
|
|
10
|
+
|
|
11
|
+
<h3 id="cn-0.13.3">新增功能</h3>
|
|
12
|
+
|
|
13
|
+
- 选完 Claude 或 DeepSeek 主题风格后,侧栏顶部、新会话页与账号行的兜底头像只能挂这两家的标志;设置页「外观」里现在可以填自己的品牌名称、上传标志图片与文字标志(PNG / SVG / WebP,不超过 2 MB),选择图片保留原色或按文字颜色着色,并指定一个主色替换按钮、选中标记、链接与焦点环的颜色。图片存在 DSH 主目录的 `dsh-claude-style/brand/` 下,由宿主半边新增的 `/dsh-claude-style/brand`、`/brand/mark`、`/brand/wordmark` 三条私有路由读写;设置项新增 `brandName`、`brandInk`、`brandAccent`。
|
|
14
|
+
|
|
15
|
+
### 问题修复
|
|
16
|
+
|
|
17
|
+
- 等待行曾连带隐藏 dsh-status-rotator 等插件插入的状态行;现在只隐藏宿主文案,第三方状态行保持可见。
|
|
18
|
+
|
|
19
|
+
<h3 id="en-0.13.3">New Features</h3>
|
|
20
|
+
|
|
21
|
+
- With the Claude or DeepSeek theme style chosen, the top of the sidebar, the new-conversation page and the account row's fallback picture could only carry those two brands' marks; the Appearance tab now takes your own brand name, a mark and a wordmark image (PNG / SVG / WebP, up to 2 MB), a choice between the images' own colours and the text colour, and an accent colour for buttons, selected marks, links and focus rings. The images live under `dsh-claude-style/brand/` in the DSH home directory, read and written through three new private routes of the host half — `/dsh-claude-style/brand`, `/brand/mark` and `/brand/wordmark`; the settings gain `brandName`, `brandInk` and `brandAccent`.
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
- The waiting line hid status lines inserted by plugins such as dsh-status-rotator; it now hides only the host wording and leaves third-party status lines visible.
|
|
26
|
+
|
|
7
27
|
## [0.13.2] - 2026-10-11
|
|
8
28
|
|
|
9
29
|
[中文](#cn-0.13.2) | [English](#en-0.13.2)
|
package/docs/FEATURES.en.md
CHANGED
|
@@ -7,6 +7,7 @@ What each feature does and where its switch lives; the five tabs, their rows and
|
|
|
7
7
|
<!-- features:start — written by npm run features, not by hand -->
|
|
8
8
|
|
|
9
9
|
- **Selection colour while unfocused**: Selected text takes the unfocused colours while the window is in the background and the focused ones when it comes back, as other applications do.
|
|
10
|
+
- **Custom brand**: Puts your own brand name, mark and wordmark over the chosen brand: the top of the sidebar, the collapsed rail, the new-conversation page and the account row's fallback picture all take them, with the images in their own colours or inked in the text colour. An accent colour of your own can recolour buttons, selected marks, links and focus rings.
|
|
10
11
|
- **Composer**: The input card on the new-conversation page and in conversations is redrawn after Claude Code Desktop: attachments sit in one row of tiles, the context usage is a ring in the toolbar, a press anywhere on the card starts typing, and a conversation resting at the bottom moves up with the card as it grows. The Composer tab chooses the home page alone, the conversation alone, both, or neither.
|
|
11
12
|
- **Home layout**: Classic is the centred greeting over the input card. Studio moves the greeting to the top left, pins the input card to the window's bottom edge and fills the space between with a usage panel: a heat map of recent usage and the usage and cost of each model.
|
|
12
13
|
- **Mascot**: A pixel companion stands on the composer's top edge and changes its animation with what the agent is doing (thinking, writing and calling tools, several sessions at work, subagents, waiting on you, compacting the context, finished, failed, asleep). Follow the brand shows the pixel crab under Claude and Deepy the whale under DeepSeek; either can be picked for good, or none. Where it appears keeps it to the new-conversation page, or puts it in conversations as well.
|
package/docs/FEATURES.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
<!-- features:start — written by npm run features, not by hand -->
|
|
8
8
|
|
|
9
9
|
- **失焦时的选区颜色**:窗口失去焦点时,选中的文字换成失焦的配色,回到窗口时换回来,与系统里别的程序一致。
|
|
10
|
+
- **自定义品牌**:在所选品牌之上换上你自己的品牌名、标志图与文字标志,侧栏顶部、折叠栏、新会话页与账号行的兜底头像都跟着换;图可以保留原色,也可以按文字颜色着色。另可指定一个主色,按钮、选中标记、链接与焦点环随之变色。
|
|
10
11
|
- **输入区**:新会话页与对话页的输入卡片按 Claude Code Desktop 的样子重画:附件排成一行缩略图,上下文用量是工具栏里的一个圆环,点卡片的空白处就能开始输入,卡片变高时停在底部的对话跟着上移。设置页「输入区」可以选只改新会话页、只改对话页、两处都改或关闭。
|
|
11
12
|
- **首页版面**:「经典」是居中的问候语与输入卡片;「工作室」把问候语移到左上角、输入卡片贴着窗口底边,中间是用量面板:近期的用量热力图、各模型的用量与费用。
|
|
12
13
|
- **吉祥物**:输入框上沿站着一只像素小伙伴,随智能体的工作状态换动画(思考、写回答与调用工具、多个会话同时工作、子代理、等你操作、压缩上下文、完成、失败、睡着)。「跟随品牌」在 Claude 品牌下是像素螃蟹,在 DeepSeek 品牌下是小鲸鱼 Deepy,也可以固定选一个或者关闭;「出现位置」决定它只在新会话页出现,还是新会话页和对话页都出现。
|
package/docs/SETTINGS.en.md
CHANGED
|
@@ -9,7 +9,7 @@ The settings page appears both in the settings dialog (the "Claude Style" tab) a
|
|
|
9
9
|
| Tab | Settings |
|
|
10
10
|
|---|---|
|
|
11
11
|
| General | Theme style, Username, Animation, Open popovers on hover, Account-hold easter egg language |
|
|
12
|
-
| Appearance | Colours, Typefaces, Mascot, Where it appears |
|
|
12
|
+
| Appearance | Colours, Typefaces, Mascot, Where it appears, Brand name, Brand mark, Wordmark, Image colours, Accent colour |
|
|
13
13
|
| Composer | Composer restyle, Home layout, Redraw the model picker (with Quick providers under it), Peak rate meter, Redraw the permission control |
|
|
14
14
|
| Sidebar | Collapse the sidebar settings area, Sidebar search, Search box style, Sidebar layout (Relaxed / Compact), In progress / Archived view, Float docked panels |
|
|
15
15
|
| Conversation | Conversation navigator, Chat-area animations (Off / Enhanced), Conversation statistics position (Inside the context popover / On its own line), Composer caret motion, Chat / Trajectory tabs |
|
|
@@ -20,6 +20,8 @@ In the settings dialog, this page's heading row ends with a GitHub mark; pressin
|
|
|
20
20
|
|
|
21
21
|
**Opened from a remote address**: DSH saves settings only from a page opened at a local address such as localhost. A page reached through a LAN address or a tunnel (a phone, another computer) shows the look and the settings DSH holds, and the settings page opens with a line saying so, its controls disabled. Settings changed on the computer running DSH reach the remote page without a reload.
|
|
22
22
|
|
|
23
|
+
**Custom brand**: the last rows of the Appearance tab put your own brand over the one Theme style picks. Brand name replaces the brand text at the top of the sidebar; Brand mark replaces the mark at the top of the sidebar, on the collapsed rail, on the new-conversation page and as the account row's fallback picture; Wordmark replaces the name beside the mark, its width following the image's proportions at the row's height, and while it is in place the brand name is not shown. The images take PNG, SVG and WebP up to 2 MB each and are kept under `dsh-claude-style/brand/` in the DSH home directory; dropping `mark.png` (or `.svg`, `.webp`) and `wordmark.png` into that directory by hand works too, after a page reload. Image colours set to Original shows the images in their own colours; Text colour uses each image as a shape filled with the text colour where it stands, which suits a one-colour mark and reads in both light and dark. Accent colour recolours buttons, selected marks, links and focus rings, with the text on a button picked dark or light to read on it; unset, the chosen brand's accent stays, and while Colours is set to Follow the host the accent has no effect. Clearing or removing any of them puts the chosen brand's own back in its place.
|
|
24
|
+
|
|
23
25
|
**Peak rate meter**: every row of the model menu carries the rate in force for that model right now. Peak, off-peak and a dated promotion each get their own mark, the colour separates expensive from cheap, and the multiplier is followed by how long it lasts; hovering the badge prints the whole judgement and what it becomes. The judgement is made from each provider's own published schedule in that provider's own time zone: outside the weekday windows, and on weekends and public holidays in full, the rate is off-peak, and a window crossing midnight belongs to the day it starts. A model with no schedule published carries no badge. The schedules are one snapshot in the public [offpeakclock.com](https://offpeakclock.com) catalog: the host half — not the page — fetches it, keeps a copy on disk and refreshes it every 24 hours, and judges by the copy shipped in the package when it cannot be reached.
|
|
24
26
|
|
|
25
27
|
**Sidebar search**: with Sidebar search on, the sidebar carries a search box whose palette finds sessions (titles and content), projects, plugins, Skills and shortcuts; picking a content hit lands the page on the turn holding that message, paging that turn's records in first on a long history. Search box style places it: Cover the brand (the default) puts it in the brand row, standing over the brand while the pointer is anywhere over the sidebar and giving the brand back when the pointer leaves; Standalone gives it a row of its own under the brand row, shown always; Icon draws no box of the plugin's, keeping DSH's own search button where the host draws it and taking only its click over, so pressing it opens this plugin's palette. The content match reads your own messages and the model's answers alone: injected context, the Skill catalog and reasoning never reach the results.
|
package/docs/SETTINGS.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
| 分页 | 设置项 |
|
|
10
10
|
|---|---|
|
|
11
11
|
| 通用 | 主题风格、用户名、动画效果、悬停展开弹层、封号彩蛋语言 |
|
|
12
|
-
| 外观 |
|
|
12
|
+
| 外观 | 配色、字体、吉祥物、出现位置、品牌名称、标志图片、文字标志、图片颜色、主色 |
|
|
13
13
|
| 输入区 | 输入区重绘范围、首页版面、重绘模型选择器(及其下的快捷供应商)、峰谷电表、重绘权限控件 |
|
|
14
14
|
| 侧栏 | 折叠侧栏设置区、侧栏搜索、搜索框样式、左侧栏布局(宽松 / 紧凑)、进行中 / 已归档视图、面板悬浮卡片 |
|
|
15
15
|
| 对话 | 对话导航、聊天区动画效果(关闭 / 增强)、对话统计信息位置(收进上下文 / 独立成行)、输入框插入符动效、对话 / 轨迹标签条 |
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
|
|
21
21
|
**从远程地址打开**:DSH 只保存从 localhost 等本机地址打开的页面所做的设置改动。经局域网地址或隧道打开的页面(手机、另一台电脑)显示的是 DSH 当前的外观与设置,设置页开头有一行说明,控件全部禁用。在运行 DSH 的电脑上改动设置后,远程页面不需要刷新就会跟上。
|
|
22
22
|
|
|
23
|
+
**自定义品牌**:「外观」页末尾几行把你自己的品牌放到「主题风格」所选的品牌之上。「品牌名称」替换侧栏顶部的品牌文字;「标志图片」替换侧栏顶部、折叠栏、新会话页与账号行兜底头像上的标志;「文字标志」替换标志旁的名称,宽度按图片比例随高度换算,有它时不再显示品牌名称。图片收 PNG、SVG 与 WebP,单张不超过 2 MB,存在 DSH 主目录的 `dsh-claude-style/brand/` 下,也可以直接把 `mark.png`(或 `.svg`、`.webp`)与 `wordmark.png` 放进这个目录,刷新页面后生效。「图片颜色」选「原色」时图按自己的颜色显示;选「文字色」时图被当作形状,按所在位置的文字颜色上色,适合单色标志,亮色暗色下都看得清。「主色」改按钮、选中标记、链接与焦点环的颜色,按钮上的文字自动取深色或浅色;未指定时沿用所选品牌的主色,「配色」选「跟随宿主」时主色不生效。每一项留空或移除后,对应位置回到所选品牌的原样。
|
|
24
|
+
|
|
23
25
|
**峰谷电表**:模型菜单的每一行标出该模型此刻的倍率。峰价、谷价与限时活动三种状态各有自己的图标,颜色区分贵与便宜,倍数后面跟着距离切换还有多久;鼠标停在徽章上,悬停提示写出此刻的完整判定与切换后的状态。判定按各家供应商自己发布的作息表与自己的时区做,工作日窗口之外、周末与法定节假日整日都算谷价,跨零点的窗口归它开始的那一天。没有任何作息表的模型不显示徽章。作息表是公开目录 [offpeakclock.com](https://offpeakclock.com) 里的一份快照,由宿主半边(而不是页面)取一次、在本机留一份缓存并按 24 小时刷新;连不上时按插件包里带的那份判定。
|
|
24
26
|
|
|
25
27
|
**侧栏搜索**:开启后侧栏里多一个搜索框,打开的面板能找会话(标题与内容)、项目、插件、Skill 与快捷键;点开一条内容命中,页面落到那条消息所在的一轮,历史很长时先把这一轮的记录翻页读进来。「搜索框样式」决定它站在哪里:「覆盖品牌」(默认)把它放进品牌行,指针移到侧栏上时它盖过品牌,指针移开再把品牌让回来;「独立」在品牌行下方给它自己一行,一直显示;「图标」不画插件自己的搜索框,让 DSH 自己的搜索按钮留在原处,只把单击接管过来,点它打开的是本插件的面板。内容匹配只认你发出的消息与模型的回答,注入的环境提示、Skill 目录与推理过程都不进结果。
|
|
@@ -15,10 +15,12 @@
|
|
|
15
15
|
- 宿主以抛错表达的预期状态:设置表单的 `set()` 拒绝不属于该配置的字段;`modelDirectories.directoryFor` 对还没建立的会话抛错,下一轮重试;`sessionQuery` 的观察(`observeSession`)与按 id 读(`readSession`)以 `SESSION_QUERY_CORRUPT_SESSION` / `SESSION_QUERY_SESSION_NOT_FOUND` 表示某个存档读不了或已被删,内容搜索与用量汇总把这一个会话记为空并记一条警告,其余会话照旧。
|
|
16
16
|
- 文件变更行解析流式工具的原始参数:参数逐块到达,半截 JSON 是正常的中途状态,解析不了就交回宿主的输入 / 输出卡片(`features/chat-files/file-row-model.ts`)。
|
|
17
17
|
- Promise 上表示「宿主半边没有应答」或「宿主自己会提示」的失败回调。
|
|
18
|
+
- 读者自己的品牌图加载失败(D64):这一张记一条警告并当作没有,另一张照常显示。
|
|
18
19
|
- 宿主半边允许的 catch,每处写明原因:
|
|
19
20
|
- `webServer.register` 以抛错拒绝已被别的插件占用的路径:逐条注册,被拒的记警告,其余照常(宿主半边的纤程失败会连带撤下浏览器半边的整个包)。
|
|
20
21
|
- 卸载时逐个运行路由的撤销函数,单个失败记警告后继续。
|
|
21
22
|
- 删除会话的请求体不是 JSON 时答 400;删除过程中的任何故障答 500 并带错误信息。
|
|
23
|
+
- 写入或删除品牌图过程中的任何故障答 500 并带错误信息(D64)。
|
|
22
24
|
- 宿主半边 `lib/assets/manifest.json` 读不了或不是 JSON 时答 404:那是构建没跑完的状态,记一次警告即可,不必让路由本身失败。
|
|
23
25
|
- 成本计量插件的账本是别的插件的文件,读取与它的写入没有协调,解析不了时当作没有账本、改用本地折算。
|
|
24
26
|
- 用量汇总自己的缓存只省工作量:读不了时记警告并整体重算覆盖,写不进时记警告、本轮结果照常返回。
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- `packages/testing/dsh-web.cjs` 起一个临时实例:`$DSH_HOME` 在 `.debug/` 下,本仓库以链接装进它的 web 配置,启动后交出带令牌的地址;通道自己的补丁走 `--patch` 覆盖层,profile 的用户层留给宿主;`resetState` 清掉会话与侧栏缓存,断言页面的场景因此从空会话列表开始。实例的标准输入是一条只由启动进程持有的管道,`packages/testing/lifeline.cjs` 经 `NODE_OPTIONS` 预加载进宿主,读到管道关闭就结束宿主:启动进程无论正常退出、抛出未捕获的错误、被 Ctrl+C 或 `taskkill /F` 终止,实例都随它结束,不会留在后台。
|
|
13
13
|
- `packages/testing/mock-llm.cjs` 是脚本化的模型服务,按 Messages 协议回答宿主路由,脚本按请求顺序交付;只有模型是脚本化的,agent 循环、会话、客户端各层与渲染都是发行版宿主。
|
|
14
14
|
- 端到端通道按职责分成几份:`packages/testing/e2e.cjs` 是运行器,为每个场景起一套实例、发出提示词、在轮次进行中逐帧采样、失败时写下现场;`packages/testing/scenarios.cjs` 是场景表,自带读取逻辑的场景各成一个模块挂进表里;`packages/testing/lane.cjs` 放运行器与场景共用的页面标记与断言形状;`packages/testing/contract-probe.cjs` 放契约表的逐条核对。场景可以给宿主的命令行与浏览器各加参数(`hostArgs`、`browserArgs`)。
|
|
15
|
-
- 每个场景各起一套实例,断言各自的东西:`conversation` 读者的消息成行、脚本回答的 Markdown 与思考过程归组;`narrow` 以 390×844 的手机窗口打开,断言输入框下沿那一行放得下权限档位、模型、推理等级与上下文圆环(权限收起下三角、两个选择器按窄屏上限截断、圆环不显示数字、四者都在卡片内且圆环不与旁边重叠);`statsPosition` 用补丁层把「对话统计信息位置」存成「独立成行」,断言这个值经宿主的设置命名空间到达页面、宿主的统计行与计量环在卡片下面排成自己的一行、皮肤自己的数字块没有建起来(`packages/testing/stats-position.cjs`:存档值与宿主设置表单这一段路,替代的宿主页面证明不了);`statsOverlay` 在「收进上下文」那一档下把计量环所在的 dock 与输入行两个盒子逐边对起来,把卡片在那一行下方留的空隙分别改成 0 与 16px 断言 dock 跟着那一行走、不停在写死的 4px 上,再把触发按钮在停放节点里左移 14px 断言行尾留出的宽度按两个盒子的并集算(`packages/testing/stats-overlay.cjs`;两个场景由 `stats-position.cjs` 一次导出);`sidebarRail` 收起侧栏,断言新会话那一格是宿主的 36 像素图标按钮、宿主留给它自己图标的座位不再占这一行的宽度、圆片由按钮自己居中并落在收起按钮与各面板图标同一条中线上,再把座位放回这一行量一次它占住的宽度,让这条中线不是巧合(`packages/testing/sidebar-rail.cjs`);`tool` 工具调用单独成行并带调用编号、结果之后的回答渲染出来;`fileMerge` 让脚本化的模型在一个轮次里改同一个文件四次、另一个文件写一次,断言这个文件在页面上只留一行可见、行尾数字是这四次改动的累计值并随每次改动滚动、其余三行整行离开页面且不占高度、展开代表行读到全部改动,另一个文件的单行不被卷进来(`packages/testing/file-merge.cjs`,D62);`send` 发送起飞期间替身离开页面、真行不可见、读者的字每一帧都看得见、替身带走了输入卡片的字体;`scroll` 逐帧记录滚动位置与内容高度,断言没有一帧在内容没有变短时倒退、没有一帧在内容没有增长时把尾部留在视野之外;`readerScroll` 在轮次进行中自己滚一次滚轮,断言状态行的固定只在跟随自己移动位置时钉住、读者往回翻看时该行随内容走而不浮在内容上,它自己逐帧采样(`packages/testing/reader-scroll.cjs`);`processSummary` 让脚本化的模型先沉默过 10 秒再开口(`packages/testing/mock-llm.cjs` 的 `holdMs`),断言运行中那一行换成皮肤的等待行、计时用宿主的单位、过 10 秒挂出「暂未响应」、模型一开口就撤下,并在轮次结束后按每个过程组标题上的计数核对它收住的东西(`packages/testing/process-summary.cjs`);`reasoningStream` 让脚本化的模型分几步推理半分钟,推理进行中每 250 毫秒读一次窗口,断言窗口跟着文本长高、长到宿主给过程组正文的上限就停住并开始按两行一步往上走,长满之前文本铺满窗口、没有遮罩也没有位移,走到的位置不超过内容末尾、最新一行始终留在窗口里,推理结束后窗口撤下、整段文本原样站着(`packages/testing/reasoning-stream.cjs`);`importance` 走过首页、对话、草稿、流式输出、各个弹层与菜单、附件、暗色与品牌和配色的切换以及每条 `:hover` 规则的悬停,逐条判定皮肤的 `!important` 是否需要,一条多余即失败;设置 `DSH_IMPORTANCE_REFERENCE` 时每个状态还与一张旧样式表逐元素比对(D51);`remoteSettings` 让宿主多信任一个名字 `remote.test`、浏览器把它解析到本机,同一实例分别以 loopback 地址与这个名字打开,在本机页面改主题风格,断言远程页面不刷新就跟上、刷新后读到的仍是宿主的值、它的设置页开头有说明行且控件全部禁用、本机设置页照常可写,结束前把主题风格写回原值,因为设置文档在各场景共用的临时目录里(`packages/testing/remote-settings.cjs`,D60);`shots` 亮暗两套截图。
|
|
15
|
+
- 每个场景各起一套实例,断言各自的东西:`conversation` 读者的消息成行、脚本回答的 Markdown 与思考过程归组;`narrow` 以 390×844 的手机窗口打开,断言输入框下沿那一行放得下权限档位、模型、推理等级与上下文圆环(权限收起下三角、两个选择器按窄屏上限截断、圆环不显示数字、四者都在卡片内且圆环不与旁边重叠);`statsPosition` 用补丁层把「对话统计信息位置」存成「独立成行」,断言这个值经宿主的设置命名空间到达页面、宿主的统计行与计量环在卡片下面排成自己的一行、皮肤自己的数字块没有建起来(`packages/testing/stats-position.cjs`:存档值与宿主设置表单这一段路,替代的宿主页面证明不了);`statsOverlay` 在「收进上下文」那一档下把计量环所在的 dock 与输入行两个盒子逐边对起来,把卡片在那一行下方留的空隙分别改成 0 与 16px 断言 dock 跟着那一行走、不停在写死的 4px 上,再把触发按钮在停放节点里左移 14px 断言行尾留出的宽度按两个盒子的并集算(`packages/testing/stats-overlay.cjs`;两个场景由 `stats-position.cjs` 一次导出);`sidebarRail` 收起侧栏,断言新会话那一格是宿主的 36 像素图标按钮、宿主留给它自己图标的座位不再占这一行的宽度、圆片由按钮自己居中并落在收起按钮与各面板图标同一条中线上,再把座位放回这一行量一次它占住的宽度,让这条中线不是巧合(`packages/testing/sidebar-rail.cjs`);`tool` 工具调用单独成行并带调用编号、结果之后的回答渲染出来;`fileMerge` 让脚本化的模型在一个轮次里改同一个文件四次、另一个文件写一次,断言这个文件在页面上只留一行可见、行尾数字是这四次改动的累计值并随每次改动滚动、其余三行整行离开页面且不占高度、展开代表行读到全部改动,另一个文件的单行不被卷进来(`packages/testing/file-merge.cjs`,D62);`send` 发送起飞期间替身离开页面、真行不可见、读者的字每一帧都看得见、替身带走了输入卡片的字体;`scroll` 逐帧记录滚动位置与内容高度,断言没有一帧在内容没有变短时倒退、没有一帧在内容没有增长时把尾部留在视野之外;`readerScroll` 在轮次进行中自己滚一次滚轮,断言状态行的固定只在跟随自己移动位置时钉住、读者往回翻看时该行随内容走而不浮在内容上,它自己逐帧采样(`packages/testing/reader-scroll.cjs`);`processSummary` 让脚本化的模型先沉默过 10 秒再开口(`packages/testing/mock-llm.cjs` 的 `holdMs`),断言运行中那一行换成皮肤的等待行、计时用宿主的单位、过 10 秒挂出「暂未响应」、模型一开口就撤下,并在轮次结束后按每个过程组标题上的计数核对它收住的东西(`packages/testing/process-summary.cjs`);`reasoningStream` 让脚本化的模型分几步推理半分钟,推理进行中每 250 毫秒读一次窗口,断言窗口跟着文本长高、长到宿主给过程组正文的上限就停住并开始按两行一步往上走,长满之前文本铺满窗口、没有遮罩也没有位移,走到的位置不超过内容末尾、最新一行始终留在窗口里,推理结束后窗口撤下、整段文本原样站着(`packages/testing/reasoning-stream.cjs`);`importance` 走过首页、对话、草稿、流式输出、各个弹层与菜单、附件、暗色与品牌和配色的切换以及每条 `:hover` 规则的悬停,逐条判定皮肤的 `!important` 是否需要,一条多余即失败;设置 `DSH_IMPORTANCE_REFERENCE` 时每个状态还与一张旧样式表逐元素比对(D51);`remoteSettings` 让宿主多信任一个名字 `remote.test`、浏览器把它解析到本机,同一实例分别以 loopback 地址与这个名字打开,在本机页面改主题风格,断言远程页面不刷新就跟上、刷新后读到的仍是宿主的值、它的设置页开头有说明行且控件全部禁用、本机设置页照常可写,结束前把主题风格写回原值,因为设置文档在各场景共用的临时目录里(`packages/testing/remote-settings.cjs`,D60);`customBrand` 从页面上经宿主的围栏调用品牌图路由,断言不收的类型、与类型不符的字节、超过上限的图分别答 415、400、413,存下的两张图出现在状态里、按自己的类型并带 `sandbox` 安全策略送出,刷新后侧栏标志、新会话页标志画的是这张图、文字标志按 4:1 的比例换算宽度,结束前删掉两张图,因为品牌目录同样在共用的临时目录里(`packages/testing/custom-brand.cjs`,D64);`shots` 亮暗两套截图。
|
|
16
16
|
- 截图沿用写盘前的隐私替换与泄漏扫描(`scripts/shared/privacy.cjs`,与 `scripts/shoot.cjs` 共用),两套明暗各写一张到本次运行的输出目录供人查看;仓库不存比对基线,画面是否变样由用户看过再定。
|
|
17
17
|
- 持续集成(`.github/workflows/ci.yml`):构建检查、单元测试与完整冒烟在 Linux 上跑;完整冒烟另在 Windows 上跑一遍,读者的桌面端在 Windows,宿主半边在那里读会话目录、盘符路径与文件时间;端到端的行为场景与截图捕获在 Linux 上跑,宿主版本固定;`contract` 场景另对宿主最新的预发布版(npm 的 `alpha` 标签)跑一遍,宿主改动了皮肤读的契约时先在这里报出,只作预警,不挡合并。每个任务都有时限;工作流用到的 Actions 由 Dependabot 每周提更新(`.github/dependabot.yml`)。
|
|
18
18
|
- `.debug/` 里有价值的探针已升级为有维护的工具:逐帧滚动记录并入 `scroll` 场景,发送过程录制并入 `send` 场景的逐帧采样,替身采样并入同一份采样;其余草稿在会话结束时删除。
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# D64. 自定义品牌是叠在两档品牌之上的一层
|
|
2
|
+
|
|
3
|
+
- **状态**:已实施
|
|
4
|
+
- **分组**:功能
|
|
5
|
+
- **关联**:D11、D12、D30、D38、D50、D60
|
|
6
|
+
|
|
7
|
+
## 决定
|
|
8
|
+
|
|
9
|
+
- 品牌仍是 Claude 与 DeepSeek 两档(D50),决定底色、基础标志与吉祥物;自定义品牌是叠在所选品牌之上的一层:品牌名称、标志图、文字标志、图片着色方式与主色,每一项只在读者提供时生效,没提供的项保持所选品牌原样。
|
|
10
|
+
- 名称、着色方式与主色是偏好(`brandName`、`brandInk`、`brandAccent`),经设置表单存进宿主的设置文档(D60);两张图不进设置文档,存在 `$DSH_HOME/dsh-claude-style/brand/` 下,文件名为 `mark.<扩展名>` 与 `wordmark.<扩展名>`,只收 PNG、SVG、WebP,单张不超过 2 MiB。
|
|
11
|
+
- 宿主半边为图提供三条私有路由:`/dsh-claude-style/brand` 回答两张图在不在以及随字节变化的版本;`/brand/mark` 与 `/brand/wordmark` 以 `GET` 送出、`PUT` 替换、`DELETE` 删除。读写都过同一道围栏(D11);写入先经临时文件再改名;图的应答带 `sandbox` 安全策略与 `nosniff`,单独打开一张 SVG 也执行不了脚本。读者手工放进目录的图在下一次读状态时生效。
|
|
12
|
+
- 浏览器半边由 `features/brand` 读状态与偏好,把每一项写成 `<body>` 上的属性(有标志图、文字标志是图还是文字、按文字色着色、有主色)与对应的自定义属性;样式表按属性画:侧栏标志与折叠栏标志、侧栏文字标志、新会话页标志、账号行的兜底头像。文字标志的宽高比由浏览器加载图片后从自然尺寸读出,只带 `viewBox` 的 SVG 也能读到。
|
|
13
|
+
- 主色只在配色为 Claude 时生效(D30):一张样式表用 `color-mix()` 从这一个颜色推出调色板里的各个强调令牌,按钮上的文字取亮暗两种画布色里对比度更高的一个,在 JS 里算好。
|
|
14
|
+
- 设置页的上传在只读页面不可用:整页控件在禁用的 `fieldset` 里(D60)。
|
|
15
|
+
|
|
16
|
+
## 理由
|
|
17
|
+
|
|
18
|
+
- 自定义只换标志与颜色,不带来新的行为分歧,叠一层属性比加第三档品牌改动小:现有按品牌分支的规则都不用决定第三档该落到哪边。
|
|
19
|
+
- 图是几 KB 到几百 KB 的二进制,放进设置文档会让每次读写设置都带着它;单独的目录也让读者能直接替换文件。
|
|
20
|
+
|
|
21
|
+
## 代价
|
|
22
|
+
|
|
23
|
+
- 宿主半边多三条路由与一个写入目录;只升级插件、没重启宿主时,旧的宿主半边没有这些路由,自定义图缺席。
|
|
24
|
+
- 主色的悬停与链接色是按固定比例混出来的,个别颜色上不如手调的调色板准。
|
|
25
|
+
|
|
26
|
+
## 重审条件
|
|
27
|
+
|
|
28
|
+
- 宿主的 `sidebar.brand.mark` / `sidebar.brand.name` 插槽成为稳定扩展点时,侧栏的标志与名称改为注册插槽组件(D43)。
|
|
29
|
+
- 宿主提供插件级的文件存储服务时,图改存到那里。
|
package/docs/decisions/README.md
CHANGED
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
| [D58](D58-redraw-retired.md) | 移除「重绘」档,过程组标题的计数摘要与等待行搬进「增强」档 | 已实施 |
|
|
73
73
|
| [D62](D62-file-row-merge.md) | 同一文件的多次改动读成一行 | 已实施 |
|
|
74
74
|
| [D63](D63-turn-status-retired.md) | 删除轮次状态行,运行中的说法归等待行一处 | 已实施 |
|
|
75
|
+
| [D64](D64-custom-brand.md) | 自定义品牌是叠在两档品牌之上的一层 | 已实施 |
|
|
75
76
|
|
|
76
77
|
## 分发与流程
|
|
77
78
|
|
|
Binary file
|
|
Binary file
|
package/lib/assets/manifest.json
CHANGED
|
@@ -151,15 +151,15 @@
|
|
|
151
151
|
"encoding": "br",
|
|
152
152
|
"bytes": 109821
|
|
153
153
|
},
|
|
154
|
-
"
|
|
154
|
+
"84b3319c06fb.js": {
|
|
155
155
|
"type": "text/javascript; charset=utf-8",
|
|
156
156
|
"encoding": "br",
|
|
157
|
-
"bytes":
|
|
157
|
+
"bytes": 25786
|
|
158
158
|
},
|
|
159
|
-
"
|
|
159
|
+
"91558108acf4.js.map": {
|
|
160
160
|
"type": "application/json; charset=utf-8",
|
|
161
161
|
"encoding": "br",
|
|
162
|
-
"bytes":
|
|
162
|
+
"bytes": 81884
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
}
|