niceeval 0.9.0 → 0.10.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 (428) hide show
  1. package/INDEX.md +31 -33
  2. package/dist/agents/types.d.ts +20 -17
  3. package/dist/context/types.d.ts +21 -21
  4. package/dist/i18n/en.d.ts +10 -2
  5. package/dist/i18n/zh-CN.d.ts +15 -7
  6. package/dist/o11y/execution-tree.d.ts +103 -0
  7. package/dist/o11y/otlp/select.d.ts +22 -0
  8. package/dist/report/{react → assets}/colors.d.ts +8 -0
  9. package/dist/report/{react → assets}/colors.js +23 -0
  10. package/dist/report/built-in/index.d.ts +2 -2
  11. package/dist/report/built-in/index.js +2 -2
  12. package/dist/report/built-in/standard.d.ts +8 -1
  13. package/dist/report/built-in/standard.js +17 -7
  14. package/dist/report/components/attempt-detail/AttemptAssertions.d.ts +6 -0
  15. package/dist/report/components/attempt-detail/AttemptAssertions.js +17 -0
  16. package/dist/report/components/attempt-detail/AttemptConversation.d.ts +6 -0
  17. package/dist/report/components/attempt-detail/AttemptConversation.js +34 -0
  18. package/dist/report/components/attempt-detail/AttemptDiagnostics.d.ts +6 -0
  19. package/dist/report/components/attempt-detail/AttemptDiagnostics.js +7 -0
  20. package/dist/report/components/attempt-detail/AttemptDiff.d.ts +6 -0
  21. package/dist/report/components/attempt-detail/AttemptDiff.js +11 -0
  22. package/dist/report/components/attempt-detail/AttemptError.d.ts +6 -0
  23. package/dist/report/components/attempt-detail/AttemptError.js +16 -0
  24. package/dist/report/components/attempt-detail/AttemptFixPrompt.d.ts +6 -0
  25. package/dist/report/components/attempt-detail/AttemptFixPrompt.js +7 -0
  26. package/dist/report/components/attempt-detail/AttemptSource.d.ts +6 -0
  27. package/dist/report/components/attempt-detail/AttemptSource.js +27 -0
  28. package/dist/report/components/attempt-detail/AttemptSummary.d.ts +8 -0
  29. package/dist/report/components/attempt-detail/AttemptSummary.js +20 -0
  30. package/dist/report/components/attempt-detail/AttemptTimeline.d.ts +6 -0
  31. package/dist/report/components/attempt-detail/AttemptTimeline.js +28 -0
  32. package/dist/report/components/attempt-detail/AttemptTrace.d.ts +6 -0
  33. package/dist/report/components/attempt-detail/AttemptTrace.js +29 -0
  34. package/dist/report/components/attempt-detail/AttemptUsage.d.ts +6 -0
  35. package/dist/report/components/attempt-detail/AttemptUsage.js +20 -0
  36. package/dist/report/components/attempt-detail/compute.d.ts +24 -0
  37. package/dist/report/components/attempt-detail/compute.js +254 -0
  38. package/dist/report/components/attempt-detail/faces.d.ts +14 -0
  39. package/dist/report/components/attempt-detail/faces.js +235 -0
  40. package/dist/report/components/attempt-detail/index.d.ts +38 -0
  41. package/dist/report/components/attempt-detail/index.js +527 -0
  42. package/dist/report/{react → components}/cell.d.ts +5 -3
  43. package/dist/report/{react → components}/cell.js +3 -3
  44. package/dist/report/{react → components/entity-lists}/AttemptList.d.ts +8 -4
  45. package/dist/report/{react → components/entity-lists}/AttemptList.js +16 -10
  46. package/dist/report/{react → components/entity-lists}/EvalList.d.ts +3 -3
  47. package/dist/report/{react → components/entity-lists}/EvalList.js +0 -0
  48. package/dist/report/{react → components/entity-lists}/ExperimentList.d.ts +3 -3
  49. package/dist/report/{react → components/entity-lists}/ExperimentList.js +10 -10
  50. package/dist/report/components/entity-lists/compute.d.ts +23 -0
  51. package/dist/report/components/entity-lists/compute.js +171 -0
  52. package/dist/report/components/entity-lists/faces.d.ts +5 -0
  53. package/dist/report/components/entity-lists/faces.js +174 -0
  54. package/dist/report/components/entity-lists/index.d.ts +51 -0
  55. package/dist/report/components/entity-lists/index.js +165 -0
  56. package/dist/report/{react → components}/fixtures.d.ts +2 -2
  57. package/dist/report/{react → components}/fixtures.js +1 -1
  58. package/dist/report/{react → components/metric-views}/DeltaTable.d.ts +2 -2
  59. package/dist/report/{react → components/metric-views}/DeltaTable.js +4 -4
  60. package/dist/report/{react → components/metric-views}/MetricBars.d.ts +3 -3
  61. package/dist/report/{react → components/metric-views}/MetricBars.js +3 -3
  62. package/dist/report/{react → components/metric-views}/MetricLine.d.ts +2 -2
  63. package/dist/report/{react → components/metric-views}/MetricLine.js +8 -5
  64. package/dist/report/{react → components/metric-views}/MetricMatrix.d.ts +3 -3
  65. package/dist/report/{react → components/metric-views}/MetricMatrix.js +4 -4
  66. package/dist/report/components/metric-views/MetricScatter.d.ts +11 -0
  67. package/dist/report/{react → components/metric-views}/MetricScatter.js +26 -23
  68. package/dist/report/{react → components/metric-views}/MetricTable.d.ts +3 -3
  69. package/dist/report/{react → components/metric-views}/MetricTable.js +4 -4
  70. package/dist/report/{react → components/metric-views}/Scoreboard.d.ts +2 -2
  71. package/dist/report/{react → components/metric-views}/Scoreboard.js +3 -3
  72. package/dist/report/components/metric-views/compute.d.ts +89 -0
  73. package/dist/report/{compute.js → components/metric-views/compute.js} +32 -415
  74. package/dist/report/components/metric-views/faces.d.ts +13 -0
  75. package/dist/report/components/metric-views/faces.js +381 -0
  76. package/dist/report/components/metric-views/index.d.ts +50 -0
  77. package/dist/report/components/metric-views/index.js +273 -0
  78. package/dist/report/{text → components/metric-views}/plot.js +1 -1
  79. package/dist/report/components/shared-compute.d.ts +22 -0
  80. package/dist/report/components/shared-compute.js +47 -0
  81. package/dist/report/components/shared-faces.d.ts +9 -0
  82. package/dist/report/components/shared-faces.js +26 -0
  83. package/dist/report/components/shared.d.ts +68 -0
  84. package/dist/report/components/shared.js +125 -0
  85. package/dist/report/{react → components/site-components}/CopyFixPrompt.d.ts +2 -2
  86. package/dist/report/{react → components/site-components}/CopyFixPrompt.js +2 -2
  87. package/dist/report/{react → components/site-components}/HeroCard.d.ts +2 -2
  88. package/dist/report/{react → components/site-components}/HeroCard.js +2 -2
  89. package/dist/report/{react → components/site-components}/ScopeWarnings.d.ts +2 -2
  90. package/dist/report/{react → components/site-components}/ScopeWarnings.js +3 -3
  91. package/dist/report/{react → components/site-components}/TraceWaterfall.d.ts +3 -3
  92. package/dist/report/{react → components/site-components}/TraceWaterfall.js +5 -5
  93. package/dist/report/components/site-components/compute.d.ts +28 -0
  94. package/dist/report/components/site-components/compute.js +132 -0
  95. package/dist/report/components/site-components/faces.d.ts +21 -0
  96. package/dist/report/components/site-components/faces.js +75 -0
  97. package/dist/report/components/site-components/index.d.ts +74 -0
  98. package/dist/report/components/site-components/index.js +220 -0
  99. package/dist/report/{scope-warnings.d.ts → components/site-components/scope-warnings.d.ts} +2 -2
  100. package/dist/report/{scope-warnings.js → components/site-components/scope-warnings.js} +2 -2
  101. package/dist/report/{react → components/summaries}/ScopeSummary.d.ts +2 -2
  102. package/dist/report/{react → components/summaries}/ScopeSummary.js +17 -8
  103. package/dist/report/components/summaries/compute.d.ts +7 -0
  104. package/dist/report/components/summaries/compute.js +51 -0
  105. package/dist/report/components/summaries/faces.d.ts +7 -0
  106. package/dist/report/components/summaries/faces.js +38 -0
  107. package/dist/report/components/summaries/index.d.ts +27 -0
  108. package/dist/report/components/summaries/index.js +78 -0
  109. package/dist/report/definition/grid-layout.d.ts +50 -0
  110. package/dist/report/definition/grid-layout.js +89 -0
  111. package/dist/report/{primitives.d.ts → definition/primitives.d.ts} +34 -4
  112. package/dist/report/{primitives.js → definition/primitives.js} +101 -10
  113. package/dist/report/{report.d.ts → definition/report.d.ts} +36 -65
  114. package/dist/report/{report.js → definition/report.js} +58 -90
  115. package/dist/report/{text/table.d.ts → definition/table-text.d.ts} +2 -2
  116. package/dist/report/{text/table.js → definition/table-text.js} +2 -2
  117. package/dist/report/{tree.d.ts → definition/tree.d.ts} +44 -12
  118. package/dist/report/{tree.js → definition/tree.js} +10 -12
  119. package/dist/report/index.d.ts +33 -18
  120. package/dist/report/index.js +23 -14
  121. package/dist/report/{aggregate.d.ts → model/aggregate.d.ts} +12 -4
  122. package/dist/report/{aggregate.js → model/aggregate.js} +28 -8
  123. package/dist/report/{flag.d.ts → model/flag.d.ts} +14 -1
  124. package/dist/report/{flag.js → model/flag.js} +35 -0
  125. package/dist/report/{format.d.ts → model/format.d.ts} +11 -5
  126. package/dist/report/{format.js → model/format.js} +48 -4
  127. package/dist/report/{locale.d.ts → model/locale.d.ts} +17 -17
  128. package/dist/report/{locale.js → model/locale.js} +31 -33
  129. package/dist/report/{metrics.d.ts → model/metrics.d.ts} +2 -2
  130. package/dist/report/{metrics.js → model/metrics.js} +2 -2
  131. package/dist/report/{types.d.ts → model/types.d.ts} +140 -20
  132. package/dist/report/react/index.d.ts +32 -21
  133. package/dist/report/react/index.js +33 -21
  134. package/dist/report/{load.d.ts → runtime/load.d.ts} +1 -1
  135. package/dist/report/{load.js → runtime/load.js} +1 -1
  136. package/dist/report/runtime/text.d.ts +67 -0
  137. package/dist/report/runtime/text.js +114 -0
  138. package/dist/report/runtime/web.d.ts +35 -0
  139. package/dist/report/runtime/web.js +70 -0
  140. package/dist/results/annotated-source.d.ts +87 -0
  141. package/dist/results/attempt-evidence.d.ts +74 -0
  142. package/dist/results/attempt-source.d.ts +15 -0
  143. package/dist/results/select.d.ts +12 -2
  144. package/dist/results/select.js +27 -5
  145. package/dist/runner/eval-selection.d.ts +26 -0
  146. package/dist/runner/feedback/sink.d.ts +26 -1
  147. package/dist/runner/types.d.ts +149 -23
  148. package/dist/sandbox/docker.d.ts +6 -0
  149. package/dist/sandbox/types.d.ts +23 -21
  150. package/dist/scoring/display.d.ts +7 -2
  151. package/dist/scoring/display.js +42 -4
  152. package/dist/scoring/types.d.ts +3 -3
  153. package/dist/shared/aggregate.d.ts +15 -1
  154. package/dist/shared/aggregate.js +32 -1
  155. package/dist/shared/types.d.ts +6 -1
  156. package/docs-site/images/logo-dark.svg +7 -0
  157. package/docs-site/images/logo.svg +6 -5
  158. package/docs-site/zh/README.md +8 -7
  159. package/docs-site/zh/examples/ai-agent-application.mdx +5 -5
  160. package/docs-site/zh/examples/coding-agent-extensions.mdx +4 -4
  161. package/docs-site/zh/examples/index.mdx +3 -3
  162. package/docs-site/zh/examples/integrations/ai-sdk-v7.mdx +1 -1
  163. package/docs-site/zh/examples/integrations/claude-sdk.mdx +3 -3
  164. package/docs-site/zh/examples/integrations/codex-sdk.mdx +3 -3
  165. package/docs-site/zh/examples/integrations/langgraph.mdx +3 -3
  166. package/docs-site/zh/examples/integrations/pi-sdk.mdx +2 -2
  167. package/docs-site/zh/explanation/adapter.mdx +19 -19
  168. package/docs-site/zh/explanation/assert.mdx +9 -9
  169. package/docs-site/zh/explanation/drive.mdx +4 -4
  170. package/docs-site/zh/explanation/evals.mdx +8 -8
  171. package/docs-site/zh/explanation/experiment.mdx +8 -8
  172. package/docs-site/zh/explanation/hitl.mdx +13 -13
  173. package/docs-site/zh/explanation/judge.mdx +3 -3
  174. package/docs-site/zh/explanation/overview.mdx +7 -7
  175. package/docs-site/zh/explanation/runner.mdx +11 -11
  176. package/docs-site/zh/explanation/tier.mdx +6 -6
  177. package/docs-site/zh/index.mdx +14 -14
  178. package/docs-site/zh/introduction.mdx +13 -16
  179. package/docs-site/zh/reference/builtin-agents.mdx +61 -28
  180. package/docs-site/zh/reference/capabilities.mdx +7 -27
  181. package/docs-site/zh/reference/cli.mdx +35 -32
  182. package/docs-site/zh/reference/define-agent.mdx +32 -31
  183. package/docs-site/zh/reference/define-config.mdx +6 -6
  184. package/docs-site/zh/reference/define-eval.mdx +33 -20
  185. package/docs-site/zh/reference/events.mdx +4 -4
  186. package/docs-site/zh/reference/expect.mdx +3 -3
  187. package/docs-site/zh/reference/official-adapters.mdx +17 -17
  188. package/docs-site/zh/reference/report-components.mdx +193 -121
  189. package/docs-site/zh/reference/results-data.mdx +13 -13
  190. package/docs-site/zh/troubleshooting/debug-sandbox.mdx +11 -11
  191. package/docs-site/zh/troubleshooting/debugging.mdx +43 -19
  192. package/docs-site/zh/{how-to → tutorials}/agent-feedback-loop.mdx +38 -38
  193. package/docs-site/zh/tutorials/agent-onboarding.mdx +100 -0
  194. package/docs-site/zh/tutorials/authoring.mdx +211 -0
  195. package/docs-site/zh/{how-to → tutorials}/ci-integration.mdx +8 -8
  196. package/docs-site/zh/{how-to → tutorials}/connect-otel.mdx +22 -22
  197. package/docs-site/zh/{how-to → tutorials}/connect-your-agent.mdx +58 -63
  198. package/docs-site/zh/tutorials/custom-reports.mdx +453 -0
  199. package/docs-site/zh/{how-to → tutorials}/dataset-fanout.mdx +4 -4
  200. package/docs-site/zh/tutorials/experiments.mdx +103 -0
  201. package/docs-site/zh/{how-to → tutorials}/fixtures.mdx +9 -9
  202. package/docs-site/zh/{how-to → tutorials}/publish-report.mdx +11 -5
  203. package/docs-site/zh/tutorials/quickstart.mdx +18 -18
  204. package/docs-site/zh/{how-to → tutorials}/reporters.mdx +6 -6
  205. package/docs-site/zh/{how-to → tutorials}/sandbox-agent.mdx +6 -6
  206. package/docs-site/zh/{how-to → tutorials}/sandbox-providers.mdx +41 -19
  207. package/docs-site/zh/{how-to → tutorials}/scoring-guide.mdx +4 -4
  208. package/docs-site/zh/{how-to → tutorials}/viewing-results.mdx +59 -50
  209. package/docs-site/zh/tutorials/write-experiment.mdx +355 -0
  210. package/docs-site/zh/{how-to → tutorials}/write-send.mdx +40 -40
  211. package/package.json +8 -4
  212. package/src/agents/bub.ts +21 -8
  213. package/src/agents/claude-code.ts +23 -10
  214. package/src/agents/codex.test.ts +22 -7
  215. package/src/agents/codex.ts +22 -9
  216. package/src/agents/index.ts +2 -2
  217. package/src/agents/openai-compat.ts +1 -1
  218. package/src/agents/post-setup.ts +45 -22
  219. package/src/agents/streaming.ts +1 -1
  220. package/src/agents/types.ts +20 -17
  221. package/src/agents/ui-message-stream.test.ts +10 -0
  222. package/src/agents/ui-message-stream.ts +12 -1
  223. package/src/cli.ts +77 -64
  224. package/src/context/types.ts +21 -21
  225. package/src/define.ts +13 -0
  226. package/src/i18n/en.ts +30 -15
  227. package/src/i18n/zh-CN.ts +30 -15
  228. package/src/index.ts +2 -0
  229. package/src/report/{react → assets}/colors.ts +22 -0
  230. package/src/report/{react → assets}/enhance.js +1 -33
  231. package/src/report/{react → assets}/styles.css +136 -112
  232. package/src/report/built-in/index.tsx +2 -2
  233. package/src/report/built-in/standard.tsx +18 -6
  234. package/src/report/components/attempt-detail/AttemptAssertions.tsx +67 -0
  235. package/src/report/components/attempt-detail/AttemptConversation.tsx +110 -0
  236. package/src/report/components/attempt-detail/AttemptDiagnostics.tsx +38 -0
  237. package/src/report/components/attempt-detail/AttemptDiff.tsx +35 -0
  238. package/src/report/components/attempt-detail/AttemptError.tsx +31 -0
  239. package/src/report/components/attempt-detail/AttemptFixPrompt.tsx +26 -0
  240. package/src/report/components/attempt-detail/AttemptSource.tsx +80 -0
  241. package/src/report/components/attempt-detail/AttemptSummary.tsx +74 -0
  242. package/src/report/components/attempt-detail/AttemptTimeline.tsx +108 -0
  243. package/src/report/components/attempt-detail/AttemptTrace.tsx +63 -0
  244. package/src/report/components/attempt-detail/AttemptUsage.tsx +29 -0
  245. package/src/report/components/attempt-detail/attempt-components.test.tsx +680 -0
  246. package/src/report/components/attempt-detail/compute.ts +287 -0
  247. package/src/report/components/attempt-detail/faces.ts +257 -0
  248. package/src/report/components/attempt-detail/index.tsx +583 -0
  249. package/src/report/components/attempt-detail/validate.test.ts +235 -0
  250. package/src/report/{react → components}/cell.tsx +6 -3
  251. package/src/report/{report.test.ts → components/compute.test.ts} +316 -46
  252. package/src/report/{react → components/entity-lists}/AttemptList.tsx +24 -16
  253. package/src/report/{react → components/entity-lists}/EvalList.tsx +0 -0
  254. package/src/report/{react → components/entity-lists}/ExperimentList.tsx +23 -20
  255. package/src/report/components/entity-lists/compute.ts +196 -0
  256. package/src/report/components/entity-lists/faces.ts +207 -0
  257. package/src/report/components/entity-lists/index.tsx +241 -0
  258. package/src/report/components/entity-lists/validate.test.ts +114 -0
  259. package/src/report/{react → components}/fixtures.ts +2 -2
  260. package/src/report/{react → components/metric-views}/DeltaTable.tsx +5 -5
  261. package/src/report/{react → components/metric-views}/MetricBars.tsx +5 -5
  262. package/src/report/{react → components/metric-views}/MetricLine.tsx +9 -6
  263. package/src/report/{react → components/metric-views}/MetricMatrix.tsx +6 -6
  264. package/src/report/{react → components/metric-views}/MetricScatter.tsx +41 -33
  265. package/src/report/{react → components/metric-views}/MetricTable.tsx +6 -6
  266. package/src/report/{react → components/metric-views}/Scoreboard.tsx +4 -4
  267. package/src/report/{compute.ts → components/metric-views/compute.ts} +51 -477
  268. package/src/report/components/metric-views/faces.ts +423 -0
  269. package/src/report/components/metric-views/index.tsx +352 -0
  270. package/src/report/{text → components/metric-views}/plot.ts +1 -1
  271. package/src/report/components/metric-views/validate.test.ts +211 -0
  272. package/src/report/{react → components}/render.test.tsx +47 -17
  273. package/src/report/components/shared-compute.ts +59 -0
  274. package/src/report/components/shared-faces.ts +30 -0
  275. package/src/report/components/shared.ts +192 -0
  276. package/src/report/{react → components/site-components}/CopyFixPrompt.tsx +3 -3
  277. package/src/report/{react → components/site-components}/HeroCard.tsx +3 -3
  278. package/src/report/{react → components/site-components}/ScopeWarnings.tsx +4 -4
  279. package/src/report/{react → components/site-components}/TraceWaterfall.tsx +13 -10
  280. package/src/report/components/site-components/compute.ts +144 -0
  281. package/src/report/components/site-components/faces.ts +80 -0
  282. package/src/report/components/site-components/index.tsx +265 -0
  283. package/src/report/{scope-warnings.ts → components/site-components/scope-warnings.ts} +3 -3
  284. package/src/report/{site-components.test.tsx → components/site-components/site-components.test.tsx} +23 -21
  285. package/src/report/components/site-components/validate.test.ts +89 -0
  286. package/src/report/{react → components/summaries}/ScopeSummary.tsx +26 -11
  287. package/src/report/components/summaries/compute.ts +56 -0
  288. package/src/report/components/summaries/faces.ts +48 -0
  289. package/src/report/components/summaries/index.tsx +127 -0
  290. package/src/report/components/summaries/validate.test.ts +49 -0
  291. package/src/report/definition/grid-layout.test.ts +124 -0
  292. package/src/report/definition/grid-layout.ts +146 -0
  293. package/src/report/{primitives.tsx → definition/primitives.tsx} +168 -18
  294. package/src/report/{report.ts → definition/report.ts} +98 -165
  295. package/src/report/{shell-head.test.ts → definition/shell-head.test.ts} +2 -2
  296. package/src/report/{text/table.ts → definition/table-text.ts} +4 -4
  297. package/src/report/{tree.ts → definition/tree.ts} +58 -22
  298. package/src/report/index.ts +126 -66
  299. package/src/report/{aggregate.ts → model/aggregate.ts} +31 -9
  300. package/src/report/{flag.ts → model/flag.ts} +39 -1
  301. package/src/report/{format.ts → model/format.ts} +59 -5
  302. package/src/report/{locale.ts → model/locale.ts} +34 -36
  303. package/src/report/{metrics.ts → model/metrics.ts} +3 -3
  304. package/src/report/{types.ts → model/types.ts} +143 -22
  305. package/src/report/react/index.tsx +52 -26
  306. package/src/report/{dual-render.test.tsx → runtime/dual-render.test.tsx} +564 -49
  307. package/src/report/runtime/host.test.ts +44 -0
  308. package/src/report/runtime/host.ts +138 -0
  309. package/src/report/{load.ts → runtime/load.ts} +1 -1
  310. package/src/report/runtime/text.ts +192 -0
  311. package/src/report/runtime/web.ts +106 -0
  312. package/src/results/attempt-evidence.ts +5 -1
  313. package/src/results/host-equivalence.test.ts +54 -3
  314. package/src/results/select.ts +30 -6
  315. package/src/runner/attempt.test.ts +48 -1
  316. package/src/runner/attempt.ts +62 -42
  317. package/src/runner/cleanup-timeout.test.ts +16 -0
  318. package/src/runner/cleanup-timeout.ts +23 -0
  319. package/src/runner/discover.ts +1 -2
  320. package/src/runner/eval-selection.test.ts +187 -0
  321. package/src/runner/eval-selection.ts +109 -0
  322. package/src/runner/experiment-cleanup-registry.test.ts +89 -0
  323. package/src/runner/experiment-cleanup-registry.ts +39 -0
  324. package/src/runner/experiment-labels.test.ts +71 -0
  325. package/src/runner/feedback/agent.test.ts +33 -1
  326. package/src/runner/feedback/agent.ts +12 -16
  327. package/src/runner/feedback/ci.test.ts +35 -1
  328. package/src/runner/feedback/ci.ts +16 -18
  329. package/src/runner/feedback/coordinator.ts +28 -0
  330. package/src/runner/feedback/human.test.ts +108 -1
  331. package/src/runner/feedback/human.ts +71 -21
  332. package/src/runner/feedback/reducer.test.ts +64 -0
  333. package/src/runner/feedback/reducer.ts +26 -0
  334. package/src/runner/feedback/sink.ts +40 -1
  335. package/src/runner/fingerprint.ts +2 -1
  336. package/src/runner/report.test.ts +14 -0
  337. package/src/runner/report.ts +3 -1
  338. package/src/runner/run.test.ts +390 -12
  339. package/src/runner/run.ts +259 -26
  340. package/src/runner/sandbox-selection.test.ts +13 -3
  341. package/src/runner/sandbox-selection.ts +4 -2
  342. package/src/runner/types.ts +158 -23
  343. package/src/sandbox/docker.ts +7 -0
  344. package/src/sandbox/e2b.ts +12 -13
  345. package/src/sandbox/types.ts +23 -21
  346. package/src/scoring/display.test.ts +28 -2
  347. package/src/scoring/display.ts +38 -5
  348. package/src/scoring/types.ts +3 -3
  349. package/src/shared/aggregate.test.ts +52 -0
  350. package/src/shared/aggregate.ts +30 -1
  351. package/src/shared/types.ts +6 -1
  352. package/src/show/command.test.ts +34 -0
  353. package/src/show/command.ts +16 -0
  354. package/src/show/compose.ts +1 -1
  355. package/src/show/index.ts +58 -22
  356. package/src/show/render.ts +16 -240
  357. package/src/show/show.test.ts +128 -35
  358. package/src/view/app/App.test.tsx +8 -7
  359. package/src/view/app/App.tsx +135 -51
  360. package/src/view/app/i18n.ts +7 -147
  361. package/src/view/app/lib/attempt-dialog.test.ts +65 -0
  362. package/src/view/app/lib/attempt-dialog.ts +69 -0
  363. package/src/view/app/main.tsx +0 -1
  364. package/src/view/app/types.ts +3 -86
  365. package/src/view/artifact-serving.test.ts +22 -38
  366. package/src/view/client-dist/app.css +1 -1
  367. package/src/view/client-dist/app.js +15 -22
  368. package/src/view/data.test.ts +48 -36
  369. package/src/view/data.ts +122 -89
  370. package/src/view/index.ts +3 -13
  371. package/src/view/server.ts +36 -6
  372. package/src/view/shared/types.ts +6 -31
  373. package/src/view/site-parity.test.ts +24 -1
  374. package/src/view/site.ts +144 -17
  375. package/src/view/styles.css +18 -806
  376. package/src/view/view-report.test.ts +182 -34
  377. package/dist/report/components.d.ts +0 -179
  378. package/dist/report/components.js +0 -544
  379. package/dist/report/compute.d.ts +0 -139
  380. package/dist/report/react/ExperimentComparison.d.ts +0 -10
  381. package/dist/report/react/ExperimentComparison.js +0 -12
  382. package/dist/report/react/MetricScatter.d.ts +0 -9
  383. package/dist/report/react/format.d.ts +0 -3
  384. package/dist/report/react/format.js +0 -7
  385. package/dist/report/text/faces.d.ts +0 -45
  386. package/dist/report/text/faces.js +0 -671
  387. package/dist/report/web.d.ts +0 -32
  388. package/dist/report/web.js +0 -48
  389. package/docs-site/zh/how-to/authoring.mdx +0 -162
  390. package/docs-site/zh/how-to/custom-reports.mdx +0 -414
  391. package/docs-site/zh/how-to/experiments.mdx +0 -86
  392. package/docs-site/zh/how-to/write-experiment.mdx +0 -164
  393. package/src/report/components.tsx +0 -925
  394. package/src/report/react/ExperimentComparison.tsx +0 -73
  395. package/src/report/react/format.ts +0 -9
  396. package/src/report/text/faces.ts +0 -767
  397. package/src/report/web.ts +0 -77
  398. package/src/show/report-host.test.ts +0 -205
  399. package/src/show/report-host.ts +0 -389
  400. package/src/view/app/components/AttemptModal.tsx +0 -496
  401. package/src/view/app/components/CodeView.test.tsx +0 -142
  402. package/src/view/app/components/CodeView.tsx +0 -310
  403. package/src/view/app/components/CopyControls.tsx +0 -106
  404. package/src/view/app/components/Trace.tsx +0 -100
  405. package/src/view/app/components/Transcript.tsx +0 -157
  406. package/src/view/app/components/ui/badge.tsx +0 -21
  407. package/src/view/app/lib/artifact-url.ts +0 -17
  408. package/src/view/app/lib/attempt-route.test.ts +0 -80
  409. package/src/view/app/lib/attempt-route.ts +0 -52
  410. package/src/view/app/lib/format.ts +0 -70
  411. package/src/view/app/lib/guards.test.ts +0 -108
  412. package/src/view/app/lib/guards.ts +0 -71
  413. package/src/view/app/lib/rows.ts +0 -22
  414. package/src/view/app/lib/transcript-data.tsx +0 -151
  415. package/src/view/app/lib/verdict.ts +0 -23
  416. package/src/view/app/shared.ts +0 -8
  417. /package/dist/report/{react → components/metric-views}/chart-math.d.ts +0 -0
  418. /package/dist/report/{react → components/metric-views}/chart-math.js +0 -0
  419. /package/dist/report/{text → components/metric-views}/plot.d.ts +0 -0
  420. /package/dist/report/{react → components/site-components}/PoweredBy.d.ts +0 -0
  421. /package/dist/report/{react → components/site-components}/PoweredBy.js +0 -0
  422. /package/dist/report/{text/layout.d.ts → model/text-layout.d.ts} +0 -0
  423. /package/dist/report/{text/layout.js → model/text-layout.js} +0 -0
  424. /package/dist/report/{types.js → model/types.js} +0 -0
  425. /package/src/report/{react → components/metric-views}/chart-math.test.ts +0 -0
  426. /package/src/report/{react → components/metric-views}/chart-math.ts +0 -0
  427. /package/src/report/{react → components/site-components}/PoweredBy.tsx +0 -0
  428. /package/src/report/{text/layout.ts → model/text-layout.ts} +0 -0
