dsh-claude-style 0.7.2 → 0.9.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,90 @@
2
2
 
3
3
  All notable changes to `dsh-claude-style` are documented here, newest first.
4
4
 
5
+ ## [0.9.0] - 2026-09-26
6
+
7
+ [中文](#cn-0.9.0) | [English](#en-0.9.0)
8
+
9
+ <h3 id="cn-0.9.0">新增功能</h3>
10
+
11
+ - **侧栏搜索框与搜索面板**:鼠标移到侧栏上时,左上角的品牌标志淡出、换成一个淡入的搜索按钮(右端标出宿主的搜索快捷键),点它在窗口上方打开搜索面板;宿主的搜索快捷键(桌面端 Ctrl+K,Web 端 Ctrl+Alt+K,在设置里改过的以改后的为准)也打开这个面板,侧栏「工作区」标题行原来的搜索图标不再显示。面板打开与关闭时连同背后的遮罩一起淡入淡出。面板能搜历史会话、项目、插件、当前会话可用的 Skill 与快捷键。会话按标题、所属工作区名和对话内容搜:你和模型说过的每句话都算(工具调用的参数与子代理会话不算),句子中间的几个中文字也能搜到,不分大小写,空格多几个少几个都行;行下显示命中的那一句,命中的字加粗。插件新增只读的私有路由 `/dsh-claude-style/session-search` 供面板查询,与其他私有路由一样先过宿主的请求校验;宿主进程启动后第一次打开面板时它会把全部会话读一遍(本机 128 个会话约 16 秒,这期间面板显示「正在搜索」),之后每次查询约 0.1 秒。顶部的「全部 / 会话 / 项目 / 插件 / Skill / 快捷键」切换分类;搜索框为空时列出最近的五个会话和「新会话 / 插件 / 设置 / 键盘快捷键」几个操作。↑↓ 选择,Enter 打开,Tab 与 Shift+Tab 切换分类,Esc 关闭。选中会话即打开该会话;选中项目在这个工作区开一个新会话;选中插件打开它在插件页的详情;选中 Skill 把 `/名称 ` 放到当前会话输入框的开头;选中快捷键打开宿主的快捷键列表,并筛到这一条。侧栏收起成窄条时没有搜索框。
12
+ - **进行中、已停止与失败的轮次改用 Claude Code 式的状态行**:原来宿主把「深度求索中,用时 N 秒」「已停止」「处理失败」排在这一轮的最前面,工作过程往下越排越长、状态却停在上方。现在这一行跟在这一轮工作的末尾(这一轮的页脚、排队中的消息仍在它下面),画成 Claude Code 的样子。进行中是一个转动的火花标记加「用时 · 输出 tokens · 当前动作」,例如「34秒 · 1.2k tokens · 思考中…」,当前动作依次有等待模型、思考中、思考了 N 秒、输出中、准备调用工具与运行工具中;停止或失败后火花静止,文字为「已停止 · 17秒 · 179 tokens」「处理失败 · 12秒 · 300 tokens」这样,历史里的这些轮次也一样。tokens 是这一轮已完成各步上报的输出用量,正在输出的那一步结束后计入。正常结束的一轮仍是宿主原来的「用时 N 秒」,在原来的位置,折叠与展开照旧。
13
+
14
+ ### 体验优化
15
+
16
+ - **像素螃蟹改用 Claude Code 的原版动画**:工作台首页输入卡片上的螃蟹原来是按 Claude Code 的样子手绘的十一个姿势;现在换成 Claude Code 自己的钓鱼动画,逐帧照搬(43 帧、每帧 80 毫秒,约 3.4 秒):眨眼、举竿甩过卡片边沿、跳一下侧过身钓鱼、收竿转回正面,像素边缘清晰。鱼竿仍用随主题变化的灰色,触发方式(点击、指针移开、闲置时隔二三十秒自己来一次,减少动态效果时只认点击)不变。
17
+ - **对话中输入框的发送键改成 Claude Code 的回车图标**:原来是等宽字体里的「↵」字符,有内容时变成陶土橙;现在是按 Claude Code 画的回车箭头(上沿一小段、沿右侧向下、再沿底边向左到箭头),线条清晰,输入框有内容时用正文墨色,空着时仍是浅灰。
18
+ - **桌面端侧栏的品牌行上移 10px**:桌面端的侧栏从 40px 高的标题栏下方开始,品牌标志因此比 Web 端低出一截;现在品牌行(连同其下的新会话、插件与会话列表)上移 10px,悬停时换上的搜索框仍整个露在标题栏下方,与标题栏里的收起按钮也不重叠。Web 端不变。
19
+ - **用量面板的倍数趣味行从二十九本书扩到六十五本**:书单补入《黄色壁纸》《变形记》《化身博士》《野性的呼唤》《时间机器》《绿野仙踪》《黑暗之心》《浮士德》《螺丝在拧紧》《伊索寓言》《彼得·潘》《君主论》《隐形人》《安徒生童话》《世界大战》《善恶的彼岸》《白牙》《沉思录》《格林童话》《格列佛游记》《瓦尔登湖》《鲁滨逊漂流记》《神曲》《包法利夫人》《查拉图斯特拉如是说》《奥德赛》《双城记》《远大前程》《理想国》《罪与罚》《利维坦》《安娜·卡列尼娜》《卡拉马佐夫兄弟》《堂吉诃德》《基督山伯爵》《悲惨世界》,长度都是全文以 o200k_base 分词器实测的值(英文原著或通行英译本,《浮士德》为德文原文)。书单仍从《道德经》排到《追忆似水年华》,用量越过的书更密,趣味行落到的那本书离实际用量更近。
20
+
21
+ ### 问题修复
22
+
23
+ - 修复 **开启「自动弹出弹层」后进入封号彩蛋页会立刻退出**:桌面端从账号菜单点开彩蛋页时,全窗浮层让指针「离开」菜单,悬停收起随后代宿主菜单按下的 Escape 被插件的键盘路由当成了用户按键,约 0.1 秒就把刚打开的彩蛋页关掉。现在这次代发的 Escape 只送达宿主菜单:彩蛋页开着时悬停收起同时停摆,页面保持打开,退出后侧栏与账号菜单恢复进入前的样子。
24
+ - 修复 **启用皮肤后带输入框的会话页上快捷键失灵**:皮肤常驻页面的模型选择器、推理强度与权限弹层卡片在关闭时仍标注 `role="menu"`,宿主据此把快捷键仲裁给一个看不见的「前景菜单」,连按 Esc 停止智能体、Ctrl+W 关闭页面与标签页菜单的 Esc 都不再生效(Web 端受影响的面更宽)。现在这一角色标注随卡片开合写入与撤销:卡片打开时才存在,快捷键的仲裁恢复如常。
25
+
26
+ <h3 id="en-0.9.0">New Features</h3>
27
+
28
+ - **A sidebar search box and search palette**: while the pointer is over the sidebar, the brand mark at its top left fades out into a search button (the host's search shortcut shown at its right end), and pressing it opens a search palette near the top of the window; the host's search shortcut (Ctrl+K on the desktop, Ctrl+Alt+K on the web, or whatever it has been rebound to in settings) opens the same palette, and the search icon the sidebar's Workspace heading used to carry is gone. The palette fades in and out together with the mask behind it. The palette searches past sessions, projects, plugins, the skills the current session offers and keyboard shortcuts. Sessions match by title, by workspace name and by what was said in them: every message between you and the model counts (tool-call arguments and subagent sessions do not), a few Chinese characters from the middle of a sentence match, case does not matter and neither do extra spaces; the matching line shows under the row with the match in bold. The plugin adds a read-only private route, `/dsh-claude-style/session-search`, for these queries, behind the host's request check like its other private routes; the first time the palette opens after the host process starts, the route reads every session once (about 16 s for 128 sessions here, while the palette shows "Searching…"), and each query after that takes about 0.1 s. The palette has All / Sessions / Projects / Plugins / Skills / Shortcuts across the top to narrow the list; with the box empty it lists the five most recent sessions and the New session, Plugins, Settings and Keyboard shortcuts actions. ↑↓ moves, Enter opens, Tab and Shift+Tab switch the category, Esc closes. Picking a session opens it; a project starts a new session in that workspace; a plugin opens its details on the plugins page; a skill puts `/name ` at the head of the current session's input; a shortcut opens the host's shortcut list filtered to that entry. The collapsed sidebar rail has no search box.
29
+ - **A Claude Code style status line for running, stopped and failed turns**: the host used to put "Deep diving for N s", "Stopped" and "Failed" at the very top of the turn, so the work grew downward while its status stayed above it. The line now follows the end of the turn's work (the turn's footer and queued messages still sit below it) and looks like Claude Code's. While the turn runs it is a turning spark, then elapsed time · output tokens · what the model is doing, for example "34s · 1.2k tokens · Thinking…", the action being one of waiting for the model, thinking, thought for N s, writing, preparing a tool call and running tools; once the turn is stopped or fails the spark stands still and the line reads like "Stopped · 17s · 179 tokens" or "Failed · 12s · 300 tokens", for such turns in the history too. The token count is the output usage the turn's finished steps report; the step still streaming joins it once it finishes. A turn that finishes normally keeps the host's own "Took N s" in its place, and folding works as before.
30
+
31
+ ### Improvements
32
+
33
+ - **The pixel crab plays Claude Code's own animation**: the crab on the Studio home page's composer card used to be eleven hand-drawn poses after Claude Code's; it now plays Claude Code's own fishing animation frame for frame (43 frames of 80 ms, about 3.4 s) — a blink, the rod raised and cast past the card's edge, a hop into a side-on stance to fish, the rod reeled in as it turns back — with crisp pixel edges. The rod keeps its theme-following grey, and what sets it off (a click, the pointer leaving it, on its own every half minute or so, only a click under reduced motion) is unchanged.
34
+ - **The in-conversation composer's send button uses Claude Code's return glyph**: it used to be the "↵" character from the monospace font, turning clay once there was text; it is now Claude Code's drawn return arrow (a short stub along the top, down the right side, back along the bottom to the arrowhead) in crisp strokes, in the body ink once the box holds text and still pale grey while it is empty.
35
+ - **The desktop sidebar's brand row sits 10px higher**: the desktop sidebar starts below the 40px titlebar, which left the brand mark lower than on the web; the brand row (and the New session, Plugins and session list below it) now rises 10px, with the search box that takes its place on hover still wholly below the titlebar and clear of the collapse button there. The web build is unchanged.
36
+ - **The usage panel's yardstick line grows from twenty-nine to sixty-five books**: the list adds The Yellow Wallpaper, Metamorphosis, The Strange Case of Dr Jekyll and Mr Hyde, The Call of the Wild, The Time Machine, The Wonderful Wizard of Oz, Heart of Darkness, Faust, The Turn of the Screw, Aesop's Fables, Peter Pan, The Prince, The Invisible Man, Andersen's Fairy Tales, The War of the Worlds, Beyond Good and Evil, White Fang, Meditations, Grimms' Fairy Tales, Gulliver's Travels, Walden, Robinson Crusoe, The Divine Comedy, Madame Bovary, Thus Spoke Zarathustra, The Odyssey, A Tale of Two Cities, Great Expectations, The Republic, Crime and Punishment, Leviathan, Anna Karenina, The Brothers Karamazov, Don Quixote, The Count of Monte Cristo and Les Misérables, each sized by feeding its full text to the o200k_base tokenizer (the English original or the standard English translation; Faust in the German original). The list still runs from Tao Te Ching to In Search of Lost Time; with the books set closer together, the one the line lands on sits nearer the real usage.
37
+
38
+ ### Bug Fixes
39
+
40
+ - **Fixed the account-hold easter egg closing itself right after it opened while "Open popovers on hover" is on**: on the desktop, opening the page from the account menu made the full-window overlay "leave" the menu, and the hover close that followed pressed Escape on the host's behalf — which the skin's keyboard routing took for the user's own key and dismissed the page about 0.1 s in. That dispatched Escape now reaches only the host's menu, the hover close stands down while the page is open, and the sidebar and its account menu come back as they were once the page is dismissed.
41
+ - **Fixed shortcuts going dead on conversation pages with an input box while the skin is enabled**: the model picker, reasoning-effort and permission popover cards the skin keeps in the page carried their `role="menu"` mark while closed, so the host arbitrated its shortcuts to an invisible "foreground menu" — pressing Esc twice to stop the agent, Ctrl+W to close a page and the Esc of the tab menu all stopped working (the Web build loses a wider set of them). The mark now rides the card's open state: it exists only while a card is open, and shortcut arbitration goes back to normal.
42
+
43
+ **Full Changelog**: [v0.8.0...v0.9.0](https://github.com/Nwflower/dsh-claude-style/compare/v0.8.0...v0.9.0)
44
+
45
+ ## [0.8.0] - 2026-09-26
46
+
47
+ [中文](#cn-0.8.0) | [English](#en-0.8.0)
48
+
49
+ <h3 id="cn-0.8.0">体验优化</h3>
50
+
51
+ - **对话 / 轨迹 / 上下文切换时高亮块平滑滑动**:切换视图时,高亮块此前在原标签上淡出、在新标签上淡入;现在同一块高亮从原标签滑到新标签,宽度随标签文字一起变化,标签文字颜色同步过渡。滑动不受系统「减少动态效果」设置影响,Windows 关掉了「在 Windows 中显示动画」时照样滑动。
52
+ - **权限分段、进行中 / 已归档与设置页分段控件的高亮块同样滑动**:只读 / 编辑 / 自动 / Yolo、侧栏的进行中 / 已归档,以及设置页里的各组分段控件,切换时高亮块都从原来那一段滑到新的一段,与对话视图标签同一套动画。
53
+ - **页面持续变化时插件的每帧开销大幅下降**:流式输出、打字机效果这类每帧都改动页面内容的场景,插件样式表此前让浏览器每帧的样式重算从 1.6ms 涨到 11–18ms,每帧主线程总耗时 14–23ms,超过一帧 16.7ms 的预算而掉帧;现在同一场景下样式重算为每帧 1.9–2.7ms,总耗时 5–7ms(本机无界面 Chrome 实测)。界面外观不变。
54
+ - **工作区选择菜单改为 Claude Code 的文件夹菜单样式**:菜单此前每行前面都有一个文件夹图标,行距与档位菜单的两行条目一样宽;现在是一张窄卡片,纯文字行排得更紧,文件夹图标与「添加工作区…」前的加号都不画,当前工作区仍以强调色勾号标出。档位菜单保持原样。
55
+ - **用量面板的倍数趣味行从十一本书扩到二十九本**:标尺书单补入《道德经》《爱丽丝漫游奇境》《圣诞颂歌》《弗兰肯斯坦》《道林·格雷的画像》《福尔摩斯冒险史》《哈克贝利·费恩历险记》《简·爱》《德古拉》,以及四大名著、《三体》三部曲、《活着》《平凡的世界》等中文书目,整份书单从《道德经》(约 7.6K tokens)排到《追忆似水年华》。书长改用真实口径:公有领域原书按全文以 o200k_base 分词器实测,仍在版权期的书目按出版字数以同一分词器实测的比例折算,几本英文经典的长度也按实测值更新。英文界面的这一行改为 “You've used ~N× the tokens in <书名>.”,此前的 “~N× more tokens than” 读起来是多出 N 倍,与实际倍数差了一倍。
56
+ - **账号弹层卡片改用象牙白底色**:浅色模式下,账号弹层与宿主账号菜单此前是纯白卡片,和界面其余部分的暖色调不一致;现在与主画布同为象牙白 `#FCFCFB`,靠细边框和阴影与侧栏区分。暗色模式不变。
57
+
58
+ ### 问题修复
59
+
60
+ - 修复 **侧栏「已归档」显示「没有已归档的会话」**:插件启动时宿主的归档数据往往还没到,列表就一直停在空白;现在列表跟随宿主的归档记录与会话列表实时更新,启动后、在别处归档或取消归档后都立刻反映。列表收录的会话与宿主自带「仅已归档」筛选一致(不含子代理会话与已不存在的会话),每行显示宿主给出的标题,不再出现成片的「未命名会话」;会话多时列表在侧栏内滚动,不再被截在窗口底部。
61
+ - 修复 **点击已归档行没有任何反应**:现在与宿主会话树里点已归档会话一样,窗口顶部弹出宿主自己的提示「已归档对话暂时无法查看,请取消归档后查看」。
62
+ - 修复 **英文界面下「排队发送」「插话发送」按钮的外观与中文界面不一致**:英文界面下,回复进行中且草稿非空时,这两个按钮此前不显示强调色,悬停时也没有底色;现在与中文界面一致。输入框里各按钮改为按它们在宿主界面中的位置识别,不再依赖按钮文字,宿主改动按钮文案或切换界面语言都不影响样式。
63
+
64
+ ### 其他变更
65
+
66
+ - **页面标出正在运行的构建**:`<body>` 上的 `data-dsh-claude-style` 属性现在写着已加载的包的构建编号(`npm run build` 会打印同一个编号),报告问题时即使页面经过多次热重载、从未刷新,也能说清运行的是哪一版。
67
+
68
+ <h3 id="en-0.8.0">Improvements</h3>
69
+
70
+ - **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.
71
+ - **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.
72
+ - **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.
73
+ - **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.
74
+ - **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.
75
+ - **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.
76
+
77
+ ### Bug Fixes
78
+
79
+ - 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.
80
+ - 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.
81
+ - 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.
82
+
83
+ ### Chores
84
+
85
+ - **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.
86
+
87
+ **Full Changelog**: [v0.7.2...v0.8.0](https://github.com/Nwflower/dsh-claude-style/compare/v0.7.2...v0.8.0)
88
+
5
89
  ## [0.7.2] - 2026-09-25
6
90
 
7
91
  [中文](#cn-0.7.2) | [English](#en-0.7.2)
package/README.en.md CHANGED
@@ -63,14 +63,14 @@ 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).
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.
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.
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
+ 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. On the desktop the brand row sits 10px higher than the host draws it, level with the web build. While the pointer is over the sidebar, the brand mark at its top left fades into a search box (the collapsed rail has none); pressing it, or the host's search shortcut (Ctrl+K on the desktop, Ctrl+Alt+K on the web), fades in a search palette near the top of the window, and the Workspace heading's own search icon is gone: it searches past sessions (by title, workspace name and what was said in them: every message between you and the model counts, a few Chinese characters from the middle of a sentence match, case does not matter, and the matching line shows under the row with the match in bold; the first time the palette opens after the host starts, every session is read once, which takes a dozen seconds or so), projects, plugins, the skills the current session offers and keyboard shortcuts, with All / Sessions / Projects / Plugins / Skills / Shortcuts across the top, and with the box empty it lists the five most recent sessions and the New session, Plugins, Settings and Keyboard shortcuts actions. ↑↓ moves, Enter opens, Tab and Shift+Tab switch the category, Esc closes; a session opens, a project starts a new session in that workspace, a plugin opens its details on the plugins page, a skill puts `/name ` at the head of the current session's input, and a shortcut opens the host's shortcut list filtered to that entry.
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. For running, stopped and failed turns the status line follows the end of the turn's work (the footer and queued messages sit below it) and looks like Claude Code's: while running, a turning spark, then elapsed time · output tokens · what the model is doing (waiting for the model, thinking, thought for N s, writing, preparing a tool call, running tools); once stopped or failed, a still spark and "Stopped / Failed · duration · output tokens". A turn that finishes normally keeps the host's own look and place.
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 sixty-five 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
+ 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, frame for frame from Claude Code's own animation: a blink, the rod raised and cast down past the card's edge, a hop into a side-on stance for a spell of fishing, and the rod reeled in as it turns back — about three and a half 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
76
76
 
package/README.md CHANGED
@@ -63,14 +63,14 @@ 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)。
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 权限分段照常显示,分段停在新会话的默认权限上,点它和点输入框一样打开工作区选择;表示「先选工作区」的虚线框只框住单行输入框本身。窗口高度放不下整块面板时,面板在问候语与输入框之间自己滚动、底边渐隐,页面不会被撑出窗口。
73
- 9. **像素螃蟹** —— 工作台版面的新会话页上,输入卡片上沿、靠右的位置站着 Claude Code 的像素螃蟹(经典版面没有)。点它一下、或指针从它身上移开时(页面开着时也会每隔二三十秒自己来一次),它会照 Claude Code 的样子钓一次鱼:半转身眨眼,举起鱼竿甩到卡片边上,侧身钓一会儿,再收竿转回正面,前后约三秒。系统要求减少动态效果时(例如 Windows 关掉了「在 Windows 中显示动画」),它只在被点击时才动。
68
+ 4. **工作区** —— 侧栏「工作区」标题改成 **进行中 / 已归档** 分段控件:进行中沿用宿主的会话树,已归档是皮肤自己的平铺列表(标题、时间、每行「取消归档」与「删除」两个图标按钮)。行排版与宿主的会话行逐项一致(行 x=12 / 宽 251 / 高 28 / 标题起点 x=36)。切换两种视图时,高亮块在两段之间平滑滑动。
69
+ 5. **侧栏** —— 新会话与插件两行取 Claude 真机形状:默认无底色、hover 才有底色,新会话的「+」套一枚圆形底,两行图标 hover 顺时针转 90°(四重对称图形,转回原位);底部账户抽屉、封号彩蛋一并保留。桌面端的品牌行比宿主原样上移 10px,不再比 Web 端低出一截。鼠标移到侧栏上时,左上角的品牌标志淡出、换成一个搜索框(侧栏收起成窄条时没有),点它或按宿主的搜索快捷键(桌面端 Ctrl+K,Web 端 Ctrl+Alt+K)在窗口上方淡入搜索面板,「工作区」标题行原来的搜索图标不再显示:搜历史会话(按标题、所属工作区名和对话内容:你和模型说过的每句话都算,句子中间的几个中文字也能搜到,不分大小写,行下显示命中的那一句并把命中的字加粗;宿主启动后第一次打开面板时要把全部会话读一遍,约十几秒)、项目、插件、当前会话可用的 Skill 与快捷键,顶部「全部 / 会话 / 项目 / 插件 / Skill / 快捷键」切换分类,搜索框为空时列出最近的五个会话与「新会话 / 插件 / 设置 / 键盘快捷键」几个操作。↑↓ 选择、Enter 打开、Tab 与 Shift+Tab 切换分类、Esc 关闭;选中会话即打开,选中项目在该工作区开新会话,选中插件打开它在插件页的详情,选中 Skill 把 `/名称 ` 放到当前会话输入框开头,选中快捷键打开宿主的快捷键列表并筛到这一条。
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 标题栏模式下居中常显在标题栏那一行(与新会话按钮同一行);宽窗口且标题较短时它停在标题那一行,否则留在标题下方自己那一行。切换视图时,高亮块从原标签平滑滑到新标签。进行中、已停止与失败的轮次,状态行跟在这一轮工作的末尾(页脚与排队中的消息在它下面),画成 Claude Code 的样子:进行中是转动的火花标记加「用时 · 输出 tokens · 当前动作」(等待模型、思考中、思考了 N 秒、输出中、准备调用工具、运行工具中),停止或失败后火花静止、文字为「已停止 / 处理失败 · 用时 · 输出 tokens」;正常结束的一轮保留宿主原来的样子与位置。
72
+ 8. **首页版面** —— 新会话页有两套版面,默认是工作台,在设置页随时切换:**经典**是居中大标题加输入卡片,标题按时段从一组问候里抽一句(早上、午间、下午、晚上、深夜各有几句,另有几句不分时段),每次回到新会话页换一句;**工作台**把标题移到左上并固定为一句「What's up next, 用户名?」,输入框改用对话内的单行样式贴住窗口底部、上方一行细边框上下文胶囊,标题与一块 480px 窄栏用量面板贴着输入框左缘排布:概览页签是六个数字格(会话数、消息数、Token 总量、活跃天数、高峰时段、最常用模型)与 26 周按天热力图(等分列方格),模型页签是每天一根按模型颜色堆叠的柱子加一份模型排行(色块、模型名、输入与输出、占比,超过六行折成「再显示 N 个」,展开后可「收起」),右上角的「全部 / 30 天 / 7 天」切换统计范围(高峰时段与趣味行一并跟随);所选范围内的用量超过一本书时,热力图下方出现倍数趣味行,书目共六十五本(《道德经》到《追忆似水年华》),每次回到新会话页随机换一本。数据由插件的宿主半边汇总:装了 `dsh-cost-meter` 时直接读它的账本缓存(只读,不写对方文件),没有时读本机会话日志自己算,并按日志的文件大小与修改时间增量缓存;两种来源都按模型给出四类 token、按天给出各模型的 token,同一模型经不同提供方的用量合成一行;账本不记小时,高峰时段始终由本机会话日志按天算出;汇总不可用时面板改用宿主会话列表每行自带的投影值。数字没到之前面板先画骨架,位置在填充前后不变。还没选工作区时(刚打开、尚无会话),用量面板与 Read / Edit / Auto / Yolo 权限分段照常显示,分段停在新会话的默认权限上,点它和点输入框一样打开工作区选择;表示「先选工作区」的虚线框只框住单行输入框本身。窗口高度放不下整块面板时,面板在问候语与输入框之间自己滚动、底边渐隐,页面不会被撑出窗口。工作区选择菜单照 Claude Code 的文件夹菜单绘制:窄卡片、纯文字行排得更紧,每行前面的文件夹图标与「添加工作区…」前的加号都不画,当前工作区仍以强调色勾号标出。
73
+ 9. **像素螃蟹** —— 工作台版面的新会话页上,输入卡片上沿、靠右的位置站着 Claude Code 的像素螃蟹(经典版面没有)。点它一下、或指针从它身上移开时(页面开着时也会每隔二三十秒自己来一次),它会照 Claude Code 的样子钓一次鱼:眨眨眼,举起鱼竿甩过卡片边沿,跳一下侧过身钓一会儿,再收竿转回正面,逐帧照搬 Claude Code 的动画,前后约三秒半。系统要求减少动态效果时(例如 Windows 关掉了「在 Windows 中显示动画」),它只在被点击时才动。
74
74
 
75
75
  ## 停用与卸载
76
76
 
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,83 @@ 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
 
203
+ ## Search · 搜索
204
+
205
+ **Sidebar box.** The box takes the brand's place in the logo row while the
206
+ pointer is over the sidebar: 32px tall, 8px radius, a 1px `#E8E6DC` hairline on
207
+ the ivory canvas fill (dark: `#2E2C29` on `#1E1E1D`), a 16px search glyph in the
208
+ secondary label, the "Search" label in the tertiary label at 14px, and the
209
+ host's search shortcut as 20px keycaps at the right end. It is a button like
210
+ the New session and Plugins rows below it: the pointer cursor, and on hover the
211
+ same plate those rows take (`--dsh-claude-hover-bg`, dark `rgba(255, 255, 255,
212
+ 0.08)`) laid over its opaque fill. Box and brand share one grid cell and
213
+ cross-fade over 0.16s, the timing the workspace heading and its segmented
214
+ control trade places with; the box is excluded from the window drag region. In
215
+ the desktop titlebar mode the brand row rises 10px, since the sidebar column
216
+ starts under the 40px titlebar — as far as it goes with the box still wholly
217
+ below that edge, which clips the column.
218
+
219
+ **Palette.** A modal card set 8vh from the top, 760px wide at most, 16px radius,
220
+ on the same ivory fill (dark `#1E1E1D`) under the host's mask. From the top: a
221
+ 17px borderless input with a 28px close button; the category chips (32px tall,
222
+ 8px radius, 14px, tertiary at rest and primary when current) sharing one
223
+ sliding highlight at `rgba(20, 20, 19, 0.06)`; the list, capped at
224
+ `min(520px, 62vh)`, with 13px tertiary section captions and 40px rows (8px
225
+ radius, 15px title, an 18px glyph in the secondary label, a 13px tertiary detail
226
+ after the title and an optional 13px tertiary excerpt line under it, the match
227
+ inside it in the primary label at weight 500 with no fill); a hairline-topped footer
228
+ of hints with 20px keycaps. The input text, the chips' text, the captions and
229
+ the row glyphs all start on one vertical line 24px in from the card edge. The
230
+ highlighted row takes `rgba(20, 20, 19, 0.05)` (dark `rgba(250, 249, 245, 0.07)`)
231
+ and shows the Enter glyph; the others hide it. The card fades in and settles
232
+ from 6px above at 98.5% scale over 0.18s; on close card and mask fade out
233
+ together over 0.14s before the modal unmounts.
234
+
235
+ ## Turn status · 轮次状态行
236
+
237
+ A running, stopped or failed turn's status line sits after the turn's work (its
238
+ footer and queued messages below it), 4px under the last row, with no rule under
239
+ it: a 14px Claude spark in the brand clay (`--dsw-alias-brand-primary`,
240
+ `#D97757`), 8px gap, then the text in the tertiary label at the host's secondary
241
+ content size (13px, 24px line), one line with an ellipsis. Parts are joined by
242
+ ` · `: `elapsed · N tokens · action` while the turn runs, `Stopped` or `Failed`
243
+ (the host's words) `· duration · N tokens` after; the token part is left out
244
+ until a finished step has reported usage. While the turn runs the spark turns a
245
+ full circle every 2.4s, breathing down to 78% at the half turn, in every motion
246
+ setting, like the sidebar's background-work ring; a stopped or failed turn's
247
+ spark stands still. A turn that finishes normally keeps the host's own control.
248
+
197
249
  ## Home layouts · 首页版面
198
250
 
199
251
  The new-conversation page has two arrangements. `homeLayout` (settings: Home
200
252
  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
253
+ `src/features/home/home-panel.css` branches on it. Both are the host's own
202
254
  hero markup — the greeting, the workspace row, the dock and the composer card
203
255
  inside `…_composerStack …_composerHero` — so only the arrangement differs.
204
256
 
@@ -212,7 +264,7 @@ inside `…_composerStack …_composerHero` — so only the arrangement differs.
212
264
 
213
265
  The studio composer is stamped `data-composer-variant="inline"` (composer.js's
214
266
  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
267
+ single-line stylesheet. The classic tray rules in `features/composer/card.css` are scoped
216
268
  away from studio with `:not([data-dsh-claude-home-layout="studio"])`. That is
217
269
  deliberate: they set `order: 1` / `order: 2` on the same boxes, and a competing
218
270
  rule would have to be out-specified rather than merely reordered — scoping them
@@ -250,8 +302,13 @@ bold figure — the figure stays barely above its own label, which is also what
250
302
  lets a long model id such as deepseek-v4.1-flash sit on one line; the favourite
251
303
  model is a name, not a figure, and keeps the regular weight. Messages are the
252
304
  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.
305
+ book, the yardstick line appears under the grid: sixty-five books from Tao Te
306
+ Ching (7.6k tokens) to In Search of Lost Time (1.6M), the public-domain ones
307
+ measured by feeding their full text to the o200k_base tokenizer (the English
308
+ original or the standard English translation; Faust in German) and the rest
309
+ estimated (1.3 tokens a word for English, 0.96 tokens a character for modern
310
+ Chinese prose). The line states the rounded multiple as a share of the book
311
+ ("~2× the tokens in Moby-Dick"), never as an excess over it.
255
312
  The book is drawn afresh each time the page comes back to the new-conversation
256
313
  hero, and a range that has not reached it steps down to the longest book it has
257
314
  passed, so the range pills keep the same book whenever the totals allow. The heat
@@ -305,132 +362,28 @@ placeholder, a zero day draws the grid's own base tone.
305
362
  ## The composer crab · 输入卡片上的螃蟹
306
363
 
307
364
  On the studio layout's new-conversation page, Claude Code's pixel crab stands on
308
- the composer card's top edge: 4px cells, a nine-cell shell with two-cell arms
309
- (52×32px), feet on the card's edge and the right arm 8px inside the single-line
365
+ the composer card's top edge. Its frames are Claude Code's own animation, cut to
366
+ 34×23 cells and drawn at 2px a cell, crisp (68×46px); the resting crab is 48×32px
367
+ with its feet on the card's edge and the right arm 8px inside the single-line
310
368
  card's right edge, so the feet stand where its 18px corner starts to round. The
311
- classic layout keeps its centred hero without the crab. The shell is the clay accent `#d97757` in both
312
- themes, the side-on back is `#b9603f`, the eyes `#141413`, and the rod takes the
313
- tertiary label ink. When the crab is clicked, when the pointer leaves it, and on its own every 25–45
314
- seconds while the page is in view, it plays Claude Code's fishing routine
315
- (about three seconds): a half turn and a wink, the rod raised overhead and cast
316
- down onto the card's edge, a hop, a spell of fishing side-on, and the rod put
317
- away as it turns back to face front. With reduced motion requested, only a click
318
- plays it: the pointer passing by and the idle timer leave it still. Only the crab
319
- takes the pointer; the room the rod swings through does not.
369
+ classic layout keeps its centred hero without the crab. The shell is the clay
370
+ accent `#d97757` in both themes, the side-on back is `#b9603f`, the eyes
371
+ `#141413`, and the rod takes the tertiary label ink. When the crab is clicked,
372
+ when the pointer leaves it, and on its own every 25–45 seconds while the page is
373
+ in view, it plays Claude Code's fishing routine, 43 frames of 80ms (3.44s): a
374
+ blink, the rod raised overhead and cast down past the card's edge, a hop into a
375
+ side-on stance, a spell of fishing, and the rod reeled in as it turns back to
376
+ face front. With reduced motion requested, only a click plays it: the pointer
377
+ passing by and the idle timer leave it still. Only the crab takes the pointer;
378
+ the room the rod swings through does not.
320
379
 
321
380
  ## Implementation notes
322
381
 
323
382
  - Every rule is scoped under `body[data-dsh-claude-style]`.
324
383
  - Dark tokens are the base; light overrides use `:not([data-ds-dark-theme])`.
384
+ - A surface's stylesheet sits beside its feature under `src/features/<feature>/`;
385
+ the look no single feature owns is in `src/theme/`, and the parts several
386
+ features share (the popover card and rows, the sliding highlight) are in
387
+ `src/shared/`. The source layout, the host selector discipline and the checks
388
+ the build runs are in `docs/architecture.md` (D1, D3, D9, D18, D19).
325
389
 
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.