oh-my-knowledge 0.35.0 → 0.37.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.
Files changed (90) hide show
  1. package/README.md +5 -3
  2. package/README.zh.md +5 -3
  3. package/dist/assets/agent-skills/omk/SKILL.md +4 -2
  4. package/dist/assets/agent-skills/omk/references/commands.md +121 -2
  5. package/dist/authoring/evolver.js +1 -1
  6. package/dist/cli/commands/doctor.js +21 -5
  7. package/dist/cli/commands/eval/index.js +7 -6
  8. package/dist/cli/commands/evolve.d.ts +11 -0
  9. package/dist/cli/commands/evolve.js +105 -5
  10. package/dist/cli/commands/list.d.ts +25 -0
  11. package/dist/cli/commands/list.js +118 -0
  12. package/dist/cli/commands/promote.d.ts +24 -0
  13. package/dist/cli/commands/promote.js +158 -0
  14. package/dist/cli/commands/rollback.d.ts +20 -0
  15. package/dist/cli/commands/rollback.js +95 -0
  16. package/dist/cli/commands/sample.d.ts +1 -0
  17. package/dist/cli/commands/sample.js +10 -4
  18. package/dist/cli/lib/cell-format.d.ts +17 -0
  19. package/dist/cli/lib/cell-format.js +19 -0
  20. package/dist/cli/lib/cmd-flags.d.ts +1 -0
  21. package/dist/cli/lib/i18n-dict/common.d.ts +1 -1
  22. package/dist/cli/lib/i18n-dict/common.js +8 -0
  23. package/dist/cli/lib/i18n-dict/list.d.ts +3 -0
  24. package/dist/cli/lib/i18n-dict/list.js +36 -0
  25. package/dist/cli/lib/i18n-dict/promote.d.ts +3 -0
  26. package/dist/cli/lib/i18n-dict/promote.js +54 -0
  27. package/dist/cli/lib/i18n-dict/rollback.d.ts +3 -0
  28. package/dist/cli/lib/i18n-dict/rollback.js +22 -0
  29. package/dist/cli/lib/i18n-dict.d.ts +4 -1
  30. package/dist/cli/lib/i18n-dict.js +6 -0
  31. package/dist/cli/lib/progress.d.ts +3 -0
  32. package/dist/cli/lib/progress.js +22 -0
  33. package/dist/cli/lib/run-tally.js +1 -1
  34. package/dist/cli/lib/shared.js +1 -1
  35. package/dist/cli/lib/source-probe.d.ts +15 -0
  36. package/dist/cli/lib/source-probe.js +129 -0
  37. package/dist/doctor/endpoint-rule.d.ts +60 -0
  38. package/dist/doctor/endpoint-rule.js +381 -0
  39. package/dist/doctor/health/load-custom-dimensions.d.ts +6 -0
  40. package/dist/doctor/health/load-custom-dimensions.js +43 -3
  41. package/dist/doctor/index.js +9 -2
  42. package/dist/eval-core/evaluation-reporting.d.ts +1 -0
  43. package/dist/eval-core/evaluation-reporting.js +6 -4
  44. package/dist/eval-workflows/batch-evaluation-workflow.js +3 -2
  45. package/dist/eval-workflows/run-evaluation.js +2 -2
  46. package/dist/executors/codex-cli.js +5 -1
  47. package/dist/inputs/skill-loader.js +6 -3
  48. package/dist/managed/index.d.ts +2 -0
  49. package/dist/managed/index.js +2 -0
  50. package/dist/managed/list-view.d.ts +58 -0
  51. package/dist/managed/list-view.js +70 -0
  52. package/dist/managed/promote-gate.d.ts +40 -0
  53. package/dist/managed/promote-gate.js +37 -0
  54. package/dist/managed/store.d.ts +25 -2
  55. package/dist/managed/store.js +137 -11
  56. package/dist/observability/experience.d.ts +2 -0
  57. package/dist/observability/experience.js +31 -2
  58. package/dist/observability/inbox.js +31 -5
  59. package/dist/observability/review-state.js +22 -11
  60. package/dist/observability/soft-standards/llm-extractor.js +3 -3
  61. package/dist/observability/soft-standards/skill-standards-store.d.ts +1 -0
  62. package/dist/observability/soft-standards/skill-standards-store.js +77 -14
  63. package/dist/observability/soft-standards/types.d.ts +2 -2
  64. package/dist/renderer/doctor-detail-renderer.d.ts +9 -0
  65. package/dist/renderer/doctor-detail-renderer.js +114 -0
  66. package/dist/renderer/html-renderer.d.ts +3 -2
  67. package/dist/renderer/html-renderer.js +102 -102
  68. package/dist/renderer/icons.d.ts +29 -0
  69. package/dist/renderer/icons.js +66 -0
  70. package/dist/renderer/layout.js +81 -68
  71. package/dist/renderer/observation-inbox/styles.d.ts +1 -1
  72. package/dist/renderer/observation-inbox/styles.js +53 -53
  73. package/dist/renderer/report-shell.d.ts +77 -0
  74. package/dist/renderer/report-shell.js +223 -0
  75. package/dist/renderer/skill-detail-renderer.js +147 -352
  76. package/dist/renderer/skill-health-renderer.js +50 -73
  77. package/dist/renderer/skill-list-renderer.js +358 -306
  78. package/dist/renderer/summary.js +272 -162
  79. package/dist/renderer/test-view.d.ts +4 -3
  80. package/dist/renderer/test-view.js +386 -135
  81. package/dist/server/report-server.js +142 -28
  82. package/dist/server/report-store.d.ts +1 -1
  83. package/dist/server/report-store.js +16 -15
  84. package/dist/server/skill-index.js +5 -4
  85. package/dist/types/doctor.d.ts +24 -2
  86. package/dist/types/doctor.js +1 -1
  87. package/dist/types/managed.d.ts +17 -3
  88. package/dist/types/observability.d.ts +6 -6
  89. package/dist/types/report.d.ts +9 -4
  90. package/package.json +1 -1