package/src/i18n/zh-CN.ts CHANGED
@@ -58,9 +58,16 @@ export const zhCN = {
58
58
  "cli.flag.invalidOutput": "标志 --output 需要 auto|human|agent|ci 之一,收到 \"{{value}}\"。\n",
59
59
  "runner.budgetUnenforceable":
60
60
  "{{budgetKey}} 的 budget:连续多个 attempt 完成后都拿不到成本数据(agent 不上报用量且模型不在价格表)——该 agent 的 budget 无法执行,取消护栏继续跑。\n",
61
+ "runner.experimentTeardownFailed":
62
+ "实验 {{experimentId}} 的 teardown 执行失败:{{message}}。结果不受影响,但该实验起的宿主机资源可能没有回收,请手动检查。\n",
63
+ "runner.cleanupTimeout": "cleanup 执行超过 {{timeoutMs}}ms 清理超时\n",
64
+ "runner.setupReturnedCleanup":
65
+ "{{layer}} 返回了一个函数。setup 不承载收尾,返回值不会被执行——收尾写在同层成对的 teardown 里({{hint}});见 docs-site 的实验教程或 docs/runner.md「环境预置」。\n",
66
+ "runner.experimentTeardownLate":
67
+ "实验 {{experimentId}} 的 teardown 未被正常计数路径触发,已在运行收尾兜底执行。结果不受影响;这行出现说明命中了一个未定位的调度间歇问题,请把本次运行信息记入 memory 台账。\n",
61
68
  "judge.modelMissing":
62
69
  "judge 未配置模型:在 defineConfig({ judge: { model: \"...\" } })、eval 的 judge 配置或环境变量 NICEEVAL_JUDGE_MODEL 里指定裁判模型(没有内置默认模型)。\n" +
63
- " 文档:node_modules/niceeval/docs-site/zh/how-to/scoring-guide.mdx",
70
+ " 文档:node_modules/niceeval/docs-site/zh/tutorials/scoring-guide.mdx",
64
71
  "loaders.yamlMissing":
65
72
  "loadYaml(\"{{path}}\") 需要 YAML 解析器:请先 `pnpm add yaml`(或改用 loadJson + JSON 数据集)。",
66
73
  "cli.flag.parseError": "{{message}}\n运行 `niceeval --help` 查看用法。\n",
@@ -68,7 +75,7 @@ export const zhCN = {
68
75
  "cli.help":
69
76
  "niceeval — agent-native evals\n\n" +
70
77
  "用法:\n" +
71
- " niceeval exp [组|实验] [eval-id 前缀…] 跑实验\n" +
78
+ " niceeval exp [路径|实验] [eval-id 前缀…] 跑实验\n" +
72
79
  " niceeval show [eval-id 前缀… | @<locator>] 终端读结果\n" +
73
80
  " 裸跑:每个 experiment 的现刻判定(跨 run 合成),每行带紧凑 attempt 索引\n" +
74
81
  " (locator + 失败原因)\n" +
@@ -80,14 +87,14 @@ export const zhCN = {
80
87
  " --timing 整个 attempt 的统一时间树(阶段 + hook/命令/turn + 轮内 OTel)\n" +
81
88
  " --diff[=文件] agent 归因的文件改动摘要;=文件 按窗口展开单个文件\n" +
82
89
  " --history 逐 experiment × eval 的执行时间轴(与 --report 互斥)\n" +
83
- " --results <目录> 钉死结果根 --experiment <id> 只看该实验\n" +
90
+ " --results <目录> 钉死结果根 --exp <id> 只看该实验\n" +
84
91
  " --report <文件> 自定义报告 --page <id> 定初始页(多页报告渲染该页,\n" +
85
92
  " 尾部再附其余页索引)\n" +
86
93
  " niceeval list 列出发现到的 eval\n" +
87
94
  " niceeval view [eval-id 前缀…] [--out 目录] [--port n] [--no-open]\n" +
88
95
  " 报告页 + 证据室;--report <文件> 整槽换成自定义报告(与 show 同一文件)\n" +
89
96
  " --page <id> 定初始页 --results <目录> 钉死结果根\n" +
90
- " --snapshot <文件> 只打开这一份快照 --experiment <id> 只看该实验\n" +
97
+ " --snapshot <文件> 只打开这一份快照 --exp <id> 只看该实验\n" +
91
98
  " --out <目录> 静态导出:index.html 连同查看器 artifact,可直接静态托管\n" +
92
99
  " niceeval sandbox list|enter|history|diff|stop 查看与销毁 --keep-sandbox 留下的现场\n" +
93
100
  " niceeval clean 删除 .niceeval/ 历史 artifact\n" +
@@ -104,7 +111,7 @@ export const zhCN = {
104
111
  "cli.show.noResults": "{{root}} 下没有结果。先 `niceeval exp` 跑一轮,再 `niceeval show`。\n",
105
112
  "cli.show.runDirMissing": "Results directory not found: {{dir}}\n",
106
113
  "cli.show.noEvalMatch": "No results matched: {{patterns}}. Evals with results: {{evals}}\n",
107
- "cli.show.noExperimentMatch": "No experiment matched --experiment {{arg}}. Experiments with results: {{experiments}}\n",
114
+ "cli.show.noExperimentMatch": "No experiment matched --exp {{arg}}. Experiments with results: {{experiments}}\n",
108
115
  "cli.show.historyReportConflict":
109
116
  "`--history` and `--report` are mutually exclusive: both take over the main output. --history is the host's per-attempt execution timeline; for snapshot-level trends, compose exp.snapshots inside your report file instead.\n",
110
117
  "cli.show.evidenceNeedsEval":
@@ -116,10 +123,14 @@ export const zhCN = {
116
123
  "cli.eval.noMatchKnown": "已发现 {{count}} 个 eval:{{evals}}\n",
117
124
  "cli.exp.agentModelFlagUnsupported": "experiment 运行不支持 --agent / --model。请新增或复制一个 experiment 文件并修改 model。\n",
118
125
  "cli.exp.viewerFlagUnsupported": "`{{flag}}` 只适用于 niceeval {{command}},不能用于 niceeval exp。\n",
119
- "cli.experiment.noMatch": "没有匹配的实验:{{arg}}。已发现:{{experiments}}\n",
126
+ "cli.experiment.noMatch":
127
+ "没有匹配的实验:{{arg}}。可用路径:{{experiments}}。\n" +
128
+ "运行 `niceeval exp <路径> --dry` 预览计划。\n",
120
129
  "cli.experiment.viewerCommandHint": "你可能想运行:niceeval {{command}}{{args}}\n",
121
- "cli.experiment.noEvalsSelected": "未选择任何 eval:{{selection}} 匹配到 0 个 eval。可用实验:{{experiments}}。\n",
122
- "cli.experimentGroup": "组",
130
+ "cli.experiment.noEvalsSelected":
131
+ "未选择任何 eval:{{selection}} 匹配到 0 个 eval。可用的 eval 前缀:{{experiments}}。\n" +
132
+ "运行 `niceeval exp {{selection}} --dry` 查看它覆盖了什么,或去掉 eval 过滤跑这些实验选中的全部 eval。\n",
133
+ "cli.experimentGroup": "路径",
123
134
  "cli.fallbackCleanupTimeout": "\ngraceful 清理超时,强制清理沙箱…\n",
124
135
  "cli.forceCleanupExit": "\n强制清理沙箱并退出…\n",
125
136
  "cli.init.done": "已就绪:evals/、niceeval.config.ts,以及 AGENTS.md 里的 niceeval agent 指引区块(指向 node_modules/niceeval/docs-site/zh)。\n",
@@ -130,8 +141,8 @@ export const zhCN = {
130
141
  "cli.pressCtrlC": "按 Ctrl+C 退出。\n",
131
142
  "cli.resultsPath": "结构化结果:{{path}}(snapshot.json + 每 attempt 的 result.json / events.json / trace.json / diff.json)\n",
132
143
  "cli.run.experimentRequired":
133
- "运行 eval 必须通过 experiment:用 `niceeval exp [实验组|配置] [eval id 前缀]`。\n" +
134
- " 文档:node_modules/niceeval/docs-site/zh/how-to/write-experiment.mdx\n",
144
+ "运行 eval 必须通过 experiment:用 `niceeval exp [路径|配置] [eval id 前缀]`。\n" +
145
+ " 文档:node_modules/niceeval/docs-site/zh/tutorials/write-experiment.mdx\n",
135
146
  "cli.run.experimentRequiredHint": "提示:\"{{pattern}}\" 是实验{{kind}},你大概想跑:niceeval exp {{pattern}}\n",
136
147
  "cli.run.experimentRequiredKnown": "已发现实验:{{experiments}}\n",
137
148
  "cli.unimplemented": "命令 \"{{command}}\" 暂未实现(MVP)。\n",
@@ -142,7 +153,7 @@ export const zhCN = {
142
153
  "cli.view.url": "niceeval view: {{url}}\n",
143
154
  "context.capabilityMissing":
144
155
  "agent \"{{agent}}\" 不是沙箱型(defineSandboxAgent 构造),t.{{method}} 这类断言只有沙箱型 agent 可用。换用 defineSandboxAgent 构造的 agent,或去掉这条断言。\n" +
145
- " 文档:node_modules/niceeval/docs-site/zh/how-to/sandbox-agent.mdx",
156
+ " 文档:node_modules/niceeval/docs-site/zh/tutorials/sandbox-agent.mdx",
146
157
  "context.skipEmpty": "skip() 需要一个非空理由。",
147
158
  "context.turnFailed": "本轮 send 返回 failed(turn status = failed):{{message}}",
148
159
  "context.turnFailedDefault": "本轮 send 返回 failed(turn status = failed)",
@@ -152,6 +163,8 @@ export const zhCN = {
152
163
  "define.evalTestRequired": "defineEval 需要一个 async test(t) 函数。",
153
164
  "define.experimentAgentRequired": "defineExperiment 需要 agent。",
154
165
  "define.experimentFlagNotJson": "experiment.flags.{{key}} 不是可 JSON 序列化的值(函数 / undefined / 循环引用 / bigint 不允许);flags 会原样进入结果快照,必须是纯 JSON。",
166
+ "define.experimentLabelInvalid": "experiment.labels.{{key}} 必须是字符串或有限数字;labels 是报告侧的归类坐标,会原样进入结果快照。",
167
+ "define.experimentSetupNotFunction": "experiment.setup 必须是函数((ctx) => void);要清理请挂 experiment.teardown;要按实验准备沙箱内环境请挂 sandbox spec 的 .setup() 钩子链。",
155
168
  "define.experimentIdRejected": "defineExperiment 不接受 id —— id 由文件路径推导。",
156
169
  "define.sandboxAgentNameRequired": "defineSandboxAgent 需要 name。",
157
170
  "define.sandboxCreateRequired": "defineSandbox 需要一个 create() 函数。",
@@ -164,7 +177,7 @@ export const zhCN = {
164
177
  "docker.unsupportedRuntime": "Unsupported runtime: {{runtime}}",
165
178
  "feedback.human.active": "ACTIVE",
166
179
  "feedback.human.budgetExhausted": "{{experimentId}} 预算已耗尽(已花 {{spent}},未跑 {{unstarted}})",
167
- "feedback.human.compare": "Compare: niceeval view {{group}}",
180
+ "feedback.human.compare": "Compare: niceeval view",
168
181
  "feedback.human.counts": "共 {{total}} · 复用 {{reused}} · 运行中 {{running}} · 排队 {{queued}} · 已完成 {{completed}}",
169
182
  "feedback.human.diffHint": "Diff: niceeval show {{locator}} --diff",
170
183
  "feedback.human.evalHint": "Eval: niceeval show {{locator}} --source",
@@ -189,6 +202,10 @@ export const zhCN = {
189
202
  "feedback.phase.evalSetup": "eval 预置",
190
203
  "feedback.phase.sandboxCreate": "创建沙箱",
191
204
  "feedback.phase.sandboxQueue": "排队等沙箱",
205
+ "feedback.phase.experimentSetup": "实验预置",
206
+ "feedback.phase.experimentTeardown": "实验收尾",
207
+ "feedback.human.hookDone": "完成",
208
+ "feedback.human.hookFailed": "失败",
192
209
  "feedback.phase.sandboxSetup": "沙箱预置",
193
210
  "feedback.phase.scoring": "评分",
194
211
  "feedback.phase.teardown": "清理中",
@@ -268,13 +285,11 @@ export const zhCN = {
268
285
  "runner.startSandboxTeardown": "sandbox teardown(环境预置钩子)…",
269
286
  "runner.timeout": "attempt 超时({{timeoutMs}}ms)\n最近进度:\n{{recentLogs}}",
270
287
  "runner.traceSelected": " → 留 {{count}}(按语义)",
271
- "runner.resumeCarry": " · 复用上次 {{carried}} 个已判定的结果,重跑 {{retry}} 个 eval\n",
272
- "runner.resumeCarryDetail": " 复用 [{{experiment}}] {{evals}}\n",
273
288
  "runner.useRemoteAgent": "使用 remote agent(不创建沙箱)…",
274
289
  "sandbox.providerNotImplemented": "{{provider}} sandbox provider not implemented; use docker, vercel, or e2b",
275
290
  "sandbox.missingSpec":
276
291
  "沙箱型 agent 需要一个 sandbox,但没有提供。niceeval 不再自动选默认 provider——请在 defineExperiment()/defineConfig() 里把 sandbox 设成 dockerSandbox() / vercelSandbox() / e2bSandbox()(从 \"niceeval/sandbox\" 导入)。\n" +
277
- " 文档:node_modules/niceeval/docs-site/zh/how-to/sandbox-providers.mdx",
292
+ " 文档:node_modules/niceeval/docs-site/zh/tutorials/sandbox-providers.mdx",
278
293
  "sandbox.dependencyMissing.docker": "Docker sandbox requires 'dockerode'. Install it with: pnpm add dockerode @types/dockerode",
279
294
  "sandbox.dependencyMissing.e2b": "E2B sandbox requires 'e2b'. Install it with: pnpm add e2b",
280
295
  "sandbox.dependencyMissing.vercel": "Vercel sandbox requires '@vercel/sandbox'. Install it with: pnpm add @vercel/sandbox",
package/src/index.ts CHANGED
@@ -24,7 +24,9 @@ export type {
24
24
  Severity,
25
25
  Verdict,
26
26
  EvalDef,
27
+ EvalDescriptor,
27
28
  ExperimentDef,
29
+ ExperimentHookContext,
28
30
  Config,
29
31
  LocalizedText,
30
32
  JudgeConfig,
@@ -32,6 +32,28 @@ export function colorIndexForKey(key: string): number {
32
32
  return hash % NRE_PALETTE_SIZE;
33
33
  }
34
34
 
35
+ /**
36
+ * 同一张图内 series 键集合的配色:每个键仍以稳定散列为起点(无冲突时与跨图配色一致),
37
+ * 图内撞色时按传入顺序(图例顺序)线性探测下一个空色格——跨图稳定让位给图内可辨;
38
+ * 键数超过色板后无空格可探,回落散列格(复用不可避免)。返回键 → 色板下标。
39
+ * 契约见 docs/feature/reports/library/metric-views.md「MetricScatter」;
40
+ * 修法台账见 memory/scatter-series-color-collision.md。
41
+ */
42
+ export function colorIndicesForKeys(keys: readonly string[]): Map<string, number> {
43
+ const used = new Set<number>();
44
+ const out = new Map<string, number>();
45
+ for (const key of keys) {
46
+ if (out.has(key)) continue;
47
+ let idx = colorIndexForKey(key);
48
+ if (used.size < NRE_PALETTE_SIZE) {
49
+ while (used.has(idx)) idx = (idx + 1) % NRE_PALETTE_SIZE;
50
+ }
51
+ used.add(idx);
52
+ out.set(key, idx);
53
+ }
54
+ return out;
55
+ }
56
+
35
57
  /** 键对应的稳定 class 名("nre-c3"),配 styles.css 的 .nre-cN 上文字色。 */
36
58
  export function colorClassForKey(key: string): string {
37
59
  return `nre-c${colorIndexForKey(key)}`;
@@ -1,5 +1,5 @@
1
1
  // niceeval 报告的渐进增强 runtime:纯 vanilla JS、零依赖、IIFE、幂等。
2
- // 只作用于 .nre DOM 与 data-nre-* 属性;六个行为——实验组切换、Tabs 单选切换、表格排序、
2
+ // 只作用于 .nre DOM 与 data-nre-* 属性;五个行为——Tabs 单选切换、表格排序、
3
3
  // 行过滤、SVG 点 tooltip、警告命令复制。全部只改浏览状态,不改数据、指标口径或初始 HTML 数值。
4
4
  // 静态 HTML 无 JS 时内容完整可读是硬约束:排序有数据侧预排、tooltip 退化为原生 <title>、
5
5
  // 过滤输入框静默无功能、Tabs 退化为原生 <details> 手风琴、命令块退化为点击全选。
@@ -19,38 +19,6 @@
19
19
  return target && target.closest ? target.closest(selector) : null;
20
20
  }
21
21
 
22
- // ───────────────────────── 实验组:[data-nre-experiment-group-select] ─────────────────────────
23
- // 数据侧已经把每组的摘要、散点和列表分别算好;这里仅在同一报告节点内切换 <details>,
24
- // 不重新请求、不重算,也不触碰 Runs / Traces / Attempt 证据室。
25
-
26
- function selectExperimentGroup(control) {
27
- var root = control.closest("[data-nre-experiment-groups]");
28
- if (!root) return;
29
- var selected = control.getAttribute("data-nre-experiment-group-select");
30
- var controls = root.querySelectorAll("[data-nre-experiment-group-select]");
31
- var panels = root.querySelectorAll("[data-nre-experiment-group-panel]");
32
- for (var i = 0; i < controls.length; i++) {
33
- var active = controls[i].getAttribute("data-nre-experiment-group-select") === selected;
34
- controls[i].setAttribute("aria-selected", active ? "true" : "false");
35
- controls[i].tabIndex = active ? 0 : -1;
36
- }
37
- for (var j = 0; j < panels.length; j++) {
38
- panels[j].open = panels[j].getAttribute("data-nre-experiment-group-panel") === selected;
39
- }
40
- }
41
-
42
- document.addEventListener("click", function (e) {
43
- var control = closest(e.target, "[data-nre-experiment-group-select]");
44
- if (control) selectExperimentGroup(control);
45
- });
46
-
47
- document.addEventListener("keydown", function (e) {
48
- var control = closest(e.target, "[data-nre-experiment-group-select]");
49
- if (!control || (e.key !== "Enter" && e.key !== " ")) return;
50
- e.preventDefault();
51
- selectExperimentGroup(control);
52
- });
53
-
54
22
  // ───────────────────────── Tabs:[data-nre-tabs] 单选切换 ─────────────────────────
55
23
  // 静态 HTML 每 tab 一个 <details> 且仅首个 open;点击 summary 时接管原生 toggle:
56
24
  // 打开所点 tab、收起同组其余,点已开的 tab 保持打开(单选语义,恒有一个面板可见)。
@@ -65,98 +65,6 @@
65
65
  .nre-attempt-list .nre-truncated { color:var(--warn); font-size:.9em; }
66
66
  .nre-attempt-list .nre-attempt-list-empty { border:1px dashed var(--line-strong); border-radius:8px; padding:18px; color:var(--muted); text-align:center; background:var(--panel); }
67
67
 
68
- /* ---- ExperimentComparison:完整组索引 + 当前组独立 panel ---- */
69
- .nre-experiment-comparison .nre-experiment-group-tabs {
70
- display:grid;
71
- grid-template-columns:repeat(auto-fit,minmax(320px,1fr));
72
- gap:12px;
73
- margin-bottom:20px;
74
- }
75
- .nre-experiment-comparison .nre-experiment-group-tab {
76
- min-width:0;
77
- border:1px solid var(--line);
78
- border-radius:9px;
79
- padding:14px 16px 8px;
80
- background:var(--panel);
81
- cursor:pointer;
82
- transition:border-color .12s,background .12s;
83
- }
84
- .nre-experiment-comparison .nre-experiment-group-tab:hover {
85
- border-color:var(--line-strong);
86
- background:color-mix(in oklch,var(--panel-2),var(--panel) 35%);
87
- }
88
- .nre-experiment-comparison .nre-experiment-group-tab:focus-visible {
89
- outline:2px solid var(--nre-c0);
90
- outline-offset:2px;
91
- }
92
- .nre-experiment-comparison .nre-experiment-group-name {
93
- display:block;
94
- margin-bottom:10px;
95
- color:var(--text);
96
- font-size:15px;
97
- overflow-wrap:anywhere;
98
- }
99
- /* 组卡里嵌的 ScopeSummary 降为紧凑行:去掉满宽 KPI 条的边框,收小数字 */
100
- .nre-experiment-comparison .nre-experiment-group-tab .nre-scope-summary { margin:0; }
101
- .nre-experiment-comparison .nre-experiment-group-tab .nre-scope-kpis {
102
- display:flex;
103
- flex-wrap:wrap;
104
- column-gap:16px;
105
- row-gap:6px;
106
- margin:0 0 6px;
107
- border:0;
108
- border-radius:0;
109
- background:transparent;
110
- overflow:visible;
111
- }
112
- .nre-experiment-comparison .nre-experiment-group-tab .nre-scope-kpi {
113
- min-width:58px;
114
- padding:0;
115
- border-right:0;
116
- }
117
- .nre-experiment-comparison .nre-experiment-group-tab .nre-scope-kpi dd {
118
- margin:3px 0 0;
119
- font-size:16px;
120
- line-height:1.15;
121
- font-weight:650;
122
- }
123
- .nre-experiment-comparison .nre-experiment-group-tab .nre-scope-kpi-rate dd { font-size:18px; }
124
- .nre-experiment-comparison .nre-experiment-group-panel {
125
- padding:16px 0;
126
- }
127
- .nre-experiment-comparison .nre-experiment-group-panel > summary {
128
- cursor:pointer;
129
- font-size:16px;
130
- font-weight:700;
131
- overflow-wrap:anywhere;
132
- }
133
- .nre-experiment-comparison .nre-experiment-group-panel[open] > summary {
134
- margin-bottom:16px;
135
- }
136
- .nre-experiment-comparison .nre-experiment-group-panel > .nre {
137
- margin:0 0 18px;
138
- }
139
- /* group panel 已经是内容的唯一外框;内嵌图表不再重复套一层卡片边框 */
140
- .nre-experiment-comparison .nre-experiment-group-panel .nre-metric-scatter,
141
- .nre-experiment-comparison .nre-experiment-group-panel .nre-metric-line,
142
- .nre-experiment-comparison .nre-experiment-group-panel .nre-metric-bars {
143
- border:0;
144
- border-radius:0;
145
- background:transparent;
146
- padding:14px 0 8px;
147
- }
148
- .nre-experiment-comparison .nre-experiment-group-panel > .nre:last-child {
149
- margin-bottom:0;
150
- }
151
- .nre-experiment-comparison .nre-experiment-groups-empty {
152
- border:1px dashed var(--line-strong);
153
- border-radius:8px;
154
- padding:18px;
155
- color:var(--muted);
156
- text-align:center;
157
- background:var(--panel);
158
- }
159
-
160
68
  /* ---- EvalList:实体列表的第二级,一条 <details> 一个 experimentId × evalId ---- */
161
69
  .nre-eval-list .nre-evals { list-style:none; margin:0; padding:0; }
162
70
  .nre-eval-list .nre-eval { border-bottom:1px solid var(--line); }
@@ -176,13 +84,19 @@
176
84
  /* ---- ExperimentList:web 面固定八列比较表,一条 <details> 一个 experiment ---- */
177
85
  .nre-experiment-table { border:1px solid var(--line); border-radius:9px; overflow:hidden; background:var(--panel); }
178
86
  .nre-experiment-head,
179
- .nre-experiment-summary { display:grid; grid-template-columns:minmax(220px,1.25fr) minmax(120px,.8fr) minmax(90px,.6fr) minmax(100px,.65fr) minmax(90px,.55fr) minmax(110px,.7fr) minmax(90px,.6fr) minmax(160px,.9fr); column-gap:16px; align-items:center; }
180
- .nre-experiment-head { padding:12px 20px; color:var(--muted); font-size:12px; font-weight:560; text-transform:uppercase; letter-spacing:.05em; border-bottom:1px solid var(--line); }
181
- .nre-experiment-head button { appearance:none; border:0; padding:0; background:transparent; color:inherit; font:inherit; text-transform:inherit; letter-spacing:inherit; text-align:left; cursor:pointer; }
182
- .nre-experiment-head button::after { content:"↕"; margin-left:6px; color:var(--soft); font-size:11px; }
183
- .nre-experiment-head button.nre-sort-asc::after { content:"↑"; color:var(--text); }
184
- .nre-experiment-head button.nre-sort-desc::after { content:"↓"; color:var(--text); }
185
- .nre-experiment-table-wrap > .nre-filter { height:34px; min-width:260px; margin-bottom:16px; border:1px solid var(--line); border-radius:7px; padding:0 11px; background:var(--panel); color:var(--text); font:inherit; }
87
+ .nre-experiment-summary { display:grid; grid-template-columns:minmax(240px,1.35fr) minmax(115px,.72fr) minmax(95px,.58fr) minmax(108px,.62fr) minmax(105px,.58fr) minmax(112px,.66fr) minmax(92px,.52fr) minmax(160px,.86fr); column-gap:14px; align-items:center; }
88
+ .nre-experiment-head { padding:13px 20px; color:var(--muted); font-size:12px; line-height:1.2; font-weight:620; border-bottom:1px solid var(--line); }
89
+ .nre-experiment-head button { appearance:none; display:inline-flex; width:max-content; max-width:100%; align-items:center; gap:5px; border:0; padding:0; background:transparent; color:inherit; font:inherit; line-height:inherit; text-align:left; white-space:nowrap; cursor:pointer; }
90
+ .nre-experiment-head button:hover,
91
+ .nre-experiment-head button:focus-visible { color:var(--text); }
92
+ .nre-experiment-head .nre-num-head { justify-self:end; text-align:right; }
93
+ .nre-experiment-head .nre-sort-icon { display:inline-block; flex:0 0 11px; width:11px; color:var(--soft); font-size:11px; text-align:center; }
94
+ .nre-experiment-head .nre-sort-icon::before { content:"↕"; opacity:0; transition:opacity .12s; }
95
+ .nre-experiment-head button:hover .nre-sort-icon::before,
96
+ .nre-experiment-head button:focus-visible .nre-sort-icon::before { opacity:1; }
97
+ .nre-experiment-head button.nre-sort-asc .nre-sort-icon::before { content:"↑"; opacity:1; color:var(--text); }
98
+ .nre-experiment-head button.nre-sort-desc .nre-sort-icon::before { content:"↓"; opacity:1; color:var(--text); }
99
+ .nre-experiment-table-wrap > .nre-filter { display:block; width:min(100%,280px); height:34px; min-width:0; margin:0 0 12px auto; border:1px solid var(--line); border-radius:7px; padding:0 11px; background:var(--panel); color:var(--text); font:inherit; }
186
100
  .nre-experiment-list .nre-experiment-entry { border-bottom:1px solid var(--line); }
187
101
  .nre-experiment-list .nre-experiment-entry:last-child { border-bottom:0; }
188
102
  .nre-experiment-list .nre-experiment-summary { padding:13px 20px; cursor:pointer; list-style:none; transition:background .12s; }
@@ -194,11 +108,11 @@
194
108
  .nre-experiment-list .nre-experiment-entry[open] .nre-experiment-name::before { transform:rotate(45deg); }
195
109
  .nre-experiment-list .nre-experiment-id { display:block; overflow-wrap:anywhere; font-weight:650; }
196
110
  .nre-experiment-list .nre-experiment-name small { display:block; margin-top:3px; color:var(--muted); font-size:12px; font-weight:400; }
197
- .nre-experiment-list .nre-num { font-variant-numeric:tabular-nums; font-feature-settings:"tnum"; white-space:nowrap; }
111
+ .nre-experiment-list .nre-num { text-align:right; font-variant-numeric:tabular-nums; font-feature-settings:"tnum"; white-space:nowrap; }
198
112
  .nre-experiment-list .nre-good { color:var(--good); }
199
113
  .nre-experiment-list .nre-warn { color:var(--warn); }
200
114
  .nre-experiment-list .nre-bad { color:var(--bad); }
201
- .nre-experiment-list .nre-experiment-pill { display:inline-flex; min-height:22px; align-items:center; border:1px solid var(--line); border-radius:999px; padding:0 8px; color:var(--muted); font-size:12px; white-space:nowrap; }
115
+ .nre-experiment-list .nre-experiment-pill { display:inline-flex; min-height:22px; align-items:center; color:var(--muted); font-size:12px; white-space:nowrap; }
202
116
  .nre-experiment-list .nre-experiment-detail { padding:18px 30px 22px; background:color-mix(in oklch,var(--panel-2),var(--panel) 24%); border-top:1px solid var(--line); }
203
117
  .nre-experiment-list .nre-experiment-flags { display:flex; flex-wrap:wrap; gap:8px; margin:0 0 14px; color:var(--soft); font-size:12px; }
204
118
  .nre-experiment-list .nre-experiment-flags b { border:1px solid color-mix(in oklch,var(--line),transparent 16%); border-radius:999px; padding:3px 8px; color:var(--text); font-weight:560; }
@@ -219,7 +133,7 @@
219
133
  .nre-experiment-list .nre-eval-attempt-metrics,
220
134
  .nre-experiment-list .nre-eval-reason { color:var(--muted); font-size:.92em; }
221
135
  .nre-experiment-list .nre-experiment-list-empty { border:1px dashed var(--line-strong); border-radius:8px; padding:18px; color:var(--muted); text-align:center; background:var(--panel); }
222
- @media(max-width:1000px){.nre-experiment-table{overflow-x:auto}.nre-experiment-head,.nre-experiment-summary{min-width:1040px}.nre-experiment-detail{min-width:1040px}}
136
+ @media(max-width:1160px){.nre-experiment-table{overflow-x:auto}.nre-experiment-head,.nre-experiment-summary{min-width:1120px}.nre-experiment-detail{min-width:1120px}}
223
137
 
224
138
  /* ---- verdict 判定色(EvalList/ExperimentList 的判定符;errored 在这里按 bad 收敛) ---- */
225
139
  .nre .nre-eval-verdict.nre-verdict-passed { color:var(--good); }
@@ -425,6 +339,15 @@ table.nre,
425
339
  font-variant-numeric: tabular-nums;
426
340
  white-space: nowrap;
427
341
  }
342
+ .nre-scope-summary .nre-scope-kpi-note {
343
+ display:block;
344
+ margin-top:5px;
345
+ color:var(--soft);
346
+ font-size:11px;
347
+ font-weight:450;
348
+ line-height:1.25;
349
+ white-space:nowrap;
350
+ }
428
351
  /* 计票格装的是 pill 组:允许换行,行高回到常规 */
429
352
  .nre-scope-summary .nre-scope-kpi-verdicts dd {
430
353
  white-space: normal;
@@ -516,20 +439,26 @@ table.nre,
516
439
  }
517
440
 
518
441
  /* ---- Hero / PoweredBy(站点标题区与品牌行) ---- */
519
- .nre-hero { margin: 0 0 18px; }
442
+ /* 居中大标题:hero 是页首的门面块,整块占满内容列宽、文本水平居中,标题随视口 clamp 放大,
443
+ meta 与品牌行居中跟随。不设 max-width——窄框居中在宽内容列里会读成左偏,占满列宽才真居中。 */
444
+ .nre-hero {
445
+ text-align: center;
446
+ margin: 0 0 clamp(28px, 5vw, 44px);
447
+ }
520
448
  .nre-hero .nre-hero-title {
521
449
  margin: 0;
522
- font-size: 24px;
523
- font-weight: 700;
450
+ font-size: clamp(38px, 5vw, 60px);
451
+ line-height: 0.98;
452
+ font-weight: 760;
524
453
  letter-spacing: -0.01em;
525
454
  }
526
455
  .nre-hero .nre-hero-meta {
527
- margin: 4px 0 0;
456
+ margin: 14px 0 0;
528
457
  color: var(--muted);
529
- font-size: 13px;
458
+ font-size: 14px;
530
459
  }
531
460
  .nre-powered-by {
532
- margin: 6px 0 0;
461
+ margin: 10px 0 0;
533
462
  font-size: 12px;
534
463
  }
535
464
  .nre-powered-by a {
@@ -714,9 +643,10 @@ table.nre,
714
643
  .nre-metric-scatter .nre-scatter-svg,
715
644
  .nre-metric-line .nre-line-svg,
716
645
  .nre-metric-bars .nre-bars-svg {
717
- max-width: 720px;
646
+ max-width: 880px;
718
647
  width: 100%;
719
648
  height: auto;
649
+ margin-inline: auto;
720
650
  display: block;
721
651
  overflow: visible;
722
652
  }
@@ -759,11 +689,16 @@ table.nre,
759
689
  }
760
690
  .nre-metric-scatter .nre-scatter-legend,
761
691
  .nre-metric-bars .nre-bars-legend {
692
+ display: flex;
693
+ max-width: 880px;
694
+ flex-wrap: wrap;
695
+ gap: 0.35rem 0.9rem;
762
696
  color: var(--muted);
763
697
  font-size: 0.85em;
764
- margin-top: 0.25rem;
698
+ margin: 0.5rem auto 0;
765
699
  }
766
- .nre .nre-legend-key { margin-right: 0.75em; }
700
+ .nre .nre-legend-key { display:inline-flex; align-items:center; gap:0.4em; }
701
+ .nre .nre-legend-key::before { content:""; width:0.55em; height:0.55em; border-radius:50%; background:currentColor; }
767
702
  .nre-metric-bars .nre-bars-metric {
768
703
  margin-right: 1em;
769
704
  font-weight: 600;
@@ -771,9 +706,10 @@ table.nre,
771
706
  }
772
707
  .nre-metric-scatter .nre-scatter-missing,
773
708
  .nre-metric-line .nre-line-missing {
709
+ max-width: 880px;
774
710
  color: var(--warn);
775
711
  font-size: 0.85em;
776
- margin: 0.25rem 0 0;
712
+ margin: 0.35rem auto 0;
777
713
  }
778
714
  /* 散点空态(0 可画点)/ 不足以成图(1 可画点):明说缺什么,不画空坐标系 */
779
715
  .nre-metric-scatter .nre-scatter-empty {
@@ -862,6 +798,94 @@ table.nre,
862
798
  margin: 0.25rem 0;
863
799
  }
864
800
 
801
+ /* ---- Section header:标题行右侧短元信息(meta),同一行右对齐,空间不足自动换行
802
+ (docs/feature/reports/library/layout.md「Grid 与 Stat」)。省略 meta 时 Section
803
+ 渲染的是裸 <h2>(既有结构),不套这层 header——旧行为逐字节不变。 ---- */
804
+ .nre-section-header {
805
+ display: flex;
806
+ flex-wrap: wrap;
807
+ align-items: baseline;
808
+ justify-content: space-between;
809
+ gap: 4px 16px;
810
+ margin: 0 0 10px;
811
+ }
812
+ .nre-section-header .nre-section-title { margin: 0; }
813
+ .nre-section-header .nre-section-meta {
814
+ margin: 0;
815
+ color: var(--muted);
816
+ font-size: 13px;
817
+ white-space: nowrap;
818
+ }
819
+
820
+ /* ---- Grid:自由摘要面板的格子容器(docs/feature/reports/architecture.md「排版原语的语义层
821
+ 与面内布局」)。max-width 钳在「声明列数 × 最小格宽 + 格间距」——auto-fit 因此永远
822
+ 摆不出比声明列数更多的列;容器比这个宽度窄时,minmax 的下限让列数按最小 inline size
823
+ 自动减少,窄到个位数视口也不会产生页面级横向滚动。响应式换列全靠这几行 CSS,
824
+ 不需要测量脚本或 hydration。 ---- */
825
+ .nre-grid {
826
+ --nre-grid-cell-min: 220px;
827
+ --nre-grid-gap: 20px;
828
+ --nre-grid-cell-padding: 16px;
829
+ --nre-stat-value-size: 20px;
830
+ display: grid;
831
+ grid-template-columns: repeat(auto-fit, minmax(min(var(--nre-grid-cell-min), 100%), 1fr));
832
+ gap: var(--nre-grid-gap);
833
+ max-width: calc(
834
+ var(--nre-grid-max-columns) * var(--nre-grid-cell-min) + (var(--nre-grid-max-columns) - 1) * var(--nre-grid-gap)
835
+ );
836
+ margin: 1rem 0;
837
+ }
838
+ .nre-grid--compact {
839
+ --nre-grid-cell-min: 160px;
840
+ --nre-grid-gap: 10px;
841
+ --nre-grid-cell-padding: 10px;
842
+ --nre-stat-value-size: 16px;
843
+ }
844
+ .nre-grid-cell { min-width: 0; }
845
+ /* boxed:每个 cell 独立完整四边框,靠 grid gap 分开——不是靠相邻项拼半边框,换行后
846
+ 不会缺左边、缺底边或出现双线。 */
847
+ .nre-grid--boxed .nre-grid-cell {
848
+ border: 1px solid var(--line);
849
+ border-radius: 8px;
850
+ padding: var(--nre-grid-cell-padding);
851
+ background: var(--panel);
852
+ }
853
+ .nre-grid--plain .nre-grid-cell { padding: 0; }
854
+ /* 一个 cell 里嵌套多个 Stat(Col 归拢):只有纵向留白,没有内部分隔线。 */
855
+ .nre-grid-cell > .nre-col { gap: calc(var(--nre-grid-gap) * 0.6); }
856
+
857
+ /* ---- Stat:label / 主值 / detail 三段;label 与 detail 弱化层级,value 用 tabular
858
+ numerals;tone 是主值的语义色,只染 value——positive 不会把 label 和 detail
859
+ 一并染色。 ---- */
860
+ .nre-stat {
861
+ display: flex;
862
+ flex-direction: column;
863
+ gap: 4px;
864
+ min-width: 0;
865
+ }
866
+ .nre-stat .nre-stat-label {
867
+ color: var(--soft);
868
+ font-size: 12px;
869
+ font-weight: 560;
870
+ overflow-wrap: anywhere;
871
+ }
872
+ .nre-stat .nre-stat-value {
873
+ font-size: var(--nre-stat-value-size);
874
+ font-weight: 700;
875
+ line-height: 1.15;
876
+ font-variant-numeric: tabular-nums;
877
+ font-feature-settings: "tnum";
878
+ overflow-wrap: anywhere;
879
+ }
880
+ .nre-stat .nre-stat-detail {
881
+ color: var(--muted);
882
+ font-size: 12px;
883
+ overflow-wrap: anywhere;
884
+ }
885
+ .nre-stat--positive .nre-stat-value { color: var(--good); }
886
+ .nre-stat--negative .nre-stat-value { color: var(--bad); }
887
+ .nre-stat--warning .nre-stat-value { color: var(--warn); }
888
+
865
889
  /* ---- Tabs:静态 HTML 每 tab 一个 <details> 且仅首个 open(无 JS = 手风琴卡片,内容完整);
866
890
  enhance.js 在 <html> 上打 nre-js 后升级为单选 tab 条:收起的 tab 缩成一枚标题排在首行,
867
891
  唯一展开的 tab 以 100% 宽 + order:1 换行到下方,活动标题带高亮下划线、贴着面板顶部。
@@ -3,8 +3,8 @@
3
3
  // (docs/feature/reports/library/built-in.md)。新增内建视图 = 新文件 + 新具名导出,
4
4
  // 不需要注册表,也不改变装载管线。
5
5
 
6
- import { standard } from "./standard.tsx";
6
+ import { standard, standardAttemptPage } from "./standard.tsx";
7
7
 
8
- export { standard };
8
+ export { standard, standardAttemptPage };
9
9
 
10
10
  export default standard;
@@ -1,14 +1,17 @@
1
- // standard —— 内建视图之一:报告 / Attempts / 追踪三页的通用结果站,没有任何私有钩子
2
- // (docs/feature/reports/library/built-in.md)。裸 `niceeval show` 与 `niceeval view`
3
- // 装载的就是它:一份普通 defineReport,与用户的 --report 文件同层、走同一条
1
+ // standard —— 内建视图之一:报告 / Attempts / 追踪三页的通用结果站 + 一张隐藏的 attempt
2
+ // 详情页,没有任何私有钩子(docs/feature/reports/library/built-in.md)。裸 `niceeval show` 与
3
+ // `niceeval view` 装载的就是它:一份普通 defineReport,与用户的 --report 文件同层、走同一条
4
4
  // 装载 → resolve → validate → render 管线。「builtin」不是装载逻辑里的类别,
5
5
  // 只是宿主默认拿哪个值的事实;用户报告经 defineReport({ extends: standard, … }) 整站复用。
6
6
  //
7
- // 三页站点:report(Hero + 警告 + 批量修复 prompt + 实验对比)、attempts(带过滤的
8
- // attempt 全列表)、traces(执行瀑布)。裸宿主导航上能看到的一切内容都在这份定义里;
9
- // 宿主保留的只有机器(docs/feature/reports/architecture.md「宿主保留的只有机器」)。
7
+ // 四页:report(Hero + 警告 + 批量修复 prompt + 实验对比)、attempts(带过滤的 attempt
8
+ // 全列表)、traces(执行瀑布)三页进导航;第四张 standardAttemptPage 以 locator 为输入、
9
+ // 不进导航,locator 深链打开它,content 就是公开的 AttemptDetail 组合组件。裸宿主导航上能
10
+ // 看到的一切内容都在这份定义里;宿主保留的只有机器(docs/feature/reports/architecture.md
11
+ // 「宿主保留的只有机器」)。
10
12
 
11
13
  import {
14
+ AttemptDetail,
12
15
  AttemptList,
13
16
  Col,
14
17
  CopyFixPrompt,
@@ -19,6 +22,14 @@ import {
19
22
  defineReport,
20
23
  } from "../index.ts";
21
24
 
25
+ export const standardAttemptPage = {
26
+ id: "attempt",
27
+ title: "Attempt",
28
+ input: "attempt",
29
+ navigation: false,
30
+ content: <AttemptDetail />,
31
+ } as const;
32
+
22
33
  export const standard = defineReport({
23
34
  pages: [
24
35
  {
@@ -55,5 +66,6 @@ export const standard = defineReport({
55
66
  </Col>
56
67
  ),
57
68
  },
69
+ standardAttemptPage,
58
70
  ],
59
71
  });