dsh-claude-style 0.13.2 → 0.14.0-dev.12

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.
Files changed (93) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/LICENSE +0 -5
  3. package/README.en.md +1 -1
  4. package/README.md +2 -2
  5. package/THIRD_PARTY_NOTICES.md +282 -6
  6. package/docs/FEATURES.en.md +13 -14
  7. package/docs/FEATURES.md +13 -14
  8. package/docs/SETTINGS.en.md +21 -12
  9. package/docs/SETTINGS.md +21 -12
  10. package/docs/STYLE.md +151 -12
  11. package/lib/assets/1952ecd55916.js.br +0 -0
  12. package/lib/assets/3b91bf51db72.js.br +0 -0
  13. package/lib/assets/4ec527e58330.js.br +0 -0
  14. package/lib/assets/7323c8c86470.js.br +0 -0
  15. package/lib/assets/755d09170f37.js.br +0 -0
  16. package/lib/assets/c02a70a798bc.js.br +0 -0
  17. package/lib/assets/d8df7a57fbe3.js.br +0 -0
  18. package/lib/assets/manifest.json +28 -28
  19. package/lib/client.js +11 -8
  20. package/lib/host/brand.js +136 -0
  21. package/lib/host/http.js +74 -0
  22. package/lib/host/peakrate.js +7 -0
  23. package/lib/host/routes.js +26 -88
  24. package/lib/host/search.js +8 -1
  25. package/lib/host/settings.js +5 -0
  26. package/lib/model-descriptions.json +195 -43
  27. package/package.json +12 -4
  28. package/docs/decisions/D11-private-routes.md +0 -26
  29. package/docs/decisions/D12-fail-fast.md +0 -36
  30. package/docs/decisions/D14-account-surface.md +0 -26
  31. package/docs/decisions/D15-hdsl-contract.md +0 -24
  32. package/docs/decisions/D16-popover-baseline.md +0 -23
  33. package/docs/decisions/D17-permission-presets.md +0 -26
  34. package/docs/decisions/D19-host-contracts.md +0 -27
  35. package/docs/decisions/D20-sliding-pill.md +0 -26
  36. package/docs/decisions/D21-archived-list.md +0 -24
  37. package/docs/decisions/D22-search-panel.md +0 -30
  38. package/docs/decisions/D24-mascot.md +0 -32
  39. package/docs/decisions/D25-ban-screen-titlebar.md +0 -24
  40. package/docs/decisions/D26-motion-preference.md +0 -23
  41. package/docs/decisions/D27-context-stats.md +0 -35
  42. package/docs/decisions/D28-desktop-band.md +0 -23
  43. package/docs/decisions/D29-feature-switches.md +0 -24
  44. package/docs/decisions/D3-host-selectors.md +0 -28
  45. package/docs/decisions/D30-palette-and-typeface.md +0 -25
  46. package/docs/decisions/D31-windows-titlebar.md +0 -24
  47. package/docs/decisions/D32-chat-interactions.md +0 -33
  48. package/docs/decisions/D33-stylesheet-ownership.md +0 -26
  49. package/docs/decisions/D34-turn-navigator.md +0 -29
  50. package/docs/decisions/D35-selection-scope.md +0 -23
  51. package/docs/decisions/D36-modules-and-bundling.md +0 -35
  52. package/docs/decisions/D38-assets.md +0 -28
  53. package/docs/decisions/D39-on-demand-loading.md +0 -33
  54. package/docs/decisions/D4-composer-gate.md +0 -22
  55. package/docs/decisions/D40-observation-bus.md +0 -36
  56. package/docs/decisions/D41-scroll-owner.md +0 -40
  57. package/docs/decisions/D42-feature-manifest.md +0 -28
  58. package/docs/decisions/D43-overlay-and-upstream.md +0 -27
  59. package/docs/decisions/D44-contract-module.md +0 -36
  60. package/docs/decisions/D45-testing.md +0 -30
  61. package/docs/decisions/D46-monorepo.md +0 -31
  62. package/docs/decisions/D47-build-output.md +0 -30
  63. package/docs/decisions/D48-documentation.md +0 -28
  64. package/docs/decisions/D49-visual-yield.md +0 -30
  65. package/docs/decisions/D5-model-copy.md +0 -29
  66. package/docs/decisions/D50-brand.md +0 -24
  67. package/docs/decisions/D51-css-toolchain.md +0 -34
  68. package/docs/decisions/D52-header-band.md +0 -31
  69. package/docs/decisions/D53-usage-merge.md +0 -33
  70. package/docs/decisions/D54-peakrate-meter.md +0 -33
  71. package/docs/decisions/D58-redraw-retired.md +0 -29
  72. package/docs/decisions/D60-settings-transport.md +0 -31
  73. package/docs/decisions/D61-wallpaper-under-one-mask.md +0 -28
  74. package/docs/decisions/D62-file-row-merge.md +0 -28
  75. package/docs/decisions/D63-turn-status-retired.md +0 -29
  76. package/docs/decisions/D7-one-package.md +0 -23
  77. package/docs/decisions/D9-style-performance.md +0 -25
  78. package/docs/decisions/README.md +0 -86
  79. package/lib/assets/2c01384360ac.js.map.br +0 -0
  80. package/lib/assets/31253ed42440.js.br +0 -0
  81. package/lib/assets/5063c46824b6.js.br +0 -0
  82. package/lib/assets/55a6154f87b5.js.map.br +0 -0
  83. package/lib/assets/5e05b29d5005.js.br +0 -0
  84. package/lib/assets/668d06ca781b.js.map.br +0 -0
  85. package/lib/assets/930546669455.js.map.br +0 -0
  86. package/lib/assets/968fcbfc3e22.js.br +0 -0
  87. package/lib/assets/abf0547f08a4.js.br +0 -0
  88. package/lib/assets/ac9b0e625837.js.map.br +0 -0
  89. package/lib/assets/ad2905345a69.js.br +0 -0
  90. package/lib/assets/ba68f60ecc71.js.map.br +0 -0
  91. package/lib/assets/c52e41b4842b.js.map.br +0 -0
  92. package/lib/assets/e1291f79b7c9.js.br +0 -0
  93. package/lib/client.js.map +0 -7
