dsh-structured 0.9.4 → 0.9.9

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.
@@ -0,0 +1,38 @@
1
+ # 1.0 基线(0.9.8 冻结版)
2
+
3
+ ## 固定 10 条 prompt
4
+
5
+ 1. P01:给一个 5 人团队做本周发布计划。
6
+ 2. P02:解释一个 Redis 连接池泄露的排查顺序。
7
+ 3. P03:比较 Postgres 与 SQLite 的适用边界。
8
+ 4. P04:把一份长会议记录压缩成决策、风险和下一步。
9
+ 5. P05:给一个前端页面做无障碍检查清单。
10
+ 6. P06:写一个可回滚的数据库迁移方案。
11
+ 7. P07:分析一段 Python 异步代码的死锁风险。
12
+ 8. P08:给一个 API 设计写三组验收用例。
13
+ 9. P09:用表格比较三种缓存策略。
14
+ 10. P10:对一个失败发布做 5-Why 复盘。
15
+
16
+ ## 注入口径(0.9.8)
17
+
18
+ 当前 `BUILTIN_STYLE_TEXT` 940 字符;GenUI 路由 186 字符;尾部提醒 206 字符。合计 1332 字符,约 333 token(按 4 字符/token 估算;不是宿主 tokenizer 实测)。10 条 prompt 共用同一注入段,per-turn 注入增量以宿主实际 tokenizer 为准。
19
+
20
+ ## 输出与结构化率
21
+
22
+ - 首屏结构化率、散文率:沿用 `docs/METRICS.md` 的 12 个新会话样本(注入 12/12,散文 0/12);这是 0.9.x 既有样本,不是本轮 10 条固定 prompt 的新跑结果。
23
+ - 输出 token 增量:**未测**;本轮没有调用模型执行 10 条固定 prompt,不能用旧样本冒充。
24
+ - 3×2 桌面实机截图:**未验**;0.9.6 的视觉截图是 web profile 裁图,0.9.8 没有安装到 desktop。
25
+
26
+ ## `style.md` 1.0 迁移语义(冻结)
27
+
28
+ - `style.md`:非空即整份覆盖内置 `BUILTIN_STYLE_TEXT`;不做片段合并。
29
+ - 需要保留结构规则时,把 `BUILTIN_STYLE_TEXT` 全文复制到 `style.md`,再追加自己的文本。
30
+ - 1.0 的 `persona.md` 只作为**追加层**设计,不改变 `style.md` 的整份覆盖语义;结构规则始终注入,见 `docs/1.0-PERSONA-SPEC.md`。
31
+ - 读取失败、文件为空、权限错误均 fail-open:回退内置规则,不阻断回复。
32
+ - 迁移路径:现有 `style.md` 用户不需要改文件;若 1.0 要同时使用结构规则和人格,按 1.0 spec 使用 `persona.md` 追加,而不是把人格塞进 `style.md`。
33
+
34
+ ## 待验
35
+
36
+ - 10 条固定 prompt 的实际注入/输出 token。
37
+ - 10 条固定 prompt 的首屏结构化率与散文率。
38
+ - 3×2 桌面实机截图与 800px 实机窄窗。
@@ -0,0 +1,39 @@
1
+ # 1.0 人格 gate(0.9.9,PM 主导)
2
+
3
+ ## 目的
4
+
5
+ 决定 1.0 是否开放 persona 追加层;不评价人格文案好坏,只评价结构保留、token 增量、偏好和 P0。
6
+
7
+ ## 受试与分组
8
+
9
+ - 5–10 名真实用户;PM 招募/主持,开发只提供夹具与测量。
10
+ - 每组同一批任务,三组顺序随机:
11
+ 1. **无 persona**:仅结构规则。
12
+ 2. **style.md 覆盖**:用户自己的整份 style.md(保留现有语义)。
13
+ 3. **persona.md 追加**:结构规则 + persona 追加层。
14
+
15
+ ## 固定任务
16
+
17
+ 使用 `docs/1.0-BASELINE.md` 的 P01–P10;每人至少完成 5 条,覆盖报告、代码/ diff、比较、风险/下一步。
18
+
19
+ ## 测量
20
+
21
+ - 结构保留:首屏标题卡/表格/列表/结论等结构不下降;用现有 `scripts/measure-prose.mjs` + 人工抽查。
22
+ - token 增量:同一任务三组的注入 token 与实际输出 token;必须给出数字,不用“差不多”。
23
+ - 偏好:受试者在三组中选最愿意继续用的一组;目标 **≥60% 偏好 persona 追加层**。
24
+ - P0:任何阻断回复、覆盖结构规则、泄露个人信息、改变工具权限/GenUI/代码隔离的案例即 P0。
25
+
26
+ ## 通过条件
27
+
28
+ 1. 结构保留不下降;
29
+ 2. token 增量有数字且可接受(PM 定阈值);
30
+ 3. ≥60% 偏好追加层;
31
+ 4. 无 P0。
32
+
33
+ 任何一项不满足:1.0 不开人格功能,回到 spec/文档方案。0.9.x 不开放用户入口。
34
+
35
+ ## 当前状态
36
+
37
+ - 夹具:`test/fixtures/persona-gate/` 三组。
38
+ - 用户 gate:**未执行**(0 名用户);0.9.9 只能交付“待 gate”,不能伪造 go。
39
+ - 结论:**NO-GO / pending**,直到 PM 提供 5–10 名用户结果。
@@ -0,0 +1,59 @@
1
+ # 1.0 人格化 spec / schema(0.9.9 草案,不实现)
2
+
3
+ ## 定位
4
+
5
+ 1.0 的人格是 **profile 级追加层**,不是替换层:
6
+
7
+ 1. 结构规则:始终由 base 注入。base 默认是 `BUILTIN_STYLE_TEXT`;`style.md` 非空时按现有契约整份覆盖 base(显式例外,用户自己承担丢失结构规则)。
8
+ 2. `persona.md`:只追加在 base 之后,不能删除、替换结构规则,不能修改 host 提示词或消息内容。
9
+ 3. 不碰 `AGENTS.md`、`soul`、工具权限、GenUI 路由和代码/diff 隔离。
10
+
11
+ ## 路径与读取顺序
12
+
13
+ - profile 级路径:`$DSH_PROFILE_DIR/dsh-structured/persona.md`;缺省 profile 目录时按宿主 profile 解析,不读其他 profile。
14
+ - 读取顺序:base(内置或 `style.md` 整份覆盖)→ `persona.md` 追加层。
15
+ - 两个文件都存在时,`style.md` 仍只控制 base;`persona.md` 不参与 base 覆盖。
16
+ - 读取失败、权限错误、文件缺失、schema 不合法:忽略 persona,继续 base,fail-open,不阻断回复。
17
+
18
+ ## Schema
19
+
20
+ `persona.md` 是 UTF-8 Markdown,可选 frontmatter:
21
+
22
+ ```yaml
23
+ ---
24
+ schema: dsh-structured/persona@1
25
+ scope: profile
26
+ append: true
27
+ recommended_max_chars: 4000
28
+ ---
29
+ # 称呼与语气
30
+ ...
31
+ ```
32
+
33
+ - `schema` 必须精确匹配 `dsh-structured/persona@1`;不匹配时忽略并记录一次非阻断警告。
34
+ - `append` 只能为 `true`;`false` 不提供“替换结构”的入口。
35
+ - `recommended_max_chars` 只是建议;**不硬截断**。超过建议值时在设置页显示提示,不改变实际内容。
36
+ - 正文只作为文本 section 追加;不插值 `{{...}}`,不执行命令,不解析 Markdown 到 DOM。
37
+
38
+ ## 优先级与迁移
39
+
40
+ 1. 结构规则:`BUILTIN_STYLE_TEXT`(默认)或 `style.md`(整份覆盖)。
41
+ 2. `persona.md`:追加层,不能覆盖 1。
42
+ 3. 其他 profile/全局文件:不参与。
43
+
44
+ 迁移:
45
+
46
+ - 现有 `style.md` 用户不需要改文件;0.9.x 不读 `persona.md`,行为不变。
47
+ - 1.0 想保留结构规则并加人格:保留/复制 `BUILTIN_STYLE_TEXT` 到 `style.md`,把人格写进 `persona.md`;或保持 `style.md` 为空,使用内置结构 + persona 追加。
48
+ - 不建议把人格塞进 `style.md`,否则会整份覆盖结构规则。
49
+
50
+ ## 隐私与安全
51
+
52
+ - persona 可能包含个人信息;只保存在本机 profile,不进入 npm 包、不写日志、不上传、不进市场。
53
+ - 文档和设置页必须提示“persona 可能含个人信息,分享 profile 前先清理”。
54
+ - persona 不能包含工具调用、系统指令覆盖、凭据或外部 URL 执行语义;仅作为文本追加。
55
+
56
+ ## 0.9.9 不实现
57
+
58
+ - 不加设置页入口、不新增命令、不做人格市场/编辑器/预设包、不读 `persona.md` 运行时。
59
+ - 只提供本 spec、三组 gate 夹具和测量口径;1.0 是否上线由 gate 决定。
package/lib/client.js CHANGED
@@ -1,5 +1,5 @@
1
- // Generated from src/client.js by scripts/build.mjs — edit src/, then run `npm run build`.
2
- // dsh-structured client module: renders "结论:" blockquotes as cards.
1
+ // Generated from src/client.js by scripts/build.mjs — edit src/, then run `npm run build`.
2
+ // dsh-structured client module: renders "结论:" blockquotes as cards.
3
3
  /**
4
4
  * dsh-structured client
5
5
  *
@@ -131,12 +131,12 @@ body[data-ds-dark-theme][data-dsh-structured-theme="codex"] [class*="_markdown_"
131
131
  }
132
132
  body[data-dsh-structured-theme="anthropic"] [class*="_markdown_"]{
133
133
  --ds-surface:#FAF9F5;--ds-surface-2:#F5F1E8;--ds-text:#141413;--ds-muted:#6B6359;
134
- --ds-border:#E5E0D5;--ds-accent:#CC785C;--ds-accent-text:#A14A2E;--ds-success:#266B4D;--ds-warn:#92400E;--ds-error:#8C1D18;
134
+ --ds-border:#E5E0D5;--ds-accent:#CC785C;--ds-accent-text:#A14A2E;--ds-success:#266B4D;--ds-warn:#806000;--ds-error:#8C1D18;
135
135
  --ds-code-bg:#F5F1E8;--ds-code-text:#141413;
136
136
  }
137
137
  body[data-ds-dark-theme][data-dsh-structured-theme="anthropic"] [class*="_markdown_"]{
138
138
  --ds-surface:#1F1E1D;--ds-surface-2:#2A2825;--ds-text:#F5F1E8;--ds-muted:#A8A29A;
139
- --ds-border:#3A3733;--ds-accent:#E8A087;--ds-accent-text:#E8A087;--ds-success:#6FBF9A;--ds-warn:#E0A458;--ds-error:#F28B82;
139
+ --ds-border:#3A3733;--ds-accent:#E8A087;--ds-accent-text:#E8A087;--ds-success:#6FBF9A;--ds-warn:#EAB308;--ds-error:#F28B82;
140
140
  --ds-code-bg:#171614;--ds-code-text:#F5F1E8;
141
141
  }
142
142
  [class*="_markdown_"] p{margin:.72em 0}
@@ -147,13 +147,15 @@ body[data-ds-dark-theme][data-dsh-structured-theme="anthropic"] [class*="_markdo
147
147
  [class*="_markdown_"] h1{font-size:26px;font-weight:700;margin:32px 0 12px;padding-bottom:8px;border-bottom:1px solid var(--ds-border)}
148
148
  [class*="_markdown_"] h2{font-size:21px;font-weight:700;margin:28px 0 10px;padding-left:12px;border-left:3px solid var(--ds-accent)}
149
149
  [class*="_markdown_"] h3{font-size:17px;font-weight:650;margin:22px 0 8px}
150
+ [class*="_markdown_"] h2[${ICON_ATTR}]{padding-left:42px;text-indent:-30px}
151
+ [class*="_markdown_"] h3[${ICON_ATTR}]{padding-left:30px;text-indent:-30px}
150
152
  [class*="_markdown_"] h4{font-size:15px;font-weight:650;margin:16px 0 6px}
151
153
  [class*="_markdown_"] h5,[class*="_markdown_"] h6{font-size:13px;font-weight:700;margin:14px 0 6px;color:var(--ds-muted);text-transform:uppercase;letter-spacing:.06em}
152
154
  [class*="_markdown_"] h2[${ICON_ATTR}]::before,
153
155
  [class*="_markdown_"] h3[${ICON_ATTR}]::before{
154
156
  content:attr(${ICON_ATTR});
155
157
  display:inline-flex;align-items:center;justify-content:center;
156
- width:22px;height:22px;margin-right:8px;border-radius:6px;
158
+ width:22px;height:22px;margin-right:8px;text-indent:0;border-radius:6px;
157
159
  background:color-mix(in srgb,var(--ds-accent) 12%,transparent);
158
160
  color:var(--ds-accent-text);font-size:12px;font-weight:700;vertical-align:2px;
159
161
  }
@@ -165,18 +167,19 @@ body[data-ds-dark-theme][data-dsh-structured-theme="anthropic"] [class*="_markdo
165
167
  [class*="_markdown_"] li::marker{color:var(--ds-accent-text)}
166
168
  [class*="_markdown_"] hr{height:1px;border:0;margin:28px 0;background:linear-gradient(90deg,transparent,var(--ds-border),transparent)}
167
169
  [class*="_markdown_"] table:not([${SKIP_ATTR}]){
168
- width:100%;margin:18px 0;border-collapse:separate;border-spacing:0;
169
- border:1px solid var(--ds-border);border-radius:12px;overflow:hidden;font-size:13.5px;
170
+ width:100%;margin:16px 0;border-collapse:separate;border-spacing:0;
171
+ border:1px solid var(--ds-border);border-radius:12px;overflow:hidden;font-size:12.5px;
170
172
  box-shadow:0 1px 2px rgba(0,0,0,.03);
171
173
  }
172
174
  [class*="_markdown_"] table:not([${SKIP_ATTR}]) thead th{
173
- background:var(--ds-surface-2);
174
- font-size:11px!important;letter-spacing:.07em!important;color:var(--ds-muted);
175
- font-weight:700!important;text-align:left;padding:12px 18px!important;
175
+ height:38px;background:var(--ds-surface-2);
176
+ font-size:13px!important;letter-spacing:0!important;
177
+ color:color-mix(in srgb,var(--ds-text) 78%,var(--ds-muted));
178
+ font-weight:700!important;text-align:left;padding:0 18px!important;vertical-align:middle;
176
179
  border-bottom:1px solid var(--ds-border);
177
180
  }
178
181
  [class*="_markdown_"] table:not([${SKIP_ATTR}]) tbody td{
179
- padding:13px 18px!important;line-height:1.55;vertical-align:middle;border-left:0;border-right:0;
182
+ padding:12px 18px!important;line-height:1.55;vertical-align:middle;border-left:0;border-right:0;
180
183
  border-bottom:1px solid color-mix(in srgb,var(--ds-border) 55%,transparent);
181
184
  word-break:break-word;
182
185
  }
@@ -191,17 +194,17 @@ body[data-ds-dark-theme][data-dsh-structured-theme="anthropic"] [class*="_markdo
191
194
  [class*="_markdown_"] table:not([${SKIP_ATTR}]):not([${STATUS_TABLE_ATTR}]):has(thead th:nth-child(3):last-child) td:nth-child(2){width:22%}
192
195
  [class*="_markdown_"] table:not([${SKIP_ATTR}])[${STATUS_TABLE_ATTR}] th:first-child,
193
196
  [class*="_markdown_"] table:not([${SKIP_ATTR}])[${STATUS_TABLE_ATTR}] td:first-child{
194
- width:68px;text-align:center;padding:7px 8px!important;font-size:11px;font-weight:700;
195
- white-space:nowrap;vertical-align:middle;border-radius:7px;
197
+ width:68px;text-align:center;padding:4px 8px!important;font-size:10px;font-weight:700;
198
+ white-space:nowrap;vertical-align:middle;border-radius:6px;
196
199
  }
197
200
  [class*="_markdown_"] table:not([${SKIP_ATTR}])[${STATUS_TABLE_ATTR}] tbody tr[${ROW_ATTR}="success"] td:first-child{background:color-mix(in srgb,var(--ds-success) 12%,transparent);color:var(--ds-success)}
198
201
  [class*="_markdown_"] table:not([${SKIP_ATTR}])[${STATUS_TABLE_ATTR}] tbody tr[${ROW_ATTR}="warn"] td:first-child{background:color-mix(in srgb,var(--ds-warn) 12%,transparent);color:var(--ds-warn)}
199
202
  [class*="_markdown_"] table:not([${SKIP_ATTR}])[${STATUS_TABLE_ATTR}] tbody tr[${ROW_ATTR}="error"] td:first-child{background:color-mix(in srgb,var(--ds-error) 12%,transparent);color:var(--ds-error)}
200
203
  [class*="_markdown_"] p[${LEAD_ATTR}="table"]{
201
- border-left:2px solid var(--ds-accent);padding-left:10px;margin:10px 0 8px;
202
- font-size:14px;color:var(--ds-text);
204
+ border:0;padding:0;margin:12px 0 8px;
205
+ font-size:13px;color:var(--ds-text);
203
206
  }
204
- [class*="_markdown_"] p[${LEAD_ATTR}="table"] strong{color:var(--ds-accent-text)}
207
+ [class*="_markdown_"] p[${LEAD_ATTR}="table"] strong{font-size:14px;font-weight:700;color:var(--ds-text)}
205
208
  [class*="_markdown_"] h2+table,[class*="_markdown_"] h2+p,[class*="_markdown_"] h3+table,[class*="_markdown_"] h3+p{margin-top:8px}
206
209
  [class*="_markdown_"] :not(pre)>code{
207
210
  background:var(--ds-surface-2);border:1px solid var(--ds-border);border-radius:6px;
@@ -252,65 +255,49 @@ body[data-ds-dark-theme][data-dsh-structured-theme="anthropic"] [class*="_markdo
252
255
  [class*="_markdown_"] blockquote[${TONE_ATTR}="warn"]{--ds-accent:var(--ds-warn);--ds-accent-text:var(--ds-warn)}
253
256
  [class*="_markdown_"] blockquote[${TONE_ATTR}="success"]{--ds-accent:var(--ds-success);--ds-accent-text:var(--ds-success)}
254
257
  [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]{
255
- border:1px solid color-mix(in srgb,var(--ds-accent) 16%,var(--ds-border));
258
+ border:1px solid color-mix(in srgb,var(--ds-accent) 18%,var(--ds-border));
256
259
  border-left:3px solid var(--ds-accent);
257
- border-radius:12px;padding:14px 16px 15px;
258
- background:linear-gradient(135deg,color-mix(in srgb,var(--ds-accent) 6%,var(--ds-surface)),var(--ds-surface) 60%);
259
- box-shadow:0 1px 2px rgba(0,0,0,.04),0 12px 32px -24px color-mix(in srgb,var(--ds-accent) 32%,transparent);
260
+ border-radius:12px;padding:18px;
261
+ background:linear-gradient(135deg,color-mix(in srgb,var(--ds-accent) 5%,var(--ds-surface)),var(--ds-surface) 62%);
262
+ box-shadow:0 1px 2px rgba(0,0,0,.04);
260
263
  }
261
264
  [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]>p:first-child>strong:first-child{
262
- display:flex;align-items:center;gap:9px;position:relative;
263
- font-size:13px;line-height:1.1;letter-spacing:.06em;text-transform:uppercase;
264
- color:var(--ds-accent-text);margin-bottom:8px;
265
+ display:block;position:static;
266
+ font-size:14px;line-height:1.3;letter-spacing:0;text-transform:none;
267
+ color:var(--ds-accent-text);margin-bottom:6px;
265
268
  }
266
- [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]>p:first-child>strong:first-child::before{
267
- content:"";display:inline-flex;flex:none;
268
- width:26px;height:26px;border-radius:7px;
269
- background:color-mix(in srgb,var(--ds-accent) 12%,transparent);
270
- }
271
- [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]>p:first-child>strong:first-child::after{
272
- content:"";position:absolute;left:5.5px;top:5.5px;width:15px;height:15px;
273
- background-color:var(--ds-accent);
274
- -webkit-mask:var(--ds-card-icon) center/contain no-repeat;
275
- mask:var(--ds-card-icon) center/contain no-repeat;
276
- }
277
- [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]>p:nth-child(2)>strong:first-child{
278
- display:block;font-size:16px;font-weight:700;line-height:1.45;
279
- letter-spacing:-.01em;color:var(--ds-text);margin-bottom:4px;
280
- }
281
- [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]>p{font-size:15.5px;line-height:1.7;font-weight:450;color:var(--ds-text)}
269
+ [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]>p{font-size:13px;line-height:1.6;font-weight:400;color:var(--ds-text)}
282
270
  [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]>p strong{font-weight:700;color:var(--ds-text)}
283
271
  [class*="_markdown_"] blockquote[${TONE_ATTR}]>p:first-child>strong:first-child{color:var(--ds-accent-text)}
284
- [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="conclusion"]{
285
- --ds-card-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3l9 9-9 9-9-9 9-9z' fill='none' stroke='black' stroke-width='1.8' stroke-linejoin='round'/%3E%3C/svg%3E");
286
- }
287
- [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="decision"]{
288
- --ds-card-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 7h6l4 10h6M4 17h6l4-10h6' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
289
- }
290
- [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="metric"]{
291
- --ds-card-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 20V10M12 20V4M19 20v-7' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
272
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="risk"]{--ds-accent:var(--ds-warn);--ds-accent-text:var(--ds-warn)}
273
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="accept"]{--ds-accent:var(--ds-success);--ds-accent-text:var(--ds-success)}
274
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="statement"]>p:first-child>strong:first-child{
275
+ font-size:24px;line-height:1.25;letter-spacing:-.02em;text-transform:none;
276
+ color:var(--ds-text);margin-bottom:0;
292
277
  }
293
- [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="risk"]{
294
- --ds-accent:var(--ds-warn);--ds-accent-text:var(--ds-warn);
295
- --ds-card-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 4l9 16H3L12 4z' fill='none' stroke='black' stroke-width='1.8' stroke-linejoin='round'/%3E%3Cpath d='M12 10v4M12 17v.5' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E");
278
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="statement"]>p:first-child>strong:first-child::after{
279
+ content:"";display:block;height:1px;margin:12px 0;
280
+ background:var(--ds-border);
296
281
  }
282
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="statement"]>p{font-size:13.5px;line-height:1.6;font-weight:400}
283
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="statement"]>p:first-child{margin-bottom:0}
297
284
  [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="next"]{
298
- --ds-card-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
299
- }
300
- [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="accept"]{
301
- --ds-accent:var(--ds-success);--ds-accent-text:var(--ds-success);
302
- --ds-card-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 12.5l5 5L20 6.5' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
303
- }
304
- [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="key"]{
305
- --ds-card-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3l2.6 6.2 6.7.5-5.1 4.4 1.6 6.5L12 17.3 6.2 20.6l1.6-6.5L2.7 9.7l6.7-.5L12 3z' fill='none' stroke='black' stroke-width='1.6' stroke-linejoin='round'/%3E%3C/svg%3E");
306
- }
307
- [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="statement"]{
308
- --ds-card-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3l9 9-9 9-9-9 9-9z' fill='none' stroke='black' stroke-width='1.8' stroke-linejoin='round'/%3E%3C/svg%3E");
309
- }
310
- [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="statement"]>p:first-child>strong:first-child{
311
- font-size:16px;line-height:1.45;letter-spacing:-.01em;text-transform:none;
312
- color:var(--ds-text);margin-bottom:4px;
313
- }
285
+ background:none;border:0;border-top:1px solid var(--ds-border);border-radius:0;
286
+ box-shadow:none;padding:14px 0 0 14px;margin:18px 0;position:relative;
287
+ }
288
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="next"]::before{
289
+ content:"";position:absolute;left:0;top:17px;width:0;height:0;
290
+ border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:9px solid #C2410C;
291
+ }
292
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="next"]>p:first-child>strong:first-child{
293
+ font-size:16px;line-height:1.3;color:var(--ds-text);margin-bottom:8px;
294
+ }
295
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="next"]>p,
296
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="next"] li{font-size:13px;line-height:1.6}
297
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="next"] ol,
298
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="next"] ul{padding-left:0;margin:.4em 0 0;list-style-position:inside}
299
+ [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="next"] li{padding-left:0}
300
+ body[data-ds-dark-theme] [class*="_markdown_"] blockquote[${CARD_TYPE_ATTR}="next"]::before{border-left-color:#FB923C}
314
301
  [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]>p:first-child{margin-top:0}
315
302
  [class*="_markdown_"] blockquote[${CARD_ATTR}="1"]>p:last-child{margin-bottom:0}
316
303
  [class*="_markdown_"] p[${STATUS_ATTR}],[class*="_markdown_"] li[${STATUS_ATTR}]{
@@ -664,11 +651,36 @@ body[data-ds-dark-theme][data-dsh-structured-theme="anthropic"] [class*="_markdo
664
651
  let disposed = false
665
652
  let scheduled = false
666
653
  let pending = null
654
+ let pendingRoots = null
655
+
656
+ // 增量扫描:mutation 只重扫它所在的 markdown 容器(或新增子树),
657
+ // 避免长会话里每帧对整页做一次全量 querySelectorAll(O(N²))。
658
+ const markRoot = (node) => {
659
+ if (!node) return
660
+ const element = node.nodeType === 1 ? node : node.parentElement
661
+ if (!element) return
662
+ const markdown = element.closest?.('[class*="_markdown_"]')
663
+ const root = markdown ?? element
664
+ if (pendingRoots === null) pendingRoots = new Set()
665
+ pendingRoots.add(root)
666
+ }
667
667
  const run = () => {
668
668
  if (disposed) return
669
669
  scheduled = false
670
670
  pending = null
671
- decorate(document)
671
+ const roots = pendingRoots
672
+ pendingRoots = null
673
+ if (roots === null) {
674
+ decorate(document)
675
+ return
676
+ }
677
+ const list = [...roots]
678
+ for (const root of list) {
679
+ if (root?.isConnected === false) continue
680
+ // 被另一个待扫根包含时跳过,避免重复工作。
681
+ if (list.some((other) => other !== root && other.contains?.(root))) continue
682
+ decorate(root)
683
+ }
672
684
  }
673
685
  const schedule = () => {
674
686
  if (disposed || scheduled) return
@@ -676,7 +688,22 @@ body[data-ds-dark-theme][data-dsh-structured-theme="anthropic"] [class*="_markdo
676
688
  if (typeof requestAnimationFrame === 'function') pending = requestAnimationFrame(run)
677
689
  else pending = setTimeout(run, 16)
678
690
  }
679
- const observer = new MutationObserver(schedule)
691
+ const observer = new MutationObserver((records) => {
692
+ try {
693
+ for (const record of records) {
694
+ if (record.type === 'childList') {
695
+ for (const node of record.addedNodes) markRoot(node)
696
+ if (record.addedNodes.length === 0) markRoot(record.target)
697
+ } else {
698
+ markRoot(record.target)
699
+ }
700
+ }
701
+ } catch {
702
+ // 记录结构异常时退回整页扫描,保证装饰不丢。
703
+ pendingRoots = null
704
+ }
705
+ schedule()
706
+ })
680
707
  observer.observe(document.body, { childList: true, subtree: true, characterData: true })
681
708
  run()
682
709