niceeval 0.8.1 → 0.9.1

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 (140) hide show
  1. package/INDEX.md +77 -45
  2. package/dist/agents/types.d.ts +28 -6
  3. package/dist/i18n/en.d.ts +2 -0
  4. package/dist/i18n/zh-CN.d.ts +3 -1
  5. package/dist/report/built-in/index.d.ts +3 -2
  6. package/dist/report/built-in/index.js +7 -8
  7. package/dist/report/built-in/standard.d.ts +1 -0
  8. package/dist/report/built-in/standard.js +30 -0
  9. package/dist/report/components.d.ts +69 -2
  10. package/dist/report/components.js +152 -3
  11. package/dist/report/compute.d.ts +28 -1
  12. package/dist/report/compute.js +123 -0
  13. package/dist/report/index.d.ts +4 -4
  14. package/dist/report/index.js +3 -2
  15. package/dist/report/locale.d.ts +39 -1
  16. package/dist/report/locale.js +69 -0
  17. package/dist/report/react/AttemptList.d.ts +3 -1
  18. package/dist/report/react/AttemptList.js +3 -3
  19. package/dist/report/react/CopyFixPrompt.d.ts +12 -0
  20. package/dist/report/react/CopyFixPrompt.js +12 -0
  21. package/dist/report/react/HeroCard.d.ts +13 -0
  22. package/dist/report/react/HeroCard.js +35 -0
  23. package/dist/report/react/PoweredBy.d.ts +5 -0
  24. package/dist/report/react/PoweredBy.js +7 -0
  25. package/dist/report/react/ScopeWarnings.d.ts +12 -0
  26. package/dist/report/react/ScopeWarnings.js +18 -0
  27. package/dist/report/react/TraceWaterfall.d.ts +14 -0
  28. package/dist/report/react/TraceWaterfall.js +22 -0
  29. package/dist/report/react/index.d.ts +6 -1
  30. package/dist/report/react/index.js +6 -0
  31. package/dist/report/report.d.ts +22 -6
  32. package/dist/report/report.js +68 -55
  33. package/dist/report/scope-warnings.d.ts +28 -0
  34. package/dist/report/scope-warnings.js +101 -0
  35. package/dist/report/text/faces.d.ts +19 -1
  36. package/dist/report/text/faces.js +61 -0
  37. package/dist/report/tree.d.ts +1 -1
  38. package/dist/report/tree.js +7 -2
  39. package/dist/report/types.d.ts +45 -0
  40. package/dist/report/web.d.ts +5 -4
  41. package/dist/report/web.js +7 -22
  42. package/dist/results/select.d.ts +17 -4
  43. package/dist/results/select.js +76 -11
  44. package/dist/results/types.d.ts +26 -0
  45. package/dist/runner/fingerprint.d.ts +3 -3
  46. package/dist/runner/sandbox-selection.d.ts +12 -0
  47. package/dist/runner/types.d.ts +18 -6
  48. package/dist/sandbox/types.d.ts +12 -0
  49. package/dist/shared/aggregate.d.ts +1 -1
  50. package/dist/shared/aggregate.js +1 -1
  51. package/docs-site/zh/explanation/evals.mdx +2 -1
  52. package/docs-site/zh/explanation/experiment.mdx +2 -0
  53. package/docs-site/zh/how-to/custom-reports.mdx +23 -7
  54. package/docs-site/zh/how-to/experiments.mdx +2 -2
  55. package/docs-site/zh/how-to/publish-report.mdx +11 -4
  56. package/docs-site/zh/how-to/viewing-results.mdx +17 -8
  57. package/docs-site/zh/how-to/write-experiment.mdx +40 -1
  58. package/docs-site/zh/reference/builtin-agents.mdx +40 -3
  59. package/docs-site/zh/reference/cli.mdx +3 -3
  60. package/docs-site/zh/reference/define-eval.mdx +8 -0
  61. package/docs-site/zh/reference/official-adapters.mdx +10 -5
  62. package/docs-site/zh/troubleshooting/debugging.mdx +3 -3
  63. package/package.json +2 -1
  64. package/src/agents/bub.ts +13 -1
  65. package/src/agents/claude-code.test.ts +43 -1
  66. package/src/agents/claude-code.ts +32 -14
  67. package/src/agents/codex.test.ts +168 -1
  68. package/src/agents/codex.ts +51 -15
  69. package/src/agents/mcp.ts +31 -0
  70. package/src/agents/post-setup.ts +33 -0
  71. package/src/agents/types.ts +28 -7
  72. package/src/cli.ts +15 -14
  73. package/src/define.ts +3 -0
  74. package/src/i18n/en.ts +8 -5
  75. package/src/i18n/zh-CN.ts +8 -4
  76. package/src/index.ts +1 -0
  77. package/src/report/built-in/index.tsx +8 -7
  78. package/src/report/built-in/standard.tsx +59 -0
  79. package/src/report/components.tsx +218 -2
  80. package/src/report/compute.ts +138 -1
  81. package/src/report/dual-render.test.tsx +141 -14
  82. package/src/report/index.ts +20 -0
  83. package/src/report/locale.ts +83 -1
  84. package/src/report/react/AttemptList.tsx +13 -1
  85. package/src/report/react/CopyFixPrompt.tsx +37 -0
  86. package/src/report/react/HeroCard.tsx +59 -0
  87. package/src/report/react/PoweredBy.tsx +20 -0
  88. package/src/report/react/ScopeWarnings.tsx +74 -0
  89. package/src/report/react/TraceWaterfall.tsx +78 -0
  90. package/src/report/react/enhance.js +14 -0
  91. package/src/report/react/index.tsx +11 -0
  92. package/src/report/react/styles.css +193 -7
  93. package/src/report/report.ts +99 -64
  94. package/src/report/scope-warnings.ts +155 -0
  95. package/src/report/site-components.test.tsx +526 -0
  96. package/src/report/text/faces.ts +66 -0
  97. package/src/report/tree.ts +10 -3
  98. package/src/report/types.ts +51 -0
  99. package/src/report/web.ts +7 -40
  100. package/src/results/host-equivalence.test.ts +6 -2
  101. package/src/results/open.ts +5 -4
  102. package/src/results/results.test.ts +78 -1
  103. package/src/results/select.ts +80 -12
  104. package/src/results/types.ts +27 -0
  105. package/src/runner/attempt.ts +10 -9
  106. package/src/runner/discover.test.ts +9 -1
  107. package/src/runner/discover.ts +3 -3
  108. package/src/runner/fingerprint.ts +9 -4
  109. package/src/runner/ledger.test.ts +30 -1
  110. package/src/runner/ledger.ts +26 -4
  111. package/src/runner/run.ts +5 -1
  112. package/src/runner/sandbox-selection.test.ts +131 -0
  113. package/src/runner/sandbox-selection.ts +110 -0
  114. package/src/runner/types.ts +19 -2
  115. package/src/sandbox/types.ts +6 -0
  116. package/src/shared/aggregate.ts +1 -1
  117. package/src/show/index.ts +19 -12
  118. package/src/show/render.ts +12 -12
  119. package/src/show/report-host.test.ts +34 -17
  120. package/src/show/report-host.ts +6 -5
  121. package/src/show/show.test.ts +141 -4
  122. package/src/view/app/App.test.tsx +79 -17
  123. package/src/view/app/App.tsx +25 -74
  124. package/src/view/app/components/CopyControls.tsx +4 -42
  125. package/src/view/app/i18n.ts +5 -227
  126. package/src/view/app/lib/rows.ts +3 -21
  127. package/src/view/app/shared.ts +1 -3
  128. package/src/view/app/types.ts +2 -2
  129. package/src/view/client-dist/app.css +1 -1
  130. package/src/view/client-dist/app.js +20 -20
  131. package/src/view/data.ts +21 -10
  132. package/src/view/index.ts +2 -12
  133. package/src/view/server.ts +4 -4
  134. package/src/view/shared/types.ts +11 -6
  135. package/src/view/styles.css +9 -252
  136. package/src/view/view-report.test.ts +99 -33
  137. package/src/view/app/components/LazyArtifact.tsx +0 -51
  138. package/src/view/app/components/SkippedRunsBanner.tsx +0 -140
  139. package/src/view/app/pages/AttemptsPage.tsx +0 -80
  140. package/src/view/app/pages/TracesPage.tsx +0 -35