@@ -0,0 +1,223 @@
1
+ /**
2
+ * 报告详情页统一外壳(doctor / eval / observe 共用)。
3
+ *
4
+ * 设计原则(与首页 / skill 弹框风格统一):
5
+ * - 纯白卡片 + 冷灰边框 #e4e8f1 + 柔和阴影
6
+ * - 综合分用 score ring,色阶 100 绿 / ≥60 橙 / <60 红
7
+ * - 维度色:doctor 蓝 #2563eb / eval 紫 #7c3aed / observe 绿 #059669
8
+ * - 主次分明:Hero 综合结论在最上,明细按 fail→warn→pass 排序,通过项折叠
9
+ */
10
+ import { layout, e, DEFAULT_LANG } from './layout.js';
11
+ import { icon, dimIconName } from './icons.js';
12
+ /** 维度中/英文名(面包屑、历史分组等复用)。 */
13
+ function dimLabel(dim, lang) {
14
+ const zh = lang === 'zh';
15
+ return dim === 'doctor' ? (zh ? '体检' : 'Doctor') : dim === 'eval' ? (zh ? '评测' : 'Eval') : (zh ? '观察' : 'Observe');
16
+ }
17
+ export const DIM_COLORS = {
18
+ doctor: '#2563eb',
19
+ eval: '#7c3aed',
20
+ observe: '#059669',
21
+ };
22
+ export function scoreColor(s) {
23
+ return s >= 100 ? '#1f9d63' : s >= 60 ? '#d97706' : '#dc2626';
24
+ }
25
+ /** 跨维度「综合健康」0-100 配色:≥85 绿 / ≥60 琥珀 / 其余红 / null 灰。
26
+ * 与 scoreColor(doctor 严格「100 才绿」)分开 —— 综合健康是聚合分,90 应读作"好"(绿),
27
+ * 而不是 doctor 那种"非满分即有问题"。Hero ring 与首页列表统一用它,避免同一个数两种颜色。 */
28
+ export function healthColor(score) {
29
+ if (score == null)
30
+ return '#9ca3af';
31
+ return score >= 85 ? '#1f9d63' : score >= 60 ? '#d97706' : '#dc2626';
32
+ }
33
+ /** band → 十六进制色(绿/黄/红/灰)。供 hero 综合健康 ring、chip 状态点等复用。 */
34
+ export function bandHex(band) {
35
+ return band === 'green' ? '#1f9d63' : band === 'yellow' ? '#d97706' : band === 'red' ? '#dc2626' : '#9ca3af';
36
+ }
37
+ // 维度身份用 DIM_COLORS 着色的小圆点(doctor 蓝 / eval 紫 / observe 绿),分数用 band 色。
38
+ // 维度切换器 = 分段控件风:当前维度填充高亮,其余可点跳到兄弟报告。右侧「全部历史」按钮弹框选历次 run。
39
+ function renderSkillContext(ctx, lang) {
40
+ const zh = lang === 'zh';
41
+ // tab 上不放分数 —— 只一个状态点(band 色)+ 维度名,点击直接看该维度明细。综合总分在 Hero。
42
+ const chipHtml = ctx.chips.map((c) => {
43
+ const dot = `<span class="rs-dim-dot" style="background:${c.band === 'gray' ? '#cbd2dd' : bandHex(c.band)}"></span>`;
44
+ const inner = `${dot}<span class="rs-dim-lbl">${e(c.label)}</span>`;
45
+ if (c.active)
46
+ return `<span class="rs-dim rs-dim--active" aria-current="page">${inner}</span>`;
47
+ if (c.href)
48
+ return `<a class="rs-dim" href="${e(c.href)}">${inner}</a>`;
49
+ return `<span class="rs-dim rs-dim--empty">${inner}</span>`;
50
+ }).join('');
51
+ const histBtn = ctx.history.length > 0
52
+ ? `<button type="button" class="rs-hist-btn" onclick="document.getElementById('rs-hist').style.display='flex'">${zh ? '全部历史' : 'All history'} <span class="rs-hist-ct">${ctx.history.length}</span></button>`
53
+ : '';
54
+ const bar = `<div class="rs-dims"><span class="rs-dims-seg">${chipHtml}</span>${histBtn}</div>`;
55
+ if (ctx.history.length === 0)
56
+ return bar;
57
+ const groups = ['eval', 'doctor'].map((dim) => {
58
+ const items = ctx.history.filter((h) => h.dim === dim);
59
+ if (items.length === 0)
60
+ return '';
61
+ const rows = items.map((h) => `<a class="rs-hist-row${h.current ? ' rs-hist-row--cur' : ''}" href="${e(h.href)}">
62
+ <span class="rs-hist-date">${e(h.dateText)}</span>
63
+ <span class="rs-hist-score rs-hist-score--${h.band}">${e(h.scoreText)}</span>
64
+ <span class="rs-hist-meta">${e(h.metaText)}</span>
65
+ <span class="rs-hist-go">${h.current ? (zh ? '当前' : 'current') : '→'}</span>
66
+ </a>`).join('');
67
+ return `<div class="rs-hist-group"><div class="rs-hist-group-h"><span class="rs-hist-group-dot" style="background:${DIM_COLORS[dim]}"></span>${e(dimLabel(dim, lang))} <small>${items.length}</small></div>${rows}</div>`;
68
+ }).join('');
69
+ const modal = `<div id="rs-hist" class="rs-hist-overlay" onclick="if(event.target===this)this.style.display='none'">
70
+ <div class="rs-hist-modal">
71
+ <div class="rs-hist-head"><strong>${e(ctx.skillName)} · ${zh ? '全部历史' : 'All history'}</strong><button type="button" class="rs-hist-x" onclick="document.getElementById('rs-hist').style.display='none'">✕</button></div>
72
+ <div class="rs-hist-list">${groups}</div>
73
+ </div>
74
+ </div>`;
75
+ return bar + modal;
76
+ }
77
+ export function reportShell(opts, lang = DEFAULT_LANG) {
78
+ const accent = DIM_COLORS[opts.dim];
79
+ const zh = lang === 'zh';
80
+ const clr = opts.ringColor ?? (opts.score != null ? scoreColor(opts.score) : '#9ca3af');
81
+ const hero = `<div class="rs-hero rs-hero--${opts.dim}">
82
+ <div class="rs-hero-left">
83
+ <div class="rs-hero-kind"><span class="rs-hero-icon" style="color:${accent}">${icon(dimIconName(opts.dim), { size: 14 }) || e(opts.icon)}</span> ${e(opts.kindTitle)}</div>
84
+ <h1 class="rs-hero-name">${e(opts.skillName)}</h1>
85
+ <div class="rs-hero-meta">${opts.metaItems.map((m) => `<span>${m}</span>`).join('')}</div>
86
+ </div>
87
+ ${opts.score != null ? `<div class="rs-hero-score">
88
+ <div class="rs-hero-num" style="color:${clr}">${e(opts.scoreText ?? String(opts.score))}</div>
89
+ ${opts.scoreLabel ? `<div class="rs-hero-grade" style="color:${clr}">${e(opts.scoreLabel)}</div>` : ''}
90
+ </div>` : ''}
91
+ </div>`;
92
+ // 面包屑 — 替掉孤零零的「← 返回列表」,让导航有上下文(工作台 › 维度 › skill)。
93
+ const crumb = `<nav class="rs-crumb">
94
+ <a class="rs-crumb-link" href="/">${icon('home', { size: 14 })}${zh ? '工作台' : 'Workbench'}</a>
95
+ <span class="rs-crumb-sep">›</span><span class="rs-crumb-dim">${e(dimLabel(opts.dim, lang))}</span>
96
+ <span class="rs-crumb-sep">›</span><span class="rs-crumb-cur">${e(opts.skillName)}</span>
97
+ <span class="rs-crumb-spacer"></span>
98
+ <a class="rs-crumb-back" href="${e(opts.backHref)}">${icon('chevron-left', { size: 14 })}${e(opts.backLabel.replace(/^←\s*/, ''))}</a>
99
+ </nav>`;
100
+ return layout(`${opts.kindTitle} · ${opts.skillName}`, `
101
+ <main>
102
+ ${crumb}
103
+ ${hero}
104
+ ${opts.skillContext ? renderSkillContext(opts.skillContext, lang) : ''}
105
+ ${opts.body}
106
+ </main>
107
+ <style>${REPORT_SHELL_CSS}${opts.extraCss ?? ''}</style>
108
+ `, lang);
109
+ }
110
+ export const REPORT_SHELL_CSS = `
111
+ /* ── 面包屑(替掉裸返回链接) ── */
112
+ .rs-crumb{display:flex;align-items:center;gap:8px;margin-bottom:16px;font-size:13px;color:#637083}
113
+ .rs-crumb-link{display:inline-flex;align-items:center;gap:6px;color:#637083;text-decoration:none}
114
+ .rs-crumb-link:hover{color:#4f46e5;text-decoration:none}
115
+ .rs-crumb-link svg{color:#9ca3af}
116
+ .rs-crumb-link:hover svg{color:#4f46e5}
117
+ .rs-crumb-sep{color:#c0c6d2}
118
+ .rs-crumb-dim{color:#637083}
119
+ .rs-crumb-cur{color:#182033;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
120
+ .rs-crumb-spacer{flex:1}
121
+ .rs-crumb-back{display:inline-flex;align-items:center;gap:5px;color:#9ca3af;text-decoration:none;flex-shrink:0}
122
+ .rs-crumb-back:hover{color:#4f46e5;text-decoration:none}
123
+
124
+ /* ── skill 维度切换器(doctor/eval/observe 互链)— 分段控件风 ── */
125
+ .rs-dims{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:0 0 16px}
126
+ .rs-dims-seg{display:inline-flex;align-items:stretch;background:#fff;border:1px solid #e4e8f1;border-radius:10px;padding:3px;gap:2px;box-shadow:0 1px 2px rgba(31,41,55,3%)}
127
+ .rs-dim{display:inline-flex;align-items:center;gap:7px;font-size:13px;padding:7px 14px;border-radius:7px;color:#637083;text-decoration:none;white-space:nowrap;transition:background .12s,color .12s}
128
+ a.rs-dim:hover{background:#f1f4f9;color:#182033}
129
+ .rs-dim-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}
130
+ .rs-dim-lbl{font-weight:500}
131
+ /* 当前维度:浅填充 + 状态点已表明身份,文字加重 */
132
+ .rs-dim--active{background:#f1f4f9;color:#182033;cursor:default}
133
+ .rs-dim--active .rs-dim-lbl{font-weight:700}
134
+ .rs-dim--empty{color:#b6bcc8;cursor:default}
135
+ /* 全部历史按钮 */
136
+ .rs-hist-btn{display:inline-flex;align-items:center;gap:6px;font-size:13px;padding:7px 13px;border-radius:9px;border:1px solid #e4e8f1;background:#fff;color:#637083;cursor:pointer;white-space:nowrap;font-family:inherit;transition:border-color .15s,color .15s}
137
+ .rs-hist-btn:hover{border-color:#c7cedb;color:#182033}
138
+ .rs-hist-ct{font-variant-numeric:tabular-nums;font-weight:700;color:#9ca3af;font-size:12px}
139
+ /* 全部历史弹框 */
140
+ .rs-hist-overlay{display:none;position:fixed;inset:0;background:rgba(24,32,51,.32);z-index:50;align-items:flex-start;justify-content:center;padding:8vh 16px}
141
+ .rs-hist-modal{background:#fff;border-radius:14px;box-shadow:0 24px 60px rgba(31,41,55,.22);width:100%;max-width:520px;max-height:76vh;display:flex;flex-direction:column;overflow:hidden}
142
+ .rs-hist-head{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid #eef1f6;font-size:14px;color:#182033}
143
+ .rs-hist-x{background:transparent;border:none;color:#9ca3af;font-size:16px;cursor:pointer;line-height:1;padding:4px}
144
+ .rs-hist-x:hover{color:#182033}
145
+ .rs-hist-list{overflow-y:auto;padding:6px 10px 12px}
146
+ .rs-hist-group{margin-top:8px}
147
+ .rs-hist-group-h{display:flex;align-items:center;gap:7px;font-size:12px;color:#637083;font-weight:600;padding:8px 8px 6px}
148
+ .rs-hist-group-dot{width:7px;height:7px;border-radius:50%}
149
+ .rs-hist-group-h small{font-weight:500;color:#b6bcc8}
150
+ .rs-hist-row{display:flex;align-items:baseline;gap:14px;padding:8px;border-radius:8px;text-decoration:none;color:#182033;font-size:13px}
151
+ .rs-hist-row:hover{background:#f1f4f9}
152
+ .rs-hist-row--cur{background:#f1f4f9;cursor:default}
153
+ .rs-hist-date{font-variant-numeric:tabular-nums;color:#637083;min-width:88px;flex-shrink:0}
154
+ .rs-hist-score{font-weight:700;font-variant-numeric:tabular-nums;font-family:"SF Mono",Menlo,monospace;min-width:72px;flex-shrink:0}
155
+ .rs-hist-score--green{color:#1f9d63}.rs-hist-score--yellow{color:#d97706}.rs-hist-score--red{color:#dc2626}.rs-hist-score--gray{color:#9ca3af}
156
+ .rs-hist-meta{flex:1;min-width:0;color:#9ca3af;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
157
+ .rs-hist-go{color:#c0c6d2;font-size:13px;flex-shrink:0}
158
+ .rs-hist-row:hover .rs-hist-go{color:#637083}
159
+ .rs-hist-row--cur .rs-hist-go{color:#4f46e5;font-weight:600;font-size:12px}
160
+
161
+ /* ── Hero ── */
162
+ .rs-hero{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:20px 24px;background:#fff;border:1px solid #e4e8f1;border-radius:12px;box-shadow:0 8px 24px rgba(31,41,55,4%);margin-bottom:16px}
163
+ @media(max-width:640px){.rs-hero{flex-direction:column;align-items:flex-start}}
164
+ .rs-hero-left{display:flex;flex-direction:column;gap:4px;min-width:0}
165
+ .rs-hero-kind{display:flex;align-items:center;gap:6px;font-size:13px;font-weight:600;color:#637083}
166
+ .rs-hero-icon{display:inline-flex;align-items:center}
167
+ .rs-hero-name{margin:0;font-size:20px;font-weight:700;color:#182033;letter-spacing:-.2px}
168
+ .rs-hero-meta{display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:4px;color:#9ca3af;font-size:12px;font-variant-numeric:tabular-nums}
169
+ .rs-hero-meta span{display:inline-flex;align-items:center;gap:4px}
170
+ .rs-hero-score{display:flex;flex-direction:column;align-items:flex-end;gap:2px;flex-shrink:0;line-height:1}
171
+ .rs-hero-num{font-size:40px;font-weight:800;letter-spacing:-1.5px;font-variant-numeric:tabular-nums;line-height:1}
172
+ .rs-hero-grade{font-size:12px;font-weight:600;color:#637083}
173
+
174
+ /* ── 统计条 ── */
175
+ .rs-stats{display:flex;flex-wrap:wrap;gap:20px;padding:14px 20px;background:#fff;border:1px solid #e4e8f1;border-radius:10px;box-shadow:0 8px 24px rgba(31,41,55,4%);margin-bottom:16px}
176
+ .rs-stat{display:flex;align-items:baseline;gap:6px}
177
+ .rs-stat-num{font-size:20px;font-weight:800;font-variant-numeric:tabular-nums;line-height:1}
178
+ .rs-stat-label{font-size:12px;color:#637083}
179
+ .rs-stat--pass .rs-stat-num{color:#1f9d63}
180
+ .rs-stat--warn .rs-stat-num{color:#d97706}
181
+ .rs-stat--fail .rs-stat-num{color:#dc2626}
182
+ .rs-stat--total .rs-stat-num{color:#182033}
183
+
184
+ /* ── Panel(内容区块) ── */
185
+ .rs-panel{background:#fff;border:1px solid #e4e8f1;border-radius:12px;box-shadow:0 8px 24px rgba(31,41,55,4%);padding:18px 20px;margin-bottom:16px}
186
+ .rs-panel-title{display:flex;align-items:center;gap:8px;font-size:15px;font-weight:700;color:#182033;margin-bottom:14px}
187
+ .rs-panel-title small{font-size:12px;font-weight:400;color:#9ca3af;margin-left:4px}
188
+
189
+ /* ── 规则 / 用例:面板内的 hairline 列表项(无 tint 盒子,状态靠左侧色点) ── */
190
+ .rs-card{border-bottom:1px solid #eef1f6;background:transparent;border-radius:8px;transition:background .12s}
191
+ .rs-card:last-child{border-bottom:none}
192
+ details.rs-card:not([open]):hover{background:#f9fafc}
193
+ details.rs-card[open]{background:#fafbfd}
194
+ .rs-card-head{display:flex;align-items:center;gap:10px;padding:12px 6px;cursor:pointer;list-style:none}
195
+ .rs-card-head::-webkit-details-marker{display:none}
196
+ details.rs-card>.rs-card-head::after{content:'›';margin-left:4px;color:#c0c6d2;font-size:16px;transition:transform .15s;flex-shrink:0}
197
+ details.rs-card[open]>.rs-card-head::after{transform:rotate(90deg)}
198
+ .rs-card-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
199
+ .rs-card-dot--fail{background:#dc2626}
200
+ .rs-card-dot--warn{background:#d97706}
201
+ .rs-card-dot--pass{background:#1f9d63}
202
+ .rs-card-dot--skip{background:#cbd2dd}
203
+ .rs-card-name{flex:1;min-width:0;font-size:14px;font-weight:600;color:#182033;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
204
+ .rs-card-badges{display:flex;gap:6px;flex-shrink:0}
205
+ .rs-badge{font-size:11px;font-weight:600;padding:1px 8px;border-radius:10px}
206
+ .rs-badge--fail{color:#dc2626;background:rgba(220,38,38,10%)}
207
+ .rs-badge--warn{color:#d97706;background:rgba(217,119,6,10%)}
208
+ .rs-badge--pass{color:#1f9d63;background:rgba(31,157,99,10%)}
209
+ .rs-card-body{padding:0 6px 14px 24px}
210
+ .rs-finding{margin-top:10px;font-size:13.5px;line-height:1.65}
211
+ .rs-finding-desc{color:#374151;word-break:break-word}
212
+ .rs-finding-sug{margin-top:6px;padding:8px 12px;background:rgba(79,70,229,.05);border-radius:6px;color:#4f46e5;font-size:12.5px;line-height:1.6;word-break:break-word}
213
+
214
+ /* ── 折叠通过项 ── */
215
+ .rs-fold{margin-top:10px}
216
+ .rs-fold>summary{cursor:pointer;list-style:none;font-size:12.5px;color:#637083;padding:6px 0}
217
+ .rs-fold>summary::-webkit-details-marker{display:none}
218
+ .rs-fold>summary:hover{color:#182033}
219
+ .rs-fold[open]>summary{margin-bottom:8px}
220
+
221
+ /* ── 空态 ── */
222
+ .rs-empty{padding:32px 20px;text-align:center;color:#9ca3af;font-size:13px}
223
+ `;