@@ -1,33 +0,0 @@
1
- # D54. 峰谷电表:作息表是数据源的快照,判定在浏览器按真实时刻做
2
-
3
- - **状态**:已实施
4
- - **分组**:功能
5
- - **关联**:D11、D12、D29、D42、D51
6
-
7
- ## 决定
8
-
9
- - 峰谷时间没有接口可用:供应商只发布作息表,没有任何一处按「此刻是不是峰时」作答。宿主半边取公开目录 `https://offpeakclock.com/pricing.json`(`schemaVersion` 为 1),校验成 `RateProfile` 后经 `/dsh-claude-style/peakrate` 下发;浏览器半边不直接访问第三方,也不知道数据源的地址。
10
- - 读取顺序是磁盘缓存优先、包内快照兜底:缓存写在 `$DSH_HOME/cache/dsh-claude-style/peakrate.json`,不比包内快照旧时采用;快照来自 `packages/host/data/peakrate-catalog.json`,构建时复制成 `lib/peakrate-catalog.json`。新旧按文档自身的 `updatedAt` 比较,两边都没有时按文件修改时间,因此插件升级带来的新快照会盖过旧缓存。
11
- - 调度:路由第一次被请求时载入目录并启动 24 小时定时器(`unref()`,不阻止进程退出),每次成功拉取后写回磁盘缓存。`GET` 答当前持有的目录,`POST` 先拉一次再答,浏览器半边读到的副本超过 24 小时时用它。定时器只在浏览器半边问过之后才存在,功能关掉后页面不再问,宿主也不再拉取:定时器每次醒来先看距上一次请求是否已超过 48 小时,超过就自己停下,直到下一次请求再启动。
12
- - 判定全部在浏览器半边,只按真实时刻:墙钟在 profile 自己的 IANA 时区里读,墙钟时间先换算成真实时刻再与此刻比较,日内加法在时区自己的日历上做,所以夏令时切换与跨零点窗口都按真实时间算;落进夏令时空档的墙钟时间没有自己的时刻,窗边就落在跳变那一刻,切换时刻因此不会被推后一天。优先级是限时活动、法定节假日整日谷价、星期过滤与峰时窗口;跨零点的窗口归它开始的那一天,开始那天是节假日还会压掉它的次日凌晨。
13
- - 整日作息的供应商把作息写成 `00:00–00:00` 加 `allDay`,这样的窗口按覆盖全天读取:标准费率整天在走的供应商照样有徽章,而不是整条 profile 被判为无效。
14
- - 限时活动按文档声明的边界判定:`startDate` / `endDate` 是整天,`startAt` / `endAt` 是带时区的时刻(开始时刻算在覆盖内,结束时刻就是切换那一刻);已经结束的活动不会再生效,因为把它只按日期或只按窗口读会让它从此一直在效。活动自己的窗口与星期表照旧参与判定。
15
- - 只有匹配到 profile 的行画徽章,匹配不到的模型什么都不显示。倍数取自数据源自己的徽章文本,按外来字符串用 `textContent` 上屏(D11);倒计时由浏览器按下一个切换时刻算出,切换候选除午夜与作息窗口的边界外,还包括活动声明的那两个时刻。
16
- - 构建核对包内快照与匹配表(`packages/client/src/features/peakrate/match.ts` 的 `MODEL_MAPPINGS`):每一行点到的 profile 必须在解析结果里存在,且那条 profile 的供应方与这一行声明的一致;对不上即构建失败(`scripts/peakrate-catalog.mjs`)。映射表与快照各写一份,少了这一步就只有页面上不显示徽章这一种表现。
17
- - 宿主半边允许的 catch 增加两处,理由写在处所:数据源不可达或答的不是本版本能读的文档时记警告并沿用当前目录;磁盘缓存读不了或写不进时记警告,本轮结果照常(D12)。
18
- - 校验时区用构造 `Intl.DateTimeFormat` 探一次:平台认不认这个时区,没有别的判断方式。profile 自己的时区探不通就丢掉整条 profile,节假日所属时区探不通就只丢掉这个字段、改用 profile 自己的时区读节假日。这是 D12 之外新增的第三处 catch,只在这里,浏览器半边因此不必再为时区兜底。
19
-
20
- ## 理由
21
-
22
- - 「此刻是不是峰时」只有浏览器知道,作息表却是全量数据:宿主取一次、留一份在磁盘,胜过每个页面各取一次。
23
- - 数据源是社区维护的快照而不是接口,供应商调价不会通知:判定规则必须留在本地代码里,取回来的只是作息。
24
-
25
- ## 代价
26
-
27
- - 首次运行要能连上数据源,连不上就按包内快照判定,直到插件升级带来更新的快照。
28
- - 数据源里的错误按没有这条 profile 或这条活动丢弃:零长度又没有 `allDay` 标记的作息窗口、读不成时刻的边界、认不出的时区。丢弃只在覆盖审计与构建核对里看得出来,界面上表现为不显示徽章或退回常规费率。
29
- - 整日作息的供应商,峰价与谷价两个徽章文本相同,界面上按峰价那一档显示;倍数是数据源自己的,状态名是皮肤自己的叫法。
30
-
31
- ## 重审条件
32
-
33
- - 供应商提供机器可读的时段接口时改接它;宿主的模型目录直接给出峰谷标记时改用宿主的。
@@ -1,29 +0,0 @@
1
- # D58. 移除「重绘」档,过程组标题的计数摘要与等待行搬进「增强」档
2
-
3
- - **状态**:已实施
4
- - **分组**:功能
5
- - **关联**:取代 D55、D56、D57;D12、D26、D29、D32、D34、D36、D41、D42、D44、D45、D51
6
-
7
- ## 决定
8
-
9
- - 「聊天区动画效果」回到一个开关(`chatAnimations` 布尔值,开即播放本插件这一套,关即交还宿主):`CHAT_ANIMATIONS_MODES` 与「增强」「重绘」两个取值一并删去,`chat-reader` 功能整体删除,早先版本存下的字符串取值由 `normalizeChatAnimations` 折算成真假(`off` 为假,其余为真),不需要迁移代码。随之删去的是:`features/chat-reader/` 的全部文件、工作步骤展示的绑定(`core/step-display`)与它的单元测试、`entry.ts` 对它的装卸、调度器里的 `chatReader` 句柄、契约表里只为它而设的条目(`chat.motion`、`fold.searchable-hidden`、`turn.nav-seat`、`conversation.embedded`、`header.view-tablist` 等)、端到端场景 `reader` 与 `readerOpen` 与 `readerTurnNav` 与 `stepDisplay`、冒烟用例 `chat-reader`、TSX 工具链(`tsconfig.json` 的 `jsx`、构建与 lint 把 `.tsx` 当源文件、替身加载器里的 JSX 运行时)、只为它装上的宿主内部开发依赖,以及 `THIRD_PARTY_NOTICES.md` 里 `dsh-util-values` 一节(dsh-better-display 一节留下,搬来的两处视觉仍出自它)。
10
- - 过程组标题的读数搬进「增强」档(`packages/client/src/features/chat-fold/process-summary.ts`,随 `chatAnimations`):宿主保留它的标题、图标与开合控件,摘要是皮肤自己的一个 span 接在控件末尾,宿主那句活动清单在它站住时由样式表隐藏,控件的可访问名字改由 `aria-label` 给出。四项数字按过程组内部的行种类在每次变动后一帧重算:带 `data-chat-group-part="reasoning"` 的步算思考、其余助手步算输出、工具调用算工具、别的记录算记录。标题写整句「执行 2 次思考,调用 1 次工具」,没有的项不写;放不下整句时(窗口或这一行的位置不够宽)改用简洁写法「思考×2 · 工具×1」,位置宽回来再换回整句,名字始终是整句。放不下与否按标题所在容器给它的宽度判断,不用它当前的宽度——宿主自己的控件是按内容排的,用当前宽度会自证。
11
- - 说明模型正在做什么的那一行搬进「增强」档(新功能 `chat-wait`,`packages/client/src/features/chat-wait/`,同样随 `chatAnimations`,对 dsh-chat-ux 让位):宿主保留它的行、小鲸鱼与实时播报区,这一行是皮肤自己的 span 接在它的文字之后。文字取自宿主的聊天快照:「正在思考」「正在准备工具调用」「正在调用工具」「正在写回答」,这几句放在一处(`packages/client/src/shared/turn-activity.ts`,D63 起只由这一行读);读不出状态时(模型还没写出任何内容、也没有工具在跑)回到宿主自己的「深度求索中」。旁边是这一轮已用的时间(宿主的 `duration.*Unit` 词,与它自己的钟同一套写法),模型连续 10 秒没有开口时再挂出「暂未响应」。说法换掉时走 transitions.dev 的「Text states swap」三段(旧句向上模糊淡出、淡出后换字、新句从下方升起),三段的时长与幅度是那份片段的取值,写成皮肤自己的自定义属性;「动画」为「减弱」时直接换字,不做三段(D26)。
12
- - 三档共用的改动保留,它们不属于重绘档:滚动主人为「读者自己刚发出的消息」保留的让位窗口按会话作废(会话一换当场作废)、`data-chat-running` 那一行的固定在跟随自己移动位置时成立(`READER_HOLD_ATTR` 标记;D63 起这段样式在 `packages/client/src/features/chat-wait/chat-wait.css`)、时长格式移到 `packages/client/src/shared/format.ts` 供读时长的功能共用、搜索面板点开内容命中落到那一轮(改按宿主的刻度跳)。
13
-
14
- ## 理由
15
-
16
- - 重绘档是 dsh-better-display 阅读视图的整份移植,页面上已经有那份实现时本插件还要让位:读者从对方那里就能得到同一幅画面,本仓库则长期付着一份数千行渲染器的维护成本。
17
- - 搬进「增强」档的这两件事都不需要会话投影:过程组标题的读数读宿主已经画好的行,这一行读宿主的聊天快照,两处都在宿主自己的 DOM 与数据上做。
18
- - 对话区回到一套动效之后,让位与共存的判定少一层:设置页少一个档位,聊天区各功能不必再为两套渲染各写一遍标记(D32)。
19
-
20
- ## 代价
21
-
22
- - 计数与读数按宿主过程组内部的行种类与属性来数,宿主编排过程组的方式变了要跟着改;这些选择器与属性因此进了契约表,由契约场景与端到端场景在真实宿主上核对。
23
- - 这一行的起点有两处:模型还没写过任何块时取这一轮的开始时刻,此后的等待从页面第一次看见它沉默的那一刻起算——宿主的快照不给工具结束时刻,所以工具跑完之后的等待会比实际略短。
24
- - 阅读视图里那些本仓库独有的做法(按宿主「工作步骤展示」分档收拢、折叠内容留给浏览器查找、逐词淡入、推理卡片、子会话的第二份座位)随功能一起消失,读者要用这些得装 dsh-better-display。
25
-
26
- ## 重审条件
27
-
28
- - 宿主把过程组的计数、时长或「正在做什么」直接放进公开数据时,这两处改为读宿主的值而不是自己数。
29
- - 读者要求本插件自己提供阅读视图时,按 D43 认可的 `conversation.view` 入口重新登记一份,并把这次搬进「增强」档的两件事留在原处。
@@ -1,31 +0,0 @@
1
- # D60. 设置读写走官方 Config 表单,非 loopback 页面只读设置文档
2
-
3
- - **状态**:已实施
4
- - **分组**:宿主边界
5
- - **关联**:取代 D10;D11、D12、D29、D46
6
-
7
- ## 决定
8
-
9
- - 浏览器半边写设置只有 `configForms` 一条传输:绑定宿主实际提供的命名空间(候选依次为加载器入口 id、包名、`cordis.patch.yml` 插入的 id,以宿主的命名空间目录为准),读写都经表单控制器(值、写队列、修订号栅栏)。命名空间晚到时订阅目录,到达即绑定。
10
- - 宿主对非 loopback 页面(局域网地址、隧道域名,由浏览器侧的 `location.hostname` 判定)只给内存态的表单:命名空间目录恒为 `unavailable`,从不读取设置文档,写入一律不落盘。皮肤以目录的 `unavailable` 认出这种页面,改用表单服务自己所依赖的读取 `remote.settings.describe()` 取自己命名空间的合并值,在 `settings/document-updated` 事件与 `connection/reset` 之后重读;宿主拒绝这次读取时抛出。
11
- - 这种页面上皮肤的设置页只读:开头一行说明改动要在运行 DSH 的电脑上做,所有行放进一个禁用的 `fieldset`,标签页仍可切换浏览。皮肤不经 `remote.settings.mutate` 绕过宿主替远程页面保存设置的限制。
12
- - 宿主半边导出 `Config` 作为 schema,只有 `.volatile()` 字段进表单。schemastery 以顶层 await 加守卫导入,解析不到时 `Config` 为 `undefined`、皮肤照常加载——这是「导入不包 try/catch」规定的唯一例外。
13
- - 设置席位注册为 `plugins.bundle.config`(键为包名);宿主没有 `configForms` 时才注册整页的 `settings.section`。
14
- - 偏好字段只有一份声明:`packages/contracts/src/prefs.ts` 的 `PREFS_DEFAULT`。宿主半边 `packages/host/src/settings.ts` 用它生成 `Config`(宿主构建把 contracts 的值内联进产物,contracts 不进 npm 包);浏览器半边的默认值与取值集合给出表单答复之前的初值与读到值时的规整。
15
- - 字段类型按默认值的类型取纯 `string` / `boolean` / 字符串数组:取值集合在消费处判定,浏览器半边读到什么都做规整。存下的值可能还是早先类型的偏好,字段同时接受 `boolean` 与 `string`:`autoPopover` 早先是开关、后来长成多档,`chatAnimations` 早先是多档、后来又回到开关。宿主在启动插件之前用 `Config` 校验配置行,类型不符即校验失败,整个包都不启动——私有路由、设置表单与浏览器半边一起缺席;浏览器半边把两种类型都读成对应的取值。偏好的默认值换类型时,这个键同一次改动里加进这份名单,冒烟的宿主半边用早先类型的值校验一遍 `Config`。
16
- - 偏好只存在宿主的设置文档里:早先存进浏览器本地存储的昵称与封号页语言,在表单第一次带值时写进表单,表单持有自己的值后删掉本地那份;只读页面不做这一步。
17
-
18
- ## 理由
19
-
20
- - 官方表单自带写队列与修订号,皮肤不重复实现一套同步。
21
- - 皮肤的外观由偏好决定:远程页面拿不到设置文档时整套外观回到出厂默认,与宿主上的设定不符;读取本身宿主照常应答,只读不越过宿主不替远程页面保存设置的边界。
22
-
23
- ## 代价
24
-
25
- - `Config` 的顶层 await 让宿主半边晚一步求值(加载器本就等待导入,无实际影响)。
26
- - 远程页面上的设置只能看不能改。
27
-
28
- ## 重审条件
29
-
30
- - 宿主提供不依赖 `Config` 的设置注册方式,或 `configForms` 契约再变。
31
- - 宿主的表单服务对已认证的远程页面也读写设置文档:那时目录不再是 `unavailable`,皮肤回到表单这一条路,这条决策的只读部分随之删去。
@@ -1,28 +0,0 @@
1
- # D61. 壁纸插件在播壁纸时,Claude 配色在整个窗口铺一层底色遮罩
2
-
3
- - **状态**:已实施
4
- - **分组**:宿主边界
5
- - **关联**:取代 D59;D3、D30、D31、D49、D51
6
-
7
- ## 决定
8
-
9
- - 壁纸插件(`dsh-plugin-wallpaper-engine`)在 `body` 上挂 `data-we-wallpaper`,壁纸本体与它的暗化层、特效层是 `body` 的子节点,分别在 `z-index: -2` 与 `-1`;这个标记在即「有壁纸正在显示」。本插件只读这一个属性,它是别的插件的标记,不进 D3 的宿主契约表,读法写在用它的那几张表里。
10
- - 标记在且配色为 Claude 时,`theme/wallpaper.css`(样式表顺序最后)做四件事:外壳让开——`body`、窗口框架、中栏、右栏、会话根节点(含会话滚动区的 `[data-phase]`)与侧栏不画底色,侧栏元素自己的 `--dsw-specific-sidebar-fill` 清成透明;一层遮罩——`body::after` 固定铺满窗口、`z-index: -1`,按文档顺序落在壁纸插件的各层之上、外壳之下,颜色是画布色,浅色 86% 不透明、深色 82%;输入区——座位本身、座位上方与会话顶部的两道渐隐不画,座位里垫一块与输入卡同宽的画布色托盘(卡片顶边以下到窗口底边),统计行与模型行落在它上面,滚过去的会话正文不会从卡片下方透出来;`tokens.css`、`typography.css`、`chrome.css` 里把画布刷到外壳上的规则挂 `:not([data-we-wallpaper])`,原有的配色门不动(D30)。
11
- - `--dsw-alias-bg-base` 在 Claude 一档保持画布色,壁纸插件自己的清空被本插件的令牌块盖过:宿主用这个令牌画的面(设置窗口、各类浮层与卡片、引导层)照旧不透明。皮肤自己的面(弹层、账号弹层、搜索面板)同样不透明。
12
- - 配色选「跟随宿主」时不铺遮罩,外壳与各面交给宿主与壁纸插件(D30)。
13
-
14
- ## 理由
15
-
16
- - 一层均匀的遮罩让侧栏、标题区、会话与底部读数落在同一块底子上,对比度处处一致,壁纸作为整窗的淡色背景透出。
17
- - 让位按元素列出,基础令牌留在画布色:宿主以后新增的面默认可读,需要透出壁纸的只有已知的那几块外壳。
18
- - 输入区的托盘与卡片同色同宽,挡住滚到下面的正文,又不在整栏宽度上多出一条更亮的带子。
19
-
20
- ## 代价
21
-
22
- - 壁纸只以约 14%(深色约 18%)的强度透出,遮罩比例写死,不随壁纸插件的暗化或玻璃滑条变化。
23
- - 外壳让位按宿主的类名子串与属性列出;宿主给外壳换了元素或令牌,这几条要跟着改,失配由冒烟的 `host-palette` 用例发现。这个外来属性不在构建的属性检查之内(D51 只管 `data-dsh-*`)。
24
-
25
- ## 重审条件
26
-
27
- - 宿主提供主题层级或令牌分层机制时,外壳的让位改由层来声明(与 D30 同一条件)。
28
- - 壁纸插件提供公开的遮罩或可读性契约(例如由它画遮罩、本插件只给颜色)时,改用那份契约。
@@ -1,28 +0,0 @@
1
- # D62. 同一文件的多次改动读成一行
2
-
3
- - **状态**:已实施
4
- - **分组**:功能
5
- - **关联**:D9、D26、D32、D45
6
-
7
- ## 决定
8
-
9
- - 同一个过程组内容层里,同一个文件的多次编辑与写入读成一行:这一行是这一组里文档顺序最早的那一次改动,行尾的 `+n -m` 是这些改动的累计值,展开读到的是全部改动的改动卡片;只改动过一次的文件按原来的样子画一行。
10
- - 每个文件改动行把自己的路径、改动内容与状态登记进这次安装自己的一张登记表(`packages/client/src/features/chat-files/file-row-merge.ts`),代表行从表里读回整组的内容。代表权按文档顺序决定,新改动到达时代表行留在原处,只有数字与卡片增长。
11
- - 被代表的行整行离开页面:标记按 D9 写在宿主这一次调用的行上(直接调用的工具是内容层的子元素,程序派发的调用是它自己那一行),宿主行的间距随之消失,样式用 `display: none`。失败与中断的行不登记,保留自己的裁决信息。
12
- - 行尾数字按过程组标题计数数字的时长与曲线滚动(160ms,`cubic-bezier(.16, 1, .3, 1)`):每个字符各占一个自己的盒子,只有自己的数字变了的字符才向上翻,其余字符原地不动,数字长大读起来像里程表。盒子用 `clip-path: inset(0)` 裁掉溢出的部分,因为 `overflow` 会把行内块的下边缘当作基线,而盒子只有一字高,字形会被抬离同一行的文字基线。动画档为「减弱」时直接写入新数字(D26)。这是仓库里第二处滚动数字,第三处出现时按 AGENTS.md 的停止线移进 `packages/client/src/shared/`。
13
- - 合并后的行多一句视觉隐藏的说明,读屏念到的是这一行代表的全部改动。
14
- - 合并挂在文件变更行已有的开关上(`chatAnimations`,D29/D32):开关关掉时这些行一起交还宿主,不新增偏好。
15
-
16
- ## 理由
17
-
18
- - 宿主每次调用画一行,同一个文件改几次就出现几行,读者要在整段过程里找出这个文件的每一次改动;读成一行之后,读者看到的是这个文件一共被改了多少。
19
- - 行尾数字与改动卡片读同一组改动内容,数字与卡片不可能对不上;代表行取最早的一行,数字增长时这一行不移动位置。
20
-
21
- ## 代价
22
-
23
- - 被代表的行上各自的「轨迹入口」按钮不再可点,它们的改动内容通过代表行展开后的卡片读到。
24
- - 代表权依赖行的文档顺序与挂载状态:长会话把离屏的行卸载时,代表权落到剩下的最早一行。
25
-
26
- ## 重审条件
27
-
28
- - 宿主自己把同一个文件的多次改动画成一行时,改为读宿主的。
@@ -1,29 +0,0 @@
1
- # D63. 删除轮次状态行,运行中的说法归等待行一处
2
-
3
- - **状态**:已实施
4
- - **分组**:功能
5
- - **关联**:取代 D23;D32、D41、D50、D58
6
-
7
- ## 决定
8
-
9
- - 「轮次状态行」功能整体删除:`packages/client/src/features/turn-status/` 的三个文件、调度器里的 `turnStatus` 句柄、`turnStatus` 偏好与它在设置页「对话」页的那一行、契约表里只为它而设的 `turn.process` 条目、`core/host.ts` 的 `findTurnProcess` 与 `dom.ts` 的 `TURN_PROCESS_SELECTOR` 一并删去。
10
- - 宿主自己的过程控件只在轮次结束(`turn.status === 'closed'`)之后渲染:进行中的轮次里那一行是空的,状态行当年按「进行中也是这个控件」写下的整套渲染(`live` 取值、当前动作的判定、「思考了 N 秒」的测量、转动的火花与它的两个关键帧)在真实宿主上不会执行,随功能一起删去。
11
- - 已停止与失败的轮次不再改写:宿主自己的控件留在它自己的位置与写法上(「已停止」「处理失败」与折叠行为照旧),`--dsh-claude-turn-order` 的排列与 `data-dsh-claude-turn-status` 画的文字一并消失。
12
- - 运行行的固定搬进等待行(`packages/client/src/features/chat-wait/chat-wait.css`):只要对话还在跟随末尾,宿主那一行就停在输入框上方;读者自己接管滚动(`READER_HOLD_ATTR`)或跟随的滑行持有位置(`FOLLOW_HOLD_ATTR`)期间照旧让开。它随「聊天区动画效果」这一个开关,也对 dsh-chat-ux 让位。
13
- - 文案随之归位:四个说法(正在思考、正在写回答、正在准备工具调用、正在调用工具)改名为 `chatWait*`,留在 `packages/client/src/shared/turn-activity.ts`,只由等待行读;等待模型、思考了 N 秒、tokens 与设置行的标题和说明五条删去。
14
-
15
- ## 理由
16
-
17
- - 宿主把运行中的状态做成自己的一行(`data-chat-running`:小鲸鱼、说法、计时与实时播报区),过程控件改为只在轮次结束后出现;同一件事由两处说,而插件那一处只剩停止与失败两种情形,画法又与运行行不同(皮肤自己的品牌图形、13px 三级色文字、末尾的 tokens)。
18
- - 保留下来的是一份不可达的状态机、一个只服务一条停止状态条的偏好与一个设置行;运行行上真正在做的两件事(写说法、固定在输入框上方)都归等待行一处之后,读代码的人不必再分辨哪一半还在生效。
19
-
20
- ## 代价
21
-
22
- - 已停止与失败轮次的用时与输出 tokens 不再显示,历史里的这些轮次只剩宿主自己的「已停止」「处理失败」。
23
- - 运行行的固定与等待行同一个开关:关闭「聊天区动画效果」,或页面上装有 dsh-chat-ux 时,宿主那一行按宿主自己的方式随内容滚动。
24
- - 早先存下 `turnStatus` 的读者,那一项在设置页不再出现,存下的取值也不再被任何代码读取。
25
-
26
- ## 重审条件
27
-
28
- - 宿主给停止与失败的轮次提供公开的状态行,或把用时与输出 tokens 放进公开数据时,另行登记一条读取它的功能,而不是恢复这份自己判定的渲染。
29
- - 读者要求把停止与失败的轮次排到这一轮工作的末尾时,按 D43 认可的扩展点重新做一次。
@@ -1,23 +0,0 @@
1
- # D7. 行为层与皮肤对外是一个插件
2
-
3
- - **状态**:已实施
4
- - **分组**:分发与流程
5
- - **关联**:D29、D30、D46
6
-
7
- ## 决定
8
-
9
- - 模型选择器、权限分段、账号弹层等行为层与皮肤层共享宿主定位点、刷新机制与弹层部件,对外发布为同一个插件;仓库内部怎样分包(D46)不影响这一条。
10
- - 「只要行为、不要外观」的入口是设置页的「配色」与「字体」:两项都选「跟随宿主」后,皮肤不再改写宿主的颜色与字体,只留布局与控件(D30)。
11
- - 每个接管宿主界面的功能另有自己的开关(D29)。
12
-
13
- ## 理由
14
-
15
- - 行为层与皮肤依赖同一套宿主定位与部件,拆成两个插件只会多出一层跨插件协调。
16
-
17
- ## 代价
18
-
19
- - 行为层随皮肤的布局一起安装,不能脱离这个插件单独使用。
20
-
21
- ## 重审条件
22
-
23
- - 出现第二个真实使用者(另一个主题插件或宿主官方)需要复用行为层时,把它拆成独立插件。
@@ -1,25 +0,0 @@
1
- # D9. 样式性能:结构判断写成属性,`:has()` 只放在最后一段
2
-
3
- - **状态**:已实施
4
- - **分组**:构建与源码
5
- - **关联**:D40、D51
6
-
7
- ## 决定
8
-
9
- - 依赖 DOM 结构的判断由脚本算好、写成属性,样式只读属性:输入框形态 `data-composer-variant`、附件 `data-dsh-claude-attachment`、草稿为空 `data-dsh-claude-draft-empty`、控件 `data-dsh-claude-control`(D19)、视图标签条 `data-dsh-view-tabs`。
10
- - `:has()` 只出现在选择器的最后一段(`A:has(B)`、`A :has(B)`),后面不接后代或兄弟选择器(`A:has(B) C`、`body:not(:has(B)) C` 都不允许);构建在语法树上逐层检查,拒绝违规写法(D51)。
11
- - 每帧都要问的页面问题读一次就留下来复用:会话的滚动容器与消息列(`packages/client/src/shared/chat-dom.ts`)在元素仍留在文档里时不再重新查找,元素被移除(换会话、切「轨迹」页签)后才重新读取;流式标记在消息列内查找,宿主「回到底部」按钮的存在本身就是「跟随已关闭」的判据;同一帧里读到的高度只读一次,交给同帧的其余判断与滑行终点共用(`scroll-owner.ts` 的 `takeBackHostPin`、`scroll-ease.ts` 的终点)。
12
-
13
- ## 理由
14
-
15
- - 在无界面 Chrome 里打开会话、每帧追加一个字(等同流式输出)实测:违规写法单条让每帧样式重算多出 7–13ms,与括号里测的是结构还是 `:hover` / `:focus-within` 无关;位于最后一段的每条只有 0.1–0.5ms。
16
- - 全部改完后,整张样式表下每帧样式重算 1.9–2.7ms(不加载样式表时 1.4ms),主线程每帧总耗时 5–7ms。
17
- - 长会话里流式输出时,跟随在每一批文字到达时问一次页面,那批文字刚把样式写脏,这一次查询就换来一次整页样式重算。临时会话(120 轮、4286 个节点)实测:把这几处查询与同一帧里重复的读数去掉后,插件发出的文档级查询从 3263 次降到 2762 次(−15%),整页最长一次停顿从 270ms 降到 234ms;文档越大,省下的每次重算越贵。
18
-
19
- ## 代价
20
-
21
- - 结构状态要等脚本写入(同一帧、绘制之前)。
22
-
23
- ## 重审条件
24
-
25
- - 浏览器对非末段 `:has()` 的失效处理实测不再明显慢于末段写法。
@@ -1,86 +0,0 @@
1
- # 架构决策
2
-
3
- 本文件由 `npm run docs:index` 从各决策文件生成,勿手改。
4
-
5
- 决策每条一个文件,模板与维护规则见 [D48](D48-documentation.md)。编号是稳定标识,代码注释按编号引用;被推翻的编号作废、不复用。
6
-
7
- 状态为「待实施」的决策写着现状:迁移完成之前,以现状为准修改代码。
8
-
9
- ## 构建与源码
10
-
11
- | 编号 | 决策 | 状态 |
12
- | --- | --- | --- |
13
- | [D4](D4-composer-gate.md) | 输入框样式的构建期门控 | 已实施 |
14
- | [D5](D5-model-copy.md) | 模型文案是数据,不进产物 | 已实施 |
15
- | [D9](D9-style-performance.md) | 样式性能:结构判断写成属性,`:has()` 只放在最后一段 | 已实施 |
16
- | [D36](D36-modules-and-bundling.md) | TypeScript 与 ES 模块,esbuild 打出单文件产物 | 已实施 |
17
- | [D38](D38-assets.md) | 资源只有一条路径:内容哈希清单与通用资产路由 | 已实施 |
18
- | [D39](D39-on-demand-loading.md) | 按需加载:首屏用不到的功能拆成单独的块 | 已实施 |
19
- | [D46](D46-monorepo.md) | monorepo 布局,对外仍是一个插件 | 已实施 |
20
- | [D47](D47-build-output.md) | 构建产物不进主分支,发布分支提供 git 安装 | 部分实施 |
21
- | [D51](D51-css-toolchain.md) | CSS 工具链:语法树上的检查与一份令牌数据 | 已实施 |
22
-
23
- ## 宿主边界
24
-
25
- | 编号 | 决策 | 状态 |
26
- | --- | --- | --- |
27
- | [D3](D3-host-selectors.md) | 宿主选择器纪律 | 已实施 |
28
- | [D11](D11-private-routes.md) | 私有路由借宿主的请求栅栏;外来字符串只以文本上屏 | 已实施 |
29
- | [D19](D19-host-contracts.md) | 宿主契约与构建编号 | 已实施 |
30
- | [D28](D28-desktop-band.md) | 桌面标题带只在一处读取 | 已实施 |
31
- | [D30](D30-palette-and-typeface.md) | 配色与字体可以交给宿主 | 已实施 |
32
- | [D31](D31-windows-titlebar.md) | Windows 桌面顶栏透明,各列延伸到窗口顶端 | 已实施 |
33
- | [D33](D33-stylesheet-ownership.md) | 皮肤样式表带上本包自己的归属标记,兄弟包的样式表不认领 | 已实施 |
34
- | [D43](D43-overlay-and-upstream.md) | 覆盖层定位与等待扩展点 | 已实施 |
35
- | [D44](D44-contract-module.md) | 宿主契约模块与契约测试 | 已实施 |
36
- | [D60](D60-settings-transport.md) | 设置读写走官方 Config 表单,非 loopback 页面只读设置文档 | 已实施 |
37
- | [D61](D61-wallpaper-under-one-mask.md) | 壁纸插件在播壁纸时,Claude 配色在整个窗口铺一层底色遮罩 | 已实施 |
38
-
39
- ## 运行时
40
-
41
- | 编号 | 决策 | 状态 |
42
- | --- | --- | --- |
43
- | [D12](D12-fail-fast.md) | 快速失败与功能隔离 | 已实施 |
44
- | [D26](D26-motion-preference.md) | 动画效果偏好:一处解析,两处读同一个值 | 已实施 |
45
- | [D29](D29-feature-switches.md) | 功能开关:每个功能声明开关或不设开关的理由 | 已实施 |
46
- | [D35](D35-selection-scope.md) | 选区样式的作用范围 | 已实施 |
47
- | [D40](D40-observation-bus.md) | 观察总线与帧管线 | 已实施 |
48
- | [D41](D41-scroll-owner.md) | 聊天区的滚动位置只有一个写入者 | 已实施 |
49
- | [D42](D42-feature-manifest.md) | 功能清单 | 已实施 |
50
- | [D53](D53-usage-merge.md) | 用量两个来源按日期合并 | 已实施 |
51
-
52
- ## 功能
53
-
54
- | 编号 | 决策 | 状态 |
55
- | --- | --- | --- |
56
- | [D14](D14-account-surface.md) | 账号表面:一套行模型,两个挂载点 | 已实施 |
57
- | [D15](D15-hdsl-contract.md) | HDSL 账号契约:宿主半边转发,浏览器半边只认一条回退顺序 | 已实施 |
58
- | [D16](D16-popover-baseline.md) | 弹层基准:一套外壳、一个停留时长、一次只开一张 | 已实施 |
59
- | [D17](D17-permission-presets.md) | 权限档位以宿主目录为准,皮肤只做表现层 | 已实施 |
60
- | [D20](D20-sliding-pill.md) | 分段控件共用滑动高亮 | 已实施 |
61
- | [D21](D21-archived-list.md) | 已归档列表跟随宿主的两份客户端数据 | 已实施 |
62
- | [D22](D22-search-panel.md) | 搜索面板:宿主的 Modal、宿主的数据与导航 | 已实施 |
63
- | [D24](D24-mascot.md) | 吉祥物:宿主的状态、一套播放器、两个角色 | 已实施 |
64
- | [D25](D25-ban-screen-titlebar.md) | 封号彩蛋页在桌面端骑在系统标题栏那一行上 | 已实施 |
65
- | [D27](D27-context-stats.md) | 会话数字收进上下文弹层,或写在输入卡片下面自己一行 | 已实施 |
66
- | [D32](D32-chat-interactions.md) | 搬来的聊天区交互:自己的前缀、自己的偏好、对上游让位 | 已实施 |
67
- | [D34](D34-turn-navigator.md) | 对话导航:皮肤画导航条,跳转按宿主自己的刻度 | 部分实施 |
68
- | [D49](D49-visual-yield.md) | 让路:皮肤占用页面时收掉整套视觉,留下设置页 | 已实施 |
69
- | [D50](D50-brand.md) | 品牌两档:配色切换只靠令牌 | 已实施 |
70
- | [D52](D52-header-band.md) | 会话标题与顶栏控件抬进桌面端标题栏,放不下就留在原行 | 已实施 |
71
- | [D54](D54-peakrate-meter.md) | 峰谷电表:作息表是数据源的快照,判定在浏览器按真实时刻做 | 已实施 |
72
- | [D58](D58-redraw-retired.md) | 移除「重绘」档,过程组标题的计数摘要与等待行搬进「增强」档 | 已实施 |
73
- | [D62](D62-file-row-merge.md) | 同一文件的多次改动读成一行 | 已实施 |
74
- | [D63](D63-turn-status-retired.md) | 删除轮次状态行,运行中的说法归等待行一处 | 已实施 |
75
-
76
- ## 分发与流程
77
-
78
- | 编号 | 决策 | 状态 |
79
- | --- | --- | --- |
80
- | [D7](D7-one-package.md) | 行为层与皮肤对外是一个插件 | 已实施 |
81
- | [D45](D45-testing.md) | 三层测试与持续集成 | 已实施 |
82
- | [D48](D48-documentation.md) | 文档流程 | 已实施 |
83
-
84
- ## 作废的编号
85
-
86
- D1(由 D36 取代)、D2(由 D43 取代)、D6(由 D40 取代)、D8(由 D46 取代)、D10(由 D60 取代)、D13(由 D42 取代)、D18(由 D46 取代)、D23(由 D63 取代)、D37(由 D51 取代)、D55(由 D58 取代)、D56(由 D58 取代)、D57(由 D58 取代)、D59(由 D61 取代)。
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file