package/src/view/data.ts CHANGED
@@ -20,6 +20,7 @@ import {
20
20
  type HostReportAsset,
21
21
  } from "../show/report-host.ts";
22
22
  import { selectCurrentResults, filterExperiments } from "../results/select.ts";
23
+ import { evalPrefixPredicate } from "../shared/aggregate.ts";
23
24
  import type { EvalResult } from "../types.ts";
24
25
  import type {
25
26
  SkippedRunNotice,
@@ -61,9 +62,9 @@ export interface ViewScan {
61
62
 
62
63
  /** view 宿主输入的组合语义(与 show 对齐,docs/feature/reports/architecture.md「Scope 是计算入口」)。 */
63
64
  export interface ViewScanOptions {
64
- /** eval id 前缀(位置参数):收窄报告槽 Scope;证据室(快照明细)不收窄,深链恒可达。 */
65
+ /** eval id 前缀(位置参数):把根滤成有效根,页面 Scope 与证据(快照明细、artifact 清单)一致收窄。 */
65
66
  patterns?: string[];
66
- /** experiment id 前缀(--experiment):Scope 只留该实验。 */
67
+ /** experiment id 前缀(--exp):有效根只留匹配实验。 */
67
68
  experiment?: string;
68
69
  /** --report 报告文件:相对 cwd 的路径。装载失败抛 ReportLoadError(CLI 打印后退出)。 */
69
70
  report?: { path: string; cwd: string };
@@ -175,10 +176,12 @@ export async function loadLatestResultsPerEval(root = ".niceeval"): Promise<Eval
175
176
  /**
176
177
  * `niceeval view` 的数据装载入口:server 每次请求现读现算,`--out` 导出用同一份。
177
178
  * 报告槽 Selection 恒经 selectCurrentResults 合成(现刻水位;与 `niceeval show` 调同一个
178
- * 函数,裸跑与局部收窄不分叉),位置前缀 / --experiment 只作为 scope 传入,不切换选择口径。
179
+ * 函数,裸跑与局部收窄不分叉),位置前缀 / --exp 只作为 scope 传入,不切换选择口径。
179
180
  * --report 本身不改挑选——它只换报告槽的填充,注入的 Selection 与裸跑同一份,
180
181
  * 「裸跑 ≡ --report <ExperimentComparison>」靠这条成立(docs/feature/reports/architecture.md「Selection 是计算入口」)。
181
- * 证据室数据(快照明细 / skipped)恒为全量,深链在任何收窄下都可达。
182
+ * 命令行收窄作用在有效根上(docs/feature/reports/view.md 开篇):证据室数据与 artifact 清单
183
+ * 与页面一致地只含收窄后的范围,本地与导出无分叉——收窄导出的站点(烘进 HTML 的数据、
184
+ * 证据文件)只含收窄到的内容。收窄之内、不在现刻水位里的历史 attempt 仍在有效根里,深链可达。
182
185
  * 零可读结果一律抛 ViewInputError,不渲染/导出空页面(server 起不来,--out 非零退出)。
183
186
  */
184
187
  export async function loadViewScan(input?: string, opts: ViewScanOptions = {}): Promise<ViewScan> {
@@ -228,6 +231,12 @@ export async function loadViewScan(input?: string, opts: ViewScanOptions = {}):
228
231
  // 静态渲染成 HTML(en / zh-CN 各一遍,切界面语言不重算数据)。
229
232
  const slot = await renderReportSlot(opts.report, opts.page, results, selection, opts.pageFailure ?? "throw");
230
233
 
234
+ // 有效根:命令行收窄把根滤成只含匹配实验与 attempt(docs/feature/reports/view.md 开篇)。
235
+ // 证据室数据与 artifact 清单从这里取数,与页面 Scope 一致收窄——本地与导出无分叉,
236
+ // 收窄导出的站点(烘进 HTML 的数据、证据文件)只含收窄后的范围。
237
+ const scopedExperiments = filterExperiments(results.experiments, opts.experiment);
238
+ const matchEval = patterns.length > 0 ? evalPrefixPredicate(patterns) : () => true;
239
+
231
240
  // 跨快照按身份键去重:--resume 携带的条目在多份落盘里重复,只保留最新快照里的那份
232
241
  // (与官方计算函数的聚合口径一致,Runs / Traces 的计数因此不被复印件灌票)。
233
242
  const artifactDirs = new Map<string, string>();
@@ -236,13 +245,15 @@ export async function loadViewScan(input?: string, opts: ViewScanOptions = {}):
236
245
  // 与报告槽 Selection(现刻水位,可能合成自更早快照)是两个独立概念,不混用。
237
246
  const latestSet = new Set(latestPerExperiment.snapshots);
238
247
  const allAttempts: AttemptHandle[] = [];
239
- for (const exp of results.experiments) {
240
- for (const snap of exp.snapshots) allAttempts.push(...snap.attempts);
248
+ for (const exp of scopedExperiments) {
249
+ for (const snap of exp.snapshots) allAttempts.push(...snap.attempts.filter((a) => matchEval(a.evalId)));
241
250
  }
242
251
  const survivors = new Set(dedupeAttempts(allAttempts).attempts);
243
252
 
244
253
  const snapshots: ViewSnapshot[] = [];
245
- for (const exp of results.experiments) {
254
+ for (const exp of scopedExperiments) {
255
+ // 整个实验没有匹配 eval 时不携带:有效根里没有它,连快照元数据也不烘进页面。
256
+ if (patterns.length > 0 && !exp.evalIds.some((id) => matchEval(id))) continue;
246
257
  for (const snap of exp.snapshots) {
247
258
  const kept = snap.attempts.filter((a) => survivors.has(a));
248
259
  const latest = latestSet.has(snap);
@@ -267,10 +278,10 @@ export async function loadViewScan(input?: string, opts: ViewScanOptions = {}):
267
278
  }
268
279
  }
269
280
 
270
- // 全局最新快照(跨全部实验):hero 的「最近一次运行」时刻从这里取。
271
- // hero 标题不从这里取——它走标题回退链(resolveReportTitle,进 viewData.report.title)。
281
+ // 全局最新快照(跨有效根内全部实验):viewData.lastRunAt 从这里取。页内 hero 的「最后运行」
282
+ // 显示由 Hero 组件按 heroData(scope) 自己算,不吃这份字段。
272
283
  let latestSnapshot: Snapshot | undefined;
273
- for (const exp of results.experiments) {
284
+ for (const exp of scopedExperiments) {
274
285
  const candidate = exp.snapshots[0];
275
286
  if (!candidate) continue;
276
287
  if (!latestSnapshot || candidate.startedAt > latestSnapshot.startedAt) latestSnapshot = candidate;
package/src/view/index.ts CHANGED
@@ -80,18 +80,8 @@ export async function buildView(opts: ViewOptions = {}): Promise<string> {
80
80
  `--out expects a directory, got "${opts.out}". Single-file HTML export was removed: code, transcript and trace views need artifact files next to the page. Export a directory instead (e.g. --out site) and serve it with any static host.`,
81
81
  );
82
82
  }
83
- // --out 与位置参数 / --experiment 互斥(docs/feature/reports/view.md「静态导出」):报告槽收窄
84
- // 只影响报告,证据室恒随根完整——允许同用会让发布者误以为站点只含该实验,实际根里全部
85
- // attempt 的证据都已出站。按实验收窄发布 = 用 copySnapshots 构建只含它的发布根,再对新根导出。
86
- if ((opts.scan?.patterns?.length ?? 0) > 0 || opts.scan?.experiment !== undefined) {
87
- throw new ViewInputError(
88
- "--out exports the whole results root and cannot be combined with eval prefixes or --experiment.\n" +
89
- "To publish a site for one experiment, build a narrower results root and export that:\n" +
90
- ' const results = await openResults(".niceeval");\n' +
91
- ' await copySnapshots(results.latest().filter((s) => s.experimentId.startsWith("<prefix>/")), "<publish-root>");\n' +
92
- "Then: niceeval view --results <publish-root> --out <site>",
93
- );
94
- }
83
+ // 位置参数 / --exp 对导出同义于本地:收窄作用在有效根上,出站的页面数据与证据文件
84
+ // 只含收窄后的范围(docs/feature/reports/view.md「静态导出」:出站的就是收窄到的)。
95
85
  // 静态导出保持「任一页失败整体失败」(pageFailure 缺省 "throw"),不产出半套站点。
96
86
  const plan = await planSite(opts.input, opts.scan);
97
87
  await writeSite(plan, out);
@@ -1,8 +1,8 @@
1
1
  // HTTP server:把站点管线(site.ts 的 planSite)产出的同一份产物挂在 127.0.0.1 上按路径服务。
2
2
  // 这里不携带任何取数或布局知识——查不到清单条目就是 404,与 `--out` 写盘的文件逐字节一致
3
- // (docs/feature/reports/view.md 开篇;奇偶由 site-parity 测试守护)。宿主语义只有三条,全部
4
- // 作用在管线输入端:打开首页整份重建(数据永远是盘上最新)、单页渲染失败折成页内错误块
5
- // (pageFailure: "embed")、报告槽可被位置参数 / --experiment 收窄。
3
+ // (docs/feature/reports/view.md 开篇;奇偶由 site-parity 测试守护)。宿主语义只有两条,全部
4
+ // 作用在管线之外:打开首页整份重建(数据永远是盘上最新)、单页渲染失败折成页内错误块
5
+ // (pageFailure: "embed")。位置参数 / --exp 收窄是管线输入,不是宿主语义——两宿主同义。
6
6
 
7
7
  import { createServer, type Server } from "node:http";
8
8
  import { type ViewScanOptions } from "./data.ts";
@@ -13,7 +13,7 @@ export interface ViewOptions {
13
13
  input?: string;
14
14
  out?: string;
15
15
  port?: number;
16
- /** 报告槽的组合语义(位置前缀 / --experiment / --report),透传给站点管线。 */
16
+ /** 站点管线的组合语义(位置前缀 / --exp 收窄有效根,--report 换报告槽),透传给管线。 */
17
17
  scan?: ViewScanOptions;
18
18
  }
19
19
 
@@ -33,8 +33,9 @@ export interface ViewReportPageMeta {
33
33
  /**
34
34
  * 规范化后的报告外壳声明(docs/feature/reports/library/shell.md):壳(导航 / 页脚)由前端
35
35
  * 渲染,页内容消费 <template> 静态块。title 已走完回退链(def.title → 唯一且相同的快照 name →
36
- * 内置文案「Eval 运行结果 / Eval Results」),落点是首页 hero 与浏览器标题——页头品牌位恒为
37
- * NiceEval 字标,不归 title;scripts / styles 是注入资产,不进 viewData。
36
+ * 内置文案「Eval 运行结果 / Eval Results」),宿主落点只有浏览器 <title>(文档单例);
37
+ * 页内 hero 标题由 Hero 组件消费同一取值链,品牌是组件、宿主页头不渲染任何品牌位。
38
+ * scripts / styles 是注入资产,不进 viewData。
38
39
  * link 的 icon 是内联 SVG 字符串(原样透传、原样内联),不收组件——viewData 就是序列化边界。
39
40
  */
40
41
  export interface ViewReportMeta {
@@ -70,7 +71,11 @@ export interface ViewSnapshot {
70
71
  results: ViewEvalResult[];
71
72
  }
72
73
 
73
- /** 目录扫描里被跳过的 run 在页面顶部的提示条目;三种原因与 niceeval/results 的 skipped 一致。 */
74
+ /**
75
+ * 目录扫描里被跳过的 run 的结构化条目;三种原因与 niceeval/results 的 skipped 一致。
76
+ * 页面上的呈现不走它:不可读快照已形成 `unreadable-snapshot` Scope warning,由报告页内的
77
+ * `ScopeWarnings` 组件显示;这里只随 viewData 携带原始事实。
78
+ */
74
79
  export interface SkippedRunNotice {
75
80
  /** run 目录,相对 cwd。 */
76
81
  dir: string;
@@ -92,11 +97,11 @@ export interface SkippedRunNotice {
92
97
  export interface ViewData {
93
98
  /** 最近一次 run 的 startedAt(ISO);没有历史 run 时缺省。 */
94
99
  lastRunAt?: string;
95
- /** 报告槽 Selection 合成自几个物理 run;hero「合成来源」标注。 */
100
+ /** 报告槽 Selection 合成自几个物理 run */
96
101
  composedRuns: number;
97
- /** 全部历史快照(跨快照按身份键去重后);修复 prompt latest,Attempts / Traces 吃全部。 */
102
+ /** 全部历史快照(跨快照按身份键去重后);attempt 详情路由对这份完整集合解析,不随报告 Scope 收窄。 */
98
103
  snapshots: ViewSnapshot[];
99
- /** 读不了的落盘(三种原因);前端顶部横幅展示,不静默。 */
104
+ /** 读不了的落盘(三种原因);呈现走报告页内的 ScopeWarnings(unreadable-snapshot warning)。 */
100
105
  skippedRuns?: SkippedRunNotice[];
101
106
  /** 报告外壳与页导航的声明(规范化后);缺省时前端按单页 `report` 兜底。 */
102
107
  report?: ViewReportMeta;
@@ -63,8 +63,8 @@ a { color: inherit; }
63
63
  align-items: center;
64
64
  justify-content: space-between;
65
65
  /* space-between 只在有富余空间时才撑开相邻项;.shell-links 的 margin-left:auto 会把富余
66
- 空间全部吸收到它左侧,导致品牌与导航贴脸、shell-links 与语言切换贴脸。显式 gap 保证
67
- 每一对相邻项(品牌—导航、shell-links—语言切换)恒有最小间距,不依赖富余空间。 */
66
+ 空间全部吸收到它左侧,导致相邻项贴脸。显式 gap 保证每一对相邻项(导航—shell-links
67
+ shell-links—语言切换)恒有最小间距,不依赖富余空间。 */
68
68
  gap: 28px;
69
69
  padding: 0 clamp(20px, 5vw, 80px);
70
70
  background: color-mix(in oklch, var(--bg), transparent 4%);
@@ -73,12 +73,16 @@ a { color: inherit; }
73
73
  z-index: 10;
74
74
  backdrop-filter: blur(10px);
75
75
  }
76
+ /* 页头左端的恒定品牌位:NiceEval 字标 + 45° 方块 mark,外链官网(App.tsx 的 .brand)。
77
+ 与 hero 下 nre-powered-by 品牌行同族,由宿主渲染、报告定义不能覆盖或移除。 */
76
78
  .brand {
77
79
  display: flex;
78
80
  align-items: baseline;
79
81
  gap: 12px;
80
82
  font-weight: 690;
81
83
  font-size: 20px;
84
+ flex: 0 0 auto;
85
+ text-decoration: none;
82
86
  }
83
87
  .mark {
84
88
  width: 18px;
@@ -121,219 +125,13 @@ main {
121
125
  margin: 0 auto;
122
126
  padding: clamp(52px, 7vw, 82px) 0 72px;
123
127
  }
124
- .hero {
125
- text-align: center;
126
- max-width: 740px;
127
- margin: 0 auto clamp(38px, 6vw, 58px);
128
- }
129
- h1 {
130
- margin: 0;
131
- font-size: clamp(42px, 5.6vw, 66px);
132
- line-height: 0.94;
133
- font-weight: 760;
134
- letter-spacing: 0;
135
- }
136
- .subtitle {
137
- margin: 20px auto 0;
138
- color: color-mix(in oklch, var(--muted), var(--text) 12%);
139
- font-size: clamp(17px, 2vw, 21px);
140
- line-height: 1.58;
141
- max-width: 660px;
142
- }
143
- .meta {
144
- display: flex;
145
- flex-wrap: wrap;
146
- justify-content: center;
147
- gap: 14px;
148
- margin-top: 24px;
149
- color: var(--muted);
150
- font-size: 14px;
151
- }
152
- .meta b { color: var(--text); font-weight: 570; }
153
- /* --report 报告槽:server 侧渲染好的静态报告 HTML(nre-* 类的样式随包 styles.css 注入),
154
- 这里只给槽位留呼吸空间,不覆盖报告自己的样式。 */
128
+ /* 报告槽:server 侧渲染好的静态报告 HTML(nre-* 类的样式随包 styles.css 注入),
129
+ 这里只给槽位留呼吸空间,不覆盖报告自己的样式。hero、警告区、批量修复 prompt 都是
130
+ 页内组件(nre-hero / nre-warnings / nre-copy-fix-prompt),宿主不再有对应 chrome。 */
155
131
  .report-slot {
156
132
  margin: 0 auto 36px;
157
133
  }
158
- /* schemaVersion 不匹配等读不了的 run:报告槽不解析它们,这里占位提示。同一原因(且文案
159
- 完全相同)的条目按 SkippedRunsBanner 分组折叠,不逐条重复整句原因 + 命令——那是原实现
160
- 把首屏挤满、警示色又淡到看不出来的根因。 */
161
- .incompatible-banner {
162
- border: 1px solid color-mix(in oklch, var(--warn), var(--line) 35%);
163
- border-left: 3px solid var(--warn);
164
- border-radius: 8px;
165
- background: color-mix(in oklch, var(--warn), var(--panel) 85%);
166
- padding: 12px 16px 14px;
167
- margin: 0 auto 36px;
168
- font-size: 13px;
169
- }
170
- .ib-head {
171
- display: flex;
172
- align-items: center;
173
- gap: 8px;
174
- }
175
- .ib-head b { font-weight: 640; }
176
- .ib-icon {
177
- width: 16px;
178
- height: 16px;
179
- flex-shrink: 0;
180
- color: var(--warn);
181
- stroke-width: 2;
182
- }
183
- .ib-groups {
184
- display: grid;
185
- gap: 10px;
186
- margin-top: 10px;
187
- }
188
- .ib-group-head {
189
- display: flex;
190
- align-items: baseline;
191
- gap: 8px;
192
- }
193
- .ib-group-count {
194
- display: inline-flex;
195
- align-items: center;
196
- justify-content: center;
197
- min-width: 20px;
198
- height: 20px;
199
- padding: 0 6px;
200
- flex-shrink: 0;
201
- border-radius: 999px;
202
- background: color-mix(in oklch, var(--warn), var(--panel) 72%);
203
- color: var(--text);
204
- font-size: 11px;
205
- font-weight: 640;
206
- font-variant-numeric: tabular-nums;
207
- }
208
- .ib-group-desc { color: var(--soft); }
209
- .ib-group ul {
210
- margin: 5px 0 0;
211
- padding: 0;
212
- list-style: none;
213
- display: grid;
214
- gap: 3px;
215
- }
216
- .ib-group li {
217
- display: flex;
218
- align-items: center;
219
- gap: 8px;
220
- min-height: 22px;
221
- }
222
- .ib-dir {
223
- font-family: var(--mono, ui-monospace, monospace);
224
- font-weight: 560;
225
- }
226
- .ib-more {
227
- color: var(--soft);
228
- font-size: 12px;
229
- }
230
- .ib-copy {
231
- display: inline-flex;
232
- align-items: center;
233
- justify-content: center;
234
- width: 22px;
235
- height: 22px;
236
- flex-shrink: 0;
237
- border: 1px solid var(--line);
238
- border-radius: 5px;
239
- background: var(--panel);
240
- color: var(--muted);
241
- cursor: pointer;
242
- transition: color 0.12s, border-color 0.12s;
243
- }
244
- .ib-copy svg { width: 12px; height: 12px; stroke: currentColor; fill: none; stroke-width: 2; }
245
- .ib-copy:hover { color: var(--text); border-color: var(--line-strong); }
246
- .ib-copy.is-copied { color: var(--good); border-color: color-mix(in oklch, var(--good), var(--line) 40%); }
247
- .ib-toggle {
248
- display: inline-flex;
249
- align-items: center;
250
- gap: 4px;
251
- margin-top: 10px;
252
- border: 0;
253
- background: none;
254
- color: var(--muted);
255
- font: inherit;
256
- font-size: 12px;
257
- cursor: pointer;
258
- padding: 0;
259
- }
260
- .ib-toggle svg { width: 12px; height: 12px; transition: transform 0.12s; }
261
- .ib-toggle svg.is-open { transform: rotate(90deg); }
262
- .ib-toggle:hover { color: var(--text); }
263
-
264
- .section-head {
265
- display: flex;
266
- align-items: end;
267
- justify-content: space-between;
268
- gap: 18px;
269
- margin-bottom: 16px;
270
- }
271
- h2 {
272
- margin: 0;
273
- font-size: clamp(24px, 2.6vw, 31px);
274
- line-height: 1.1;
275
- font-weight: 720;
276
- }
277
- .controls {
278
- display: flex;
279
- gap: 8px;
280
- align-items: center;
281
- flex-wrap: wrap;
282
- }
283
- .search {
284
- height: 36px;
285
- min-width: 320px;
286
- border: 1px solid var(--line);
287
- border-radius: 7px;
288
- padding: 0 12px;
289
- background: var(--panel);
290
- color: var(--text);
291
- outline: none;
292
- }
293
- .search:focus { border-color: var(--focus); }
294
- .table-wrap {
295
- border: 1px solid var(--line);
296
- border-radius: 8px;
297
- overflow: auto;
298
- background: var(--panel);
299
- }
300
- table {
301
- width: 100%;
302
- border-collapse: collapse;
303
- min-width: 1040px;
304
- }
305
- th, td {
306
- border-bottom: 1px solid var(--line);
307
- padding: 0 16px;
308
- height: 52px;
309
- text-align: left;
310
- vertical-align: middle;
311
- font-size: 14px;
312
- }
313
- th {
314
- color: var(--muted);
315
- font-weight: 500;
316
- background: var(--panel);
317
- position: sticky;
318
- top: 0;
319
- z-index: 2;
320
- }
321
- tbody tr:last-child td { border-bottom: 0; }
322
- .section-sub-head {
323
- display: flex;
324
- align-items: center;
325
- justify-content: space-between;
326
- gap: 18px;
327
- margin-bottom: 16px;
328
- min-height: 36px;
329
- }
330
- .group-detail-label {
331
- font-size: 15px;
332
- font-weight: 680;
333
- color: var(--text);
334
- }
335
134
  .name { font-weight: 610; }
336
- .sub { color: var(--muted); font-size: 12px; margin-top: 3px; }
337
135
  .num {
338
136
  font-variant-numeric: tabular-nums;
339
137
  white-space: nowrap;
@@ -343,12 +141,6 @@ tbody tr:last-child td { border-bottom: 0; }
343
141
  .bad { color: var(--bad); }
344
142
  .warn { color: var(--warn); }
345
143
  .infra-err { color: var(--warn); }
346
- .eval-id {
347
- display: flex;
348
- align-items: center;
349
- overflow-wrap: anywhere;
350
- font-weight: 560;
351
- }
352
144
  .copy-all-errors {
353
145
  height: 36px;
354
146
  display: inline-flex;
@@ -702,41 +494,10 @@ pre {
702
494
  font-size: 12px;
703
495
  line-height: 1.5;
704
496
  }
705
- .empty {
706
- border: 1px dashed var(--line-strong);
707
- border-radius: 8px;
708
- padding: 40px 24px;
709
- color: var(--muted);
710
- text-align: center;
711
- background: var(--panel);
712
- }
713
- a.brand { text-decoration: none; color: inherit; }
714
- a.brand:hover { opacity: 0.75; }
715
- .traces-entry {
716
- border: 1px solid var(--line);
717
- border-radius: 8px;
718
- background: var(--panel);
719
- margin-bottom: 12px;
720
- padding: 14px 18px;
721
- }
722
- .traces-entry-head {
723
- display: flex;
724
- align-items: baseline;
725
- gap: 12px;
726
- margin-bottom: 8px;
727
- font-size: 13px;
728
- }
729
- .traces-verdict { font-weight: 600; min-width: 52px; }
730
- .traces-exp { color: var(--muted); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
731
- .traces-dur { color: var(--soft); }
732
497
  @media (max-width: 760px) {
733
498
  .topbar { padding: 0 20px; }
734
499
  .lang-switch button { min-width: 40px; }
735
500
  main { width: min(100vw - 28px, 1120px); padding-top: 42px; }
736
- .hero { text-align: left; margin-left: 0; }
737
- .meta { justify-content: flex-start; }
738
- .section-head { align-items: stretch; flex-direction: column; }
739
- .search { width: 100%; min-width: 0; }
740
501
  .detail { padding: 18px 16px 20px; }
741
502
  .config-strip { gap: 6px; }
742
503
  .detail-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 10px; }
@@ -1194,8 +955,4 @@ li.tnode-row::before { content: ""; width: 4px; flex-shrink: 0; }
1194
955
  color: var(--soft);
1195
956
  font-size: 12px;
1196
957
  }
1197
- /* 品牌行:hero 之下、品牌蓝,恒带官网链接(shell.md「行为约束」)。 */
1198
- .hero .powered-by { display: block; margin-top: 16px; font-size: 12px; }
1199
- .hero .powered-by a { color: var(--blue); text-decoration: none; }
1200
- .hero .powered-by a:hover { text-decoration: underline; }
1201
958
  .nre-page-error pre { white-space: pre-wrap; }