dsh-claude-style 0.7.2 → 0.8.0

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 CHANGED
@@ -2,6 +2,50 @@
2
2
 
3
3
  All notable changes to `dsh-claude-style` are documented here, newest first.
4
4
 
5
+ ## [0.8.0] - 2026-09-26
6
+
7
+ [中文](#cn-0.8.0) | [English](#en-0.8.0)
8
+
9
+ <h3 id="cn-0.8.0">体验优化</h3>
10
+
11
+ - **对话 / 轨迹 / 上下文切换时高亮块平滑滑动**:切换视图时,高亮块此前在原标签上淡出、在新标签上淡入;现在同一块高亮从原标签滑到新标签,宽度随标签文字一起变化,标签文字颜色同步过渡。滑动不受系统「减少动态效果」设置影响,Windows 关掉了「在 Windows 中显示动画」时照样滑动。
12
+ - **权限分段、进行中 / 已归档与设置页分段控件的高亮块同样滑动**:只读 / 编辑 / 自动 / Yolo、侧栏的进行中 / 已归档,以及设置页里的各组分段控件,切换时高亮块都从原来那一段滑到新的一段,与对话视图标签同一套动画。
13
+ - **页面持续变化时插件的每帧开销大幅下降**:流式输出、打字机效果这类每帧都改动页面内容的场景,插件样式表此前让浏览器每帧的样式重算从 1.6ms 涨到 11–18ms,每帧主线程总耗时 14–23ms,超过一帧 16.7ms 的预算而掉帧;现在同一场景下样式重算为每帧 1.9–2.7ms,总耗时 5–7ms(本机无界面 Chrome 实测)。界面外观不变。
14
+ - **工作区选择菜单改为 Claude Code 的文件夹菜单样式**:菜单此前每行前面都有一个文件夹图标,行距与档位菜单的两行条目一样宽;现在是一张窄卡片,纯文字行排得更紧,文件夹图标与「添加工作区…」前的加号都不画,当前工作区仍以强调色勾号标出。档位菜单保持原样。
15
+ - **用量面板的倍数趣味行从十一本书扩到二十九本**:标尺书单补入《道德经》《爱丽丝漫游奇境》《圣诞颂歌》《弗兰肯斯坦》《道林·格雷的画像》《福尔摩斯冒险史》《哈克贝利·费恩历险记》《简·爱》《德古拉》,以及四大名著、《三体》三部曲、《活着》《平凡的世界》等中文书目,整份书单从《道德经》(约 7.6K tokens)排到《追忆似水年华》。书长改用真实口径:公有领域原书按全文以 o200k_base 分词器实测,仍在版权期的书目按出版字数以同一分词器实测的比例折算,几本英文经典的长度也按实测值更新。英文界面的这一行改为 “You've used ~N× the tokens in <书名>.”,此前的 “~N× more tokens than” 读起来是多出 N 倍,与实际倍数差了一倍。
16
+ - **账号弹层卡片改用象牙白底色**:浅色模式下,账号弹层与宿主账号菜单此前是纯白卡片,和界面其余部分的暖色调不一致;现在与主画布同为象牙白 `#FCFCFB`,靠细边框和阴影与侧栏区分。暗色模式不变。
17
+
18
+ ### 问题修复
19
+
20
+ - 修复 **侧栏「已归档」显示「没有已归档的会话」**:插件启动时宿主的归档数据往往还没到,列表就一直停在空白;现在列表跟随宿主的归档记录与会话列表实时更新,启动后、在别处归档或取消归档后都立刻反映。列表收录的会话与宿主自带「仅已归档」筛选一致(不含子代理会话与已不存在的会话),每行显示宿主给出的标题,不再出现成片的「未命名会话」;会话多时列表在侧栏内滚动,不再被截在窗口底部。
21
+ - 修复 **点击已归档行没有任何反应**:现在与宿主会话树里点已归档会话一样,窗口顶部弹出宿主自己的提示「已归档对话暂时无法查看,请取消归档后查看」。
22
+ - 修复 **英文界面下「排队发送」「插话发送」按钮的外观与中文界面不一致**:英文界面下,回复进行中且草稿非空时,这两个按钮此前不显示强调色,悬停时也没有底色;现在与中文界面一致。输入框里各按钮改为按它们在宿主界面中的位置识别,不再依赖按钮文字,宿主改动按钮文案或切换界面语言都不影响样式。
23
+
24
+ ### 其他变更
25
+
26
+ - **页面标出正在运行的构建**:`<body>` 上的 `data-dsh-claude-style` 属性现在写着已加载的包的构建编号(`npm run build` 会打印同一个编号),报告问题时即使页面经过多次热重载、从未刷新,也能说清运行的是哪一版。
27
+
28
+ <h3 id="en-0.8.0">Improvements</h3>
29
+
30
+ - **The Chat / Trajectory / Context highlight slides between tabs**: switching views used to fade the highlight out on the old tab and in on the new one; now one highlight slides from the old tab to the new one, resizing to the new label as it goes, while the labels' colours cross over. The slide ignores the system's reduced-motion setting, so it still plays with Windows' "Show animations in Windows" turned off.
31
+ - **The permission segments, Active / Archived and the settings page's segmented controls slide their highlight too**: Read / Edit / Auto / Yolo, the sidebar's Active / Archived, and every segmented control on the settings page now slide the highlight from the old segment to the new one, with the same motion as the conversation view tabs.
32
+ - **Much lower per-frame cost while the page keeps changing**: when content changes every frame (streaming output, a typewriter effect), the plugin's stylesheet used to raise the browser's style recalculation from 1.6ms to 11–18ms per frame, for 14–23ms of main-thread work per frame — over the 16.7ms frame budget, so frames dropped. The same scenario now costs 1.9–2.7ms of style recalculation and 5–7ms in total per frame (measured locally in headless Chrome). Nothing on screen looks different.
33
+ - **The workspace picker takes the look of Claude Code's folder menu**: every row used to carry a folder glyph and was spaced like the preset menu's two-line entries; it is now a narrow card of plain text rows set closer together, with no folder glyph and no plus sign on "Add workspace…", and the current workspace keeps the accent check. The preset menu is unchanged.
34
+ - **The usage panel's yardstick line grows from eleven to twenty-nine books**: the list adds Tao Te Ching, Alice's Adventures in Wonderland, A Christmas Carol, Frankenstein, The Picture of Dorian Gray, The Adventures of Sherlock Holmes, Adventures of Huckleberry Finn, Jane Eyre and Dracula, plus the Chinese classics — the Four Great Classical Novels, the Three-Body trilogy, To Live and Ordinary World — with the whole list spanning Tao Te Ching (~7.6K tokens) to In Search of Lost Time. Book lengths now carry a real basis: public-domain originals are measured by feeding their full text to the o200k_base tokenizer, and in-copyright titles are their published word counts at the ratio that tokenizer measures, with several English classics' lengths updated to the measured values. The English line now reads "You've used ~N× the tokens in <book>."; the former "~N× more tokens than" said N times more, one whole book off the real multiple.
35
+ - **The account popover's card takes the ivory canvas fill**: in light mode the account popover and the host's account menu were pure white cards, out of tone with the warm rest of the interface; they now share the main canvas's ivory `#FCFCFB`, set off from the sidebar by their hairline and shadow. Dark mode is unchanged.
36
+
37
+ ### Bug Fixes
38
+
39
+ - Fixed **the sidebar's Archived view reading "No archived conversations"**: the host's archive data usually arrives after the plugin starts, and the list stayed empty. The list now follows the host's archive record and session list live, so it fills in after startup and reflects archiving or unarchiving done anywhere. It holds the same conversations as the host's own "Archived only" filter (no subagent sessions, no sessions that no longer exist), each row carries the host's title instead of a run of "Untitled conversation", and a long list scrolls inside the sidebar instead of being cut off at the bottom of the window.
40
+ - Fixed **clicking an archived row doing nothing**: it now raises the host's own notice at the top of the window, "Archived sessions cannot be opened. Unarchive it to view.", the same one the host's session tree shows for an archived session.
41
+ - Fixed **the Queue message and Steer message buttons looking different in the English UI**: in English, with a reply running and a non-empty draft, these two buttons showed no accent colour and no hover fill; they now match the Chinese UI. The composer's buttons are now recognised by where they sit in the host's markup rather than by their text, so a host wording change or a switch of the UI language leaves their styling intact.
42
+
43
+ ### Chores
44
+
45
+ - **The page states which build it is running**: the `data-dsh-claude-style` attribute on `<body>` now carries the build id of the loaded bundle (`npm run build` prints the same id), so a bug report can name the exact build even after hot reloads that never reloaded the page.
46
+
47
+ **Full Changelog**: [v0.7.2...v0.8.0](https://github.com/Nwflower/dsh-claude-style/compare/v0.7.2...v0.8.0)
48
+
5
49
  ## [0.7.2] - 2026-09-25
6
50
 
7
51
  [中文](#cn-0.7.2) | [English](#en-0.7.2)
package/README.en.md CHANGED
@@ -63,13 +63,13 @@ Keep only one theme enabled at a time. After installation, **restart `dsh web`**
63
63
  ## Features
64
64
 
65
65
  1. **Theme** — applies globally the moment it is installed, with nothing to configure. Light mode uses ivory `#FCFCFB`, dark mode warm black `#141413`, and both share the same ember orange `#D97757` action accent; light/dark follows the system color mode.
66
- 2. **Composer** — the input box is rebuilt from the ground up: a permission segmented control (Read / Edit / Auto / Yolo) with its tier list under it, a model trigger carrying the vendor lockup, and the toolbar and status stats laid out on a single line, with the send and stop buttons unified into 7px rounded rectangles. The stats sentence and the model trigger share the same font size and color. The permission tiers come from the host's own catalog: a deployment draws exactly the tiers it configures, and a tier a third-party plugin registers (the auto mode plugin's `auto-mode`, say) appears in the list and takes the Auto slot; the list stays text-only, so a tier's declared glyph is not drawn.
66
+ 2. **Composer** — the input box is rebuilt from the ground up: a permission segmented control (Read / Edit / Auto / Yolo) with its tier list under it, a model trigger carrying the vendor lockup, and the toolbar and status stats laid out on a single line, with the send and stop buttons unified into 7px rounded rectangles. The stats sentence and the model trigger share the same font size and color. The permission tiers come from the host's own catalog: a deployment draws exactly the tiers it configures, and a tier a third-party plugin registers (the auto mode plugin's `auto-mode`, say) appears in the list and takes the Auto slot; the list stays text-only, so a tier's declared glyph is not drawn. Switching tiers slides the highlight from the old tier to the new one, and every segmented control on the settings page does the same.
67
67
  3. **Model picker** — a new two-level popover. The first level lists the official service plus the quick providers selected in settings; "More models" opens a second level grouped by provider. Every row carries its vendor lockup and a description, and the footer holds the reasoning-effort slider (stepless — it snaps to the nearest level on release) together with the "More models" entry. The second level aligns its bottom edge with the first, providers already shown on the first level are not repeated, and models without thinking support get no slider. Hovering opens the popover after a 100 ms dwell and closes it after 150 ms; the gap between the two cards does not count as leaving.
68
- 4. **Workspace** — the sidebar's "Workspace" heading becomes an **Active / Archived** segmented control. Active keeps the host's session tree, while Archived is the skin's own flat list (title, time, and per-row unarchive and delete icon buttons). Rows match the host's session rows measurement for measurement (row x=12 / width 251 / height 28 / title x=36).
68
+ 4. **Workspace** — the sidebar's "Workspace" heading becomes an **Active / Archived** segmented control. Active keeps the host's session tree, while Archived is the skin's own flat list (title, time, and per-row unarchive and delete icon buttons). Rows match the host's session rows measurement for measurement (row x=12 / width 251 / height 28 / title x=36). Switching between the two views slides the highlight from one segment to the other.
69
69
  5. **Sidebar** — the New session and Plugins rows take Claude's real shape: no background at rest, a background on hover, the "+" of New session set inside a circular chip, and both icons rotating 90° clockwise on hover (four-fold symmetric glyphs, so they land back on themselves). The account drawer and the ban-screen easter egg remain as they were.
70
- 6. **Account area** — the nickname and the picture each follow one fixed order. Nickname: the custom nickname → the signed-in account's name → the HDSL launcher's account name → the last probed system user → the freshly probed system user → `User`. Picture: the signed-in account's avatar → the HDSL launcher's avatar → the Claude mark. The account profile is fetched from the server only at startup, on hot reload, and on sign-in and sign-out — never polled. The HDSL contract is read once by the host half and forwarded over two read-only routes (`GET /dsh-claude-style/hdsl` for the metadata, `GET /dsh-claude-style/hdsl-skin.png` for the avatar image; neither carries the avatar file's absolute path, and both sit behind the host's request fence). A contract version that is missing or unknown voids the whole group, and a deleted avatar file falls back to the mark. What the launcher publishes is a skin sheet rather than a finished avatar, so that picture is cropped into the head first — the face's 8×8 texel block inset by 1/18 of the box with the hat layer over the whole box, drawn square so no rounding shaves its pixels. The account popover remains the host's own: the host's account row is the entry point, and the popover lists the account header, the other plugins' footer entries, and the host's own Settings / Feedback / Sign out, each keeping its original copy, order, and click behavior. On hosts without an account area (Web), the plugin builds a popover with the same look. The card uses a pure white background and spans the sidebar's width.
71
- 7. **Conversation views** — in the desktop Windows titlebar mode, the Conversation / Trajectory control sits centered and always visible on the titlebar row (the same row as the New session button). On wide windows with a short title it stays on the title's row; otherwise it keeps its own row below the title.
72
- 8. **Home layouts** — the new-conversation page comes in two layouts, Studio by default and switchable in the settings page at any time: **Classic** is the centered headline over the composer card, the headline drawn from a pool of greetings for the time of day (a few each for morning, midday, afternoon, evening and night, plus a few for any hour) and redrawn each time the new-conversation page comes back; **Studio** pins the greeting to the top left as one fixed line ("What's up next, <user>?"), docks the composer in the conversation's single-line form at the window's bottom edge with a row of hairline context chips above it, and sets the greeting and a 480px usage panel against the composer's left edge: an Overview tab with six stat cells (sessions, messages, total tokens, active days, peak hour, favorite model) and a twenty-six-week per-day heat grid of square cells in equal columns, a Models tab stacking each day's per-model tokens into one bar over a ranked model list (swatch, name, input and output, share; past six rows it folds behind a "show more" row, and the open list folds back with "show less"), and All / 30d / 7d range pills at the top right, which the peak hour and the multiplier line follow too; once the picked range's total passes one book, a multiplier line appears under the grid, naming one of eleven books (Animal Farm to In Search of Lost Time) drawn afresh each time the new-conversation page comes back. The numbers are rolled up by the plugin's host half: with `dsh-cost-meter` installed it reads that plugin's ledger cache directly (read-only — their file is never written), and without it the host half folds the local session logs itself, caching per log by size and modification time. Both sources answer each model's four buckets and each day's per-model tokens, with one model served by several providers counted as one row; the ledger keeps no hours, so the peak hour is always folded per day from the local session logs; when the roll-up cannot answer, the panel falls back to the projection block each host session row carries. The panel draws its skeleton first and does not shift when the numbers land. Before a workspace is picked (a fresh start, no session yet), the usage panel and the Read / Edit / Auto / Yolo permission segments still show; the segments rest on the preset a new session starts in, and pressing them opens the workspace picker, the same as pressing the input box, whose dashed "pick a workspace" ring now outlines the single-line input box alone. When the window is too short for the whole panel, the panel scrolls between the greeting and the composer with its bottom edge fading out, and the page no longer runs past the window.
70
+ 6. **Account area** — the nickname and the picture each follow one fixed order. Nickname: the custom nickname → the signed-in account's name → the HDSL launcher's account name → the last probed system user → the freshly probed system user → `User`. Picture: the signed-in account's avatar → the HDSL launcher's avatar → the Claude mark. The account profile is fetched from the server only at startup, on hot reload, and on sign-in and sign-out — never polled. The HDSL contract is read once by the host half and forwarded over two read-only routes (`GET /dsh-claude-style/hdsl` for the metadata, `GET /dsh-claude-style/hdsl-skin.png` for the avatar image; neither carries the avatar file's absolute path, and both sit behind the host's request fence). A contract version that is missing or unknown voids the whole group, and a deleted avatar file falls back to the mark. What the launcher publishes is a skin sheet rather than a finished avatar, so that picture is cropped into the head first — the face's 8×8 texel block inset by 1/18 of the box with the hat layer over the whole box, drawn square so no rounding shaves its pixels. The account popover remains the host's own: the host's account row is the entry point, and the popover lists the account header, the other plugins' footer entries, and the host's own Settings / Feedback / Sign out, each keeping its original copy, order, and click behavior. On hosts without an account area (Web), the plugin builds a popover with the same look. The card uses the main canvas's ivory background and spans the sidebar's width.
71
+ 7. **Conversation views** — in the desktop Windows titlebar mode, the Conversation / Trajectory control sits centered and always visible on the titlebar row (the same row as the New session button). On wide windows with a short title it stays on the title's row; otherwise it keeps its own row below the title. Switching views slides the highlight from the old tab to the new one.
72
+ 8. **Home layouts** — the new-conversation page comes in two layouts, Studio by default and switchable in the settings page at any time: **Classic** is the centered headline over the composer card, the headline drawn from a pool of greetings for the time of day (a few each for morning, midday, afternoon, evening and night, plus a few for any hour) and redrawn each time the new-conversation page comes back; **Studio** pins the greeting to the top left as one fixed line ("What's up next, <user>?"), docks the composer in the conversation's single-line form at the window's bottom edge with a row of hairline context chips above it, and sets the greeting and a 480px usage panel against the composer's left edge: an Overview tab with six stat cells (sessions, messages, total tokens, active days, peak hour, favorite model) and a twenty-six-week per-day heat grid of square cells in equal columns, a Models tab stacking each day's per-model tokens into one bar over a ranked model list (swatch, name, input and output, share; past six rows it folds behind a "show more" row, and the open list folds back with "show less"), and All / 30d / 7d range pills at the top right, which the peak hour and the multiplier line follow too; once the picked range's total passes one book, a multiplier line appears under the grid, naming one of twenty-nine books (Tao Te Ching to In Search of Lost Time) drawn afresh each time the new-conversation page comes back. The numbers are rolled up by the plugin's host half: with `dsh-cost-meter` installed it reads that plugin's ledger cache directly (read-only — their file is never written), and without it the host half folds the local session logs itself, caching per log by size and modification time. Both sources answer each model's four buckets and each day's per-model tokens, with one model served by several providers counted as one row; the ledger keeps no hours, so the peak hour is always folded per day from the local session logs; when the roll-up cannot answer, the panel falls back to the projection block each host session row carries. The panel draws its skeleton first and does not shift when the numbers land. Before a workspace is picked (a fresh start, no session yet), the usage panel and the Read / Edit / Auto / Yolo permission segments still show; the segments rest on the preset a new session starts in, and pressing them opens the workspace picker, the same as pressing the input box, whose dashed "pick a workspace" ring now outlines the single-line input box alone. When the window is too short for the whole panel, the panel scrolls between the greeting and the composer with its bottom edge fading out, and the page no longer runs past the window. The workspace picker is drawn as Claude Code's folder menu: a narrow card of plain text rows set closer together, with no folder glyph in front of each folder and no plus sign on "Add workspace…"; the current workspace keeps the accent check.
73
73
  9. **The pixel crab** — in the Studio layout, Claude Code's pixel crab stands on the new-conversation composer card's top edge, near its right end (the Classic layout has none). When it is clicked or the pointer leaves it (and on its own every half minute or so while the page is open), it plays Claude Code's fishing routine: a half turn and a wink, the rod raised and cast down onto the card's edge, a spell of fishing side-on, and the rod put away as it turns back — about three seconds. With reduced motion requested (Windows' "Show animations in Windows" turned off, for one), it moves only when clicked.
74
74
 
75
75
  ## Disabling and uninstalling
package/README.md CHANGED
@@ -63,13 +63,13 @@ dsh plugin --profile web add Nwflower/dsh-claude-style # GitHub 源
63
63
  ## 特点
64
64
 
65
65
  1. **主题** —— 安装即全局生效,无需配置。亮色象牙白 `#FCFCFB`、暗色暖黑 `#141413`,两套画布共用同一个操作强调色陶烬橙 `#D97757`;亮暗跟随系统颜色模式切换。
66
- 2. **输入框** —— 输入框整块重做:权限分段控件(只读 / 编辑 / 自动 / Yolo)与它下方的档位列表、带品牌锁定标的模型触发器、工具栏与状态统计同一行排版,发送键与停止键统一成 7px 圆角。统计句与模型触发器共用一套字号与颜色。权限档位取自宿主的权限目录:宿主配置了哪几档就画哪几档,第三方插件注册的档位(例如 auto mode 插件的 `auto-mode`)会自动出现在列表里并占用「自动」那一格;列表保持纯文字,档位自己声明的图标不画。
66
+ 2. **输入框** —— 输入框整块重做:权限分段控件(只读 / 编辑 / 自动 / Yolo)与它下方的档位列表、带品牌锁定标的模型触发器、工具栏与状态统计同一行排版,发送键与停止键统一成 7px 圆角。统计句与模型触发器共用一套字号与颜色。权限档位取自宿主的权限目录:宿主配置了哪几档就画哪几档,第三方插件注册的档位(例如 auto mode 插件的 `auto-mode`)会自动出现在列表里并占用「自动」那一格;列表保持纯文字,档位自己声明的图标不画。切换档位时,高亮块从原档位平滑滑到新档位;设置页里的各组分段控件也是如此。
67
67
  3. **模型选择器** —— 全新的两级弹层:一级列官方服务与设置页勾选的快捷供应商,「更多模型」二级按供应商分组;每行带厂商锁定标与说明文案,底部是推理等级推条(无极滑动,松手对齐最近档位)与「更多模型」入口。二级底边与一级对齐,一级已显示的供应商不再重复;模型不支持思考时不画推条。悬停停留 100ms 打开、离开 150ms 关闭,两卡之间的空隙不算离开。
68
- 4. **工作区** —— 侧栏「工作区」标题改成 **进行中 / 已归档** 分段控件:进行中沿用宿主的会话树,已归档是皮肤自己的平铺列表(标题、时间、每行「取消归档」与「删除」两个图标按钮)。行排版与宿主的会话行逐项一致(行 x=12 / 宽 251 / 高 28 / 标题起点 x=36)。
68
+ 4. **工作区** —— 侧栏「工作区」标题改成 **进行中 / 已归档** 分段控件:进行中沿用宿主的会话树,已归档是皮肤自己的平铺列表(标题、时间、每行「取消归档」与「删除」两个图标按钮)。行排版与宿主的会话行逐项一致(行 x=12 / 宽 251 / 高 28 / 标题起点 x=36)。切换两种视图时,高亮块在两段之间平滑滑动。
69
69
  5. **侧栏** —— 新会话与插件两行取 Claude 真机形状:默认无底色、hover 才有底色,新会话的「+」套一枚圆形底,两行图标 hover 顺时针转 90°(四重对称图形,转回原位);底部账户抽屉、封号彩蛋一并保留。
70
- 6. **账号区** —— 昵称与头像各走一条固定顺序。昵称:自定义昵称 → 官方账号昵称 → HDSL 启动器昵称 → 上次探测到的系统用户名 → 本次探测到的系统用户名 → `User`;头像:官方账号头像 → HDSL 启动器头像 → Claude 徽标。官方账号资料只在启动、热重载、登录与登出时向服务器读取,不轮询;HDSL 契约由宿主半边读一次后经两条只读路由转发(`GET /dsh-claude-style/hdsl` 回账号元数据、`GET /dsh-claude-style/hdsl-skin.png` 回头像图片,都不含头像文件的绝对路径,并过宿主的请求栅栏),契约版本读不到或不认识时整组忽略,头像文件被删除时回落到徽标。启动器给的是皮肤贴图而不是成品头像,因此账号位置的头像由贴图裁出:脸部 8×8 贴图块按盒子 1/18 内缩、帽子层铺满整盒,方形绘制不被圆角裁切。账号弹层沿用宿主自带的那一个:宿主的账号行就是入口,弹层里依次是账号头部、其它插件的页脚条目与宿主自己的「设置 / 意见反馈 / 退出登录」,各行的文案、顺序与点击行为保持宿主原样;宿主没有账号区的环境(Web)由插件自建同样外观的弹层。弹层卡片为纯白背景、宽度与侧栏一致。
71
- 7. **对话视图** —— 对话 / 轨迹控件在桌面 Windows 标题栏模式下居中常显在标题栏那一行(与新会话按钮同一行);宽窗口且标题较短时它停在标题那一行,否则留在标题下方自己那一行。
72
- 8. **首页版面** —— 新会话页有两套版面,默认是工作台,在设置页随时切换:**经典**是居中大标题加输入卡片,标题按时段从一组问候里抽一句(早上、午间、下午、晚上、深夜各有几句,另有几句不分时段),每次回到新会话页换一句;**工作台**把标题移到左上并固定为一句「What's up next, 用户名?」,输入框改用对话内的单行样式贴住窗口底部、上方一行细边框上下文胶囊,标题与一块 480px 窄栏用量面板贴着输入框左缘排布:概览页签是六个数字格(会话数、消息数、Token 总量、活跃天数、高峰时段、最常用模型)与 26 周按天热力图(等分列方格),模型页签是每天一根按模型颜色堆叠的柱子加一份模型排行(色块、模型名、输入与输出、占比,超过六行折成「再显示 N 个」,展开后可「收起」),右上角的「全部 / 30 天 / 7 天」切换统计范围(高峰时段与趣味行一并跟随);所选范围内的用量超过一本书时,热力图下方出现倍数趣味行,书目共十一本(《动物农场》到《追忆似水年华》),每次回到新会话页随机换一本。数据由插件的宿主半边汇总:装了 `dsh-cost-meter` 时直接读它的账本缓存(只读,不写对方文件),没有时读本机会话日志自己算,并按日志的文件大小与修改时间增量缓存;两种来源都按模型给出四类 token、按天给出各模型的 token,同一模型经不同提供方的用量合成一行;账本不记小时,高峰时段始终由本机会话日志按天算出;汇总不可用时面板改用宿主会话列表每行自带的投影值。数字没到之前面板先画骨架,位置在填充前后不变。还没选工作区时(刚打开、尚无会话),用量面板与 Read / Edit / Auto / Yolo 权限分段照常显示,分段停在新会话的默认权限上,点它和点输入框一样打开工作区选择;表示「先选工作区」的虚线框只框住单行输入框本身。窗口高度放不下整块面板时,面板在问候语与输入框之间自己滚动、底边渐隐,页面不会被撑出窗口。
70
+ 6. **账号区** —— 昵称与头像各走一条固定顺序。昵称:自定义昵称 → 官方账号昵称 → HDSL 启动器昵称 → 上次探测到的系统用户名 → 本次探测到的系统用户名 → `User`;头像:官方账号头像 → HDSL 启动器头像 → Claude 徽标。官方账号资料只在启动、热重载、登录与登出时向服务器读取,不轮询;HDSL 契约由宿主半边读一次后经两条只读路由转发(`GET /dsh-claude-style/hdsl` 回账号元数据、`GET /dsh-claude-style/hdsl-skin.png` 回头像图片,都不含头像文件的绝对路径,并过宿主的请求栅栏),契约版本读不到或不认识时整组忽略,头像文件被删除时回落到徽标。启动器给的是皮肤贴图而不是成品头像,因此账号位置的头像由贴图裁出:脸部 8×8 贴图块按盒子 1/18 内缩、帽子层铺满整盒,方形绘制不被圆角裁切。账号弹层沿用宿主自带的那一个:宿主的账号行就是入口,弹层里依次是账号头部、其它插件的页脚条目与宿主自己的「设置 / 意见反馈 / 退出登录」,各行的文案、顺序与点击行为保持宿主原样;宿主没有账号区的环境(Web)由插件自建同样外观的弹层。弹层卡片为象牙白背景(与主画布同色)、宽度与侧栏一致。
71
+ 7. **对话视图** —— 对话 / 轨迹控件在桌面 Windows 标题栏模式下居中常显在标题栏那一行(与新会话按钮同一行);宽窗口且标题较短时它停在标题那一行,否则留在标题下方自己那一行。切换视图时,高亮块从原标签平滑滑到新标签。
72
+ 8. **首页版面** —— 新会话页有两套版面,默认是工作台,在设置页随时切换:**经典**是居中大标题加输入卡片,标题按时段从一组问候里抽一句(早上、午间、下午、晚上、深夜各有几句,另有几句不分时段),每次回到新会话页换一句;**工作台**把标题移到左上并固定为一句「What's up next, 用户名?」,输入框改用对话内的单行样式贴住窗口底部、上方一行细边框上下文胶囊,标题与一块 480px 窄栏用量面板贴着输入框左缘排布:概览页签是六个数字格(会话数、消息数、Token 总量、活跃天数、高峰时段、最常用模型)与 26 周按天热力图(等分列方格),模型页签是每天一根按模型颜色堆叠的柱子加一份模型排行(色块、模型名、输入与输出、占比,超过六行折成「再显示 N 个」,展开后可「收起」),右上角的「全部 / 30 天 / 7 天」切换统计范围(高峰时段与趣味行一并跟随);所选范围内的用量超过一本书时,热力图下方出现倍数趣味行,书目共二十九本(《道德经》到《追忆似水年华》),每次回到新会话页随机换一本。数据由插件的宿主半边汇总:装了 `dsh-cost-meter` 时直接读它的账本缓存(只读,不写对方文件),没有时读本机会话日志自己算,并按日志的文件大小与修改时间增量缓存;两种来源都按模型给出四类 token、按天给出各模型的 token,同一模型经不同提供方的用量合成一行;账本不记小时,高峰时段始终由本机会话日志按天算出;汇总不可用时面板改用宿主会话列表每行自带的投影值。数字没到之前面板先画骨架,位置在填充前后不变。还没选工作区时(刚打开、尚无会话),用量面板与 Read / Edit / Auto / Yolo 权限分段照常显示,分段停在新会话的默认权限上,点它和点输入框一样打开工作区选择;表示「先选工作区」的虚线框只框住单行输入框本身。窗口高度放不下整块面板时,面板在问候语与输入框之间自己滚动、底边渐隐,页面不会被撑出窗口。工作区选择菜单照 Claude Code 的文件夹菜单绘制:窄卡片、纯文字行排得更紧,每行前面的文件夹图标与「添加工作区…」前的加号都不画,当前工作区仍以强调色勾号标出。
73
73
  9. **像素螃蟹** —— 工作台版面的新会话页上,输入卡片上沿、靠右的位置站着 Claude Code 的像素螃蟹(经典版面没有)。点它一下、或指针从它身上移开时(页面开着时也会每隔二三十秒自己来一次),它会照 Claude Code 的样子钓一次鱼:半转身眨眼,举起鱼竿甩到卡片边上,侧身钓一会儿,再收竿转回正面,前后约三秒。系统要求减少动态效果时(例如 Windows 关掉了「在 Windows 中显示动画」),它只在被点击时才动。
74
74
 
75
75
  ## 停用与卸载
package/docs/STYLE.md CHANGED
@@ -77,7 +77,7 @@ Both are solid (never translucent) and `!important`, so they override whatever
77
77
  colour the text underneath carries — links, inline code, syntax tokens. CSS
78
78
  cannot read window focus: Chromium reaches the inactive paint through its own
79
79
  internal `-internal-inactive-selection-*` properties, which a stylesheet cannot
80
- address. `src/overrides/selection.js` therefore mirrors `document.hasFocus()`
80
+ address. `src/features/selection/selection.js` therefore mirrors `document.hasFocus()`
81
81
  onto `data-dsh-window-blur` and the stylesheet switches on that attribute; the
82
82
  selection itself survives the blur.
83
83
 
@@ -117,7 +117,7 @@ the account drawer, the session-stats card, and the host's own menu primitive
117
117
  under the hero row's workspace and preset pickers — is meant to start from one
118
118
  recipe. New popovers take it rather than inventing a card.
119
119
 
120
- Two rules hold across all of them, both owned by `overrides/popover-utils.js`. A
120
+ Two rules hold across all of them, both owned by `shared/popover.js`. A
121
121
  pointer opens a card only after a **100 ms dwell** — long enough that crossing a
122
122
  28px trigger on the way somewhere else unfolds nothing — and the card closes
123
123
  100 ms after the pointer leaves. Two cards keep their own numbers with the reason
@@ -174,31 +174,37 @@ takes the longest stable piece of whichever family it targets — `_itemWrap_`,
174
174
  never the bare local name.
175
175
 
176
176
  The hero row's two pickers are that primitive, portaled to `<body>` with no
177
- marker of their own. `src/overrides/hero-menu.js` stamps the open card with
178
- `data-dsh-claude-hero-menu` and `components/hero-menu.css` restyles it; the
177
+ marker of their own. `src/features/hero-menu/hero-menu.js` stamps the open card with
178
+ `data-dsh-claude-hero-menu` and `features/hero-menu/hero-menu.css` restyles it; the
179
179
  host's other menus (sidebar row menus, the settings permission row, submenus)
180
180
  keep the host's own design on purpose. What that replaces: a 20px radius card
181
181
  with 4px padding, 40px rows at 10px radius, and 14px text.
182
182
 
183
+ The stamp's value names the picker (`workspace` or `preset`), because the two
184
+ cards differ. The preset card keeps the popover table's 32px rows for its
185
+ two-line entries. The workspace card is Claude Code's folder menu: a 180px-min
186
+ card with 4px padding, 26px plain-text rows (no folder glyph in front of each
187
+ folder, no `+` on the pinned add row) and the accent check on the current one.
188
+
183
189
  **All five are aligned**: the account drawer and the stats card were the outliers
184
190
  (8px row radius, 2px and 4px card gap, 8px padding, 220 / 260px min-width,
185
191
  z-index 1000 and 100000) and now follow the table above. The hero row's pickers are the host's own menu primitive, which differs in
186
192
  two ways that CSS cannot change: it mounts instead of toggling a `data-open`
187
193
  attribute, so it takes the same fade/scale as a one-shot `0.15s` animation; and
188
194
  the host places it *below* its trigger, which is where the composer sits — so
189
- `src/overrides/hero-menu.js` re-places it beside the trigger (bottom-aligned,
195
+ `src/features/hero-menu/hero-menu.js` re-places it beside the trigger (bottom-aligned,
190
196
  growing upward into the empty hero space, flipping left when the viewport is
191
197
  tight). The host re-runs its own placement from its anchor geometry on every
192
198
  frame while the card is open, so the position is handed over in two custom
193
199
  properties on the card (`--dsh-claude-hero-menu-x` / `--dsh-claude-hero-menu-y`,
194
- written by the same pass that stamps it) which `components/hero-menu.css` reads
200
+ written by the same pass that stamps it) which `features/hero-menu/hero-menu.css` reads
195
201
  with `!important`; that declaration outranks the host's plain inline value.
196
202
 
197
203
  ## Home layouts · 首页版面
198
204
 
199
205
  The new-conversation page has two arrangements. `homeLayout` (settings: Home
200
206
  layout) writes `data-dsh-claude-home-layout` onto `<body>` and
201
- `src/styles/components/home-panel.css` branches on it. Both are the host's own
207
+ `src/features/home/home-panel.css` branches on it. Both are the host's own
202
208
  hero markup — the greeting, the workspace row, the dock and the composer card
203
209
  inside `…_composerStack …_composerHero` — so only the arrangement differs.
204
210
 
@@ -212,7 +218,7 @@ inside `…_composerStack …_composerHero` — so only the arrangement differs.
212
218
 
213
219
  The studio composer is stamped `data-composer-variant="inline"` (composer.js's
214
220
  pass reads the same preference), so the home card is drawn by the conversation's
215
- single-line stylesheet. The classic tray rules in `composer/card.css` are scoped
221
+ single-line stylesheet. The classic tray rules in `features/composer/card.css` are scoped
216
222
  away from studio with `:not([data-dsh-claude-home-layout="studio"])`. That is
217
223
  deliberate: they set `order: 1` / `order: 2` on the same boxes, and a competing
218
224
  rule would have to be out-specified rather than merely reordered — scoping them
@@ -250,8 +256,12 @@ bold figure — the figure stays barely above its own label, which is also what
250
256
  lets a long model id such as deepseek-v4.1-flash sit on one line; the favourite
251
257
  model is a name, not a figure, and keeps the regular weight. Messages are the
252
258
  settled calls. Once the picked range's total passes one
253
- book, the yardstick line appears under the grid: eleven books from Animal Farm
254
- (39k tokens) to In Search of Lost Time (1.6M), each sized at 1.3 tokens a word.
259
+ book, the yardstick line appears under the grid: twenty-nine books from Tao Te
260
+ Ching (7.6k tokens) to In Search of Lost Time (1.6M), the public-domain ones
261
+ measured by feeding their full text to the o200k_base tokenizer and the rest
262
+ estimated (1.3 tokens a word for English, 0.96 tokens a character for modern
263
+ Chinese prose). The line states the rounded multiple as a share of the book
264
+ ("~2× the tokens in Moby-Dick"), never as an excess over it.
255
265
  The book is drawn afresh each time the page comes back to the new-conversation
256
266
  hero, and a range that has not reached it steps down to the longest book it has
257
267
  passed, so the range pills keep the same book whenever the totals allow. The heat
@@ -322,115 +332,9 @@ takes the pointer; the room the rod swings through does not.
322
332
 
323
333
  - Every rule is scoped under `body[data-dsh-claude-style]`.
324
334
  - Dark tokens are the base; light overrides use `:not([data-ds-dark-theme])`.
335
+ - A surface's stylesheet sits beside its feature under `src/features/<feature>/`;
336
+ the look no single feature owns is in `src/theme/`, and the parts several
337
+ features share (the popover card and rows, the sliding highlight) are in
338
+ `src/shared/`. The source layout, the host selector discipline and the checks
339
+ the build runs are in `docs/architecture.md` (D1, D3, D9, D18, D19).
325
340
 
326
- ## Architecture · 源码结构
327
-
328
- The shipped bundle `lib/client.js` is **generated** — never edit it directly.
329
- Source lives in `src/` and `node scripts/build.mjs` (or `npm run build`)
330
- assembles the bundle. The map below annotates what each source is for; the
331
- assembly order itself is authoritative in `scripts/build.mjs`
332
- (`FRAGMENTS` / `STYLE_FILES`), which the build enforces:
333
-
334
- | Source | Content |
335
- |---|---|
336
- | `src/constants.js` | constants, spinner verbs, shared token values (evaluated at build time to fill `%%TOKEN%%` placeholders) |
337
- | `src/assets/brand/*.svg` | brand marks, inlined as CSS `url()` data URIs at build time (the loader exposes no asset URLs) |
338
- | `src/assets/icons/combine/*.svg` | vendor lockups (Lobe Icons mark + wordmark composed into one SVG, MIT), inlined as JS markup tables at build time; bound to models by `model-descriptions.json` → `brands` |
339
- | `src/assets/icons/*.svg` | hand-provided lockup artwork (e.g. ChatGPT), which the vendoring step prefers over anything fetched; `brands.lockups` may also point a brand's two halves at different Lobe icons or crop a wordmark |
340
- | `src/styles/tokens.css` | design tokens (dark base + ivory light) |
341
- | `src/styles/typography.css` | serif display / sans UI / mono code, editorial markdown |
342
- | `src/styles/chrome.css` | canvas, hairlines, clay accent, chrome details |
343
- | `src/styles/composer/hero.css` | hero brand mark and headline |
344
- | `src/styles/composer/card.css` | composer input card and footer tray (gated by composer preference) |
345
- | `src/styles/composer/inline.css` | in-conversation single-line composer (gated by composer preference) |
346
- | `src/styles/composer/inline-bar.css` | the inline composer's trailing bar: model trigger and merged time/usage stats line (gated by composer preference) |
347
- | `src/styles/sidebar.css` | sidebar brand, new-session row, workspace tree |
348
- | `src/styles/components/workspace.css` | the workspace section's 进行中 / 已归档 segment control and the skin's own archived list |
349
- | `src/styles/components/permissions.css` | permission segments and popover |
350
- | `src/styles/components/account-footer.css` | account row and floating popover |
351
- | `src/styles/components/ban-screen.css` | the account-hold easter egg (full-window overlay) |
352
- | `src/styles/components/model-picker.css` | model picker popovers |
353
- | `src/styles/components/effort-picker.css` | the reasoning-effort card, slider and its trigger |
354
- | `src/styles/components/popover.css` | shared popover chrome: header, body and menu rows |
355
- | `src/styles/components/hero-menu.css` | the host's menu primitive under the hero row's workspace/preset pickers (composer-gated) |
356
- | `src/styles/components/footer-takeover.css` | host footer takeover rules |
357
- | `src/styles/components/third-party.css` | agy-link repair rules |
358
- | `src/styles/components/settings.css` | settings page section |
359
- | `src/styles/components/home-panel.css` | the studio home layout and the usage panel's shell (keyed on the attribute `home-layout.js` writes) |
360
- | `src/styles/components/home-overview.css` | the usage panel's Overview tab: stat cells, heat grid, yardstick line |
361
- | `src/styles/components/home-models.css` | the usage panel's Models tab: the stacked chart and the ranked list |
362
- | `src/styles/components/mascot.css` | the pixel crab: its seat on the card's top edge and its inks |
363
- | `src/styles/components/theme-flip.css` | theme-flip transition suppression |
364
- | `src/context/host.js` | host accessors and helpers |
365
- | `src/context/prefs.js` | preference store |
366
- | `src/context/model-copy.js` | model copy document store |
367
- | `src/context/i18n.js` | localized copy lookups |
368
- | `src/overrides/popover-utils.js` | shared anchor positioning and hover intent |
369
- | `src/overrides/composer.js` | composer layout feature: each pass writes the variant, gate, attachment and context-ring attributes the composer stylesheets read |
370
- | `src/overrides/copy.js` | composer/copy rewrites installer |
371
- | `src/overrides/session-stats.js` | session-stats card factory (`createSessionStats`), the permissions feature's split-out half |
372
- | `src/overrides/permissions.js` | permission segments/popover installer (the stats card lives in `session-stats.js`) |
373
- | `src/overrides/model-brand.js` | brand lockup lookup: maps a catalog model to its vendored lockup through the `brands` bindings |
374
- | `src/overrides/model-copy-lookup.js` | model copy lookup: exact entry → family rule → tier rule → the catalog's own text |
375
- | `src/overrides/model/catalog.js` | model catalog factory (`createModelCatalog`): the per-session ModelDirectory store |
376
- | `src/overrides/model/rows.js` | model row factory (`createModelRows`): option cells, provider rules, level-1 sections |
377
- | `src/overrides/model-picker.js` | model picker installer, wiring the `model/` factories (thin orchestration) |
378
- | `src/overrides/effort/matrix.js` | effort matrix factory (`createEffortMatrix`): the tier data the slider snaps to |
379
- | `src/overrides/effort/control.js` | effort control factory (`createEffortControl`): the reasoning-effort slider and its card |
380
- | `src/overrides/effort-picker.js` | effort picker installer, wiring the `effort/` factories (thin orchestration) |
381
- | `src/overrides/hero-menu.js` | stamps the host menu card the hero row's pickers open |
382
- | `src/overrides/quick-providers.js` | the settings page's quick-providers multi-select popover |
383
- | `src/overrides/account/profile.js` | account profile factory (`createAccountProfile`): signed-in name/avatar reads and retries |
384
- | `src/overrides/account/host-menu.js` | host account menu factory (`createHostAccountMenu`): reads and drives the host's own menu |
385
- | `src/overrides/account/rows.js` | account rows factory (`createAccountRows`): the account popover's row builders |
386
- | `src/overrides/account/footer-mirror.js` | footer mirror factory (`createFooterMirror`): redirects other plugins' footer entries into the drawer |
387
- | `src/overrides/account/surface.js` | account surface factory (`createAccountSurface`): one row model, picks the mount point each pass (the host's account menu or the self-built popover) |
388
- | `src/overrides/account-footer.js` | account drawer installer, wiring the `account/` factories (thin orchestration) |
389
- | `src/overrides/ban-screen.js` | account-hold easter egg installer |
390
- | `src/overrides/theme-flip.js` | suppresses transitions during a theme flip, so colours and shapes land together |
391
- | `src/overrides/workspace-view.js` | workspace section feature: the 进行中 / 已归档 segments and the archived list (row delete goes through the plugin's own route) |
392
- | `src/overrides/view-tabs.js` | conversation view tabs: moves the tab bar onto the title row when it fits |
393
- | `src/overrides/home-layout.js` | home layout feature shell: writes the layout attribute, registers the usage panel into the host's dock seat, and draws the panel's head |
394
- | `src/overrides/home/data.js` | the usage panel's data: the roll-up route, the session list's fallback, and the figures both tabs read |
395
- | `src/overrides/home/overview.js` | the usage panel's Overview tab: stat cells, heat grid, yardstick line |
396
- | `src/overrides/home/models.js` | the usage panel's Models tab: the stacked chart and the ranked list |
397
- | `src/overrides/mascot.js` | the pixel crab on the new-conversation card: its poses as one inline SVG, and the fishing routine |
398
- | `src/overrides/scheduler.js` | scheduler, observers, subscriptions, teardown |
399
- | `src/overrides/selection.js` | mirrors the window's focus state onto the document for the two text-selection paints |
400
- | `src/settings.js` | settings section (brand switch) |
401
- | `src/entry.js` | `apply()` orchestrator + exports |
402
- | `src/model-descriptions.json` | model copy (picker labels + per-model descriptions); validated at build time and **copied** to `lib/`, not inlined |
403
-
404
- Fragments share one factory scope at runtime — no `import`/`export`, 4-space
405
- base indent; the build rejects unsubstituted `%%TOKENS%%` and refuses to emit a
406
- bundle that fails to parse. The hard rules for fragments, model copy and host
407
- selectors live in `AGENTS.md` (the selector section below is the detail page it
408
- points to); the reasoning behind them is in `docs/architecture.md` (D1, D3, D5).
409
-
410
- Model copy is the one thing that does **not** go into the bundle: the build
411
- copies `src/model-descriptions.json` to `lib/` and the host half serves it, so
412
- the table grows without a rebuild. The picker's brand bindings ride the same
413
- document under `brands`; the note inside the file explains why a model no rule
414
- claims draws no lockup at all.
415
-
416
- ### Host selector discipline · 宿主选择器纪律
417
-
418
- The host uses hashed CSS-module classes (`p_FcLG_row`, `_0cyzDW_viewArea`, …).
419
- Substring matchers must use the **longest stable fragment**, and every new
420
- rule should be checked for accidental hits:
421
-
422
- - `[class*="_row"]`, never `[class*="row"]` — the bare substring also matches
423
- the composer growth wrapper `…_grow` and pinned the input field to 28px.
424
- - Never override the host's active-phase layout contract on
425
- `[class*="viewArea"]` (`flex: 1 0 auto; min-height: auto`) — it is what
426
- keeps the sticky composer seat pinned to the scrollport bottom.
427
- - An anchor that carries a host button class (`_linkButton`, e.g. the settings
428
- page's "充值") is a filled or outlined control, not a text link: it states its
429
- own ink. The blanket anchor colour excludes that class — painting it leaves a
430
- filled button's label the same colour as its fill.
431
-
432
- `node scripts/probe.cjs --token <launch-token>` drives a headless Chrome over
433
- CDP and asserts the invariants (composer pinned at bottom, single-line start,
434
- content growth). `node scripts/shoot.cjs --token <launch-token>` recaptures
435
- the README screenshots (`docs/light.png` / `docs/dark.png`), swapping personal
436
- data for neutral stand-ins in the DOM before any pixel is written.