niceeval 0.6.1 → 0.7.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 (378) hide show
  1. package/INDEX.md +23 -23
  2. package/README.zh.md +6 -6
  3. package/dist/agents/types.d.ts +69 -7
  4. package/dist/context/types.d.ts +32 -12
  5. package/dist/i18n/en.d.ts +54 -0
  6. package/dist/i18n/zh-CN.d.ts +57 -3
  7. package/dist/o11y/types.d.ts +16 -2
  8. package/dist/report/aggregate.d.ts +32 -24
  9. package/dist/report/aggregate.js +158 -50
  10. package/dist/report/built-in/index.d.ts +2 -0
  11. package/dist/report/built-in/index.js +8 -0
  12. package/dist/report/components.d.ts +93 -160
  13. package/dist/report/components.js +377 -114
  14. package/dist/report/compute.d.ts +87 -81
  15. package/dist/report/compute.js +597 -417
  16. package/dist/report/flag.d.ts +32 -6
  17. package/dist/report/flag.js +92 -4
  18. package/dist/report/format.d.ts +19 -11
  19. package/dist/report/format.js +30 -13
  20. package/dist/report/index.d.ts +16 -16
  21. package/dist/report/index.js +20 -21
  22. package/dist/report/load.js +3 -2
  23. package/dist/report/locale.d.ts +57 -33
  24. package/dist/report/locale.js +122 -56
  25. package/dist/report/metrics.d.ts +23 -4
  26. package/dist/report/metrics.js +110 -25
  27. package/dist/report/primitives.d.ts +48 -15
  28. package/dist/report/primitives.js +135 -26
  29. package/dist/report/react/AttemptList.d.ts +9 -7
  30. package/dist/report/react/AttemptList.js +17 -10
  31. package/dist/report/react/DeltaTable.js +19 -18
  32. package/dist/report/react/EvalList.d.ts +4 -4
  33. package/dist/report/react/EvalList.js +0 -0
  34. package/dist/report/react/ExperimentComparison.d.ts +10 -0
  35. package/dist/report/react/ExperimentComparison.js +12 -0
  36. package/dist/report/react/ExperimentList.d.ts +4 -3
  37. package/dist/report/react/ExperimentList.js +17 -18
  38. package/dist/report/react/MetricBars.js +5 -4
  39. package/dist/report/react/MetricLine.js +12 -5
  40. package/dist/report/react/MetricMatrix.js +1 -1
  41. package/dist/report/react/MetricScatter.js +59 -28
  42. package/dist/report/react/MetricTable.js +2 -12
  43. package/dist/report/react/ScopeSummary.d.ts +10 -0
  44. package/dist/report/react/ScopeSummary.js +17 -0
  45. package/dist/report/react/Scoreboard.js +6 -6
  46. package/dist/report/react/cell.js +2 -2
  47. package/dist/report/react/chart-math.d.ts +23 -6
  48. package/dist/report/react/chart-math.js +71 -19
  49. package/dist/report/react/fixtures.d.ts +5 -9
  50. package/dist/report/react/fixtures.js +110 -147
  51. package/dist/report/react/index.d.ts +15 -5
  52. package/dist/report/react/index.js +18 -7
  53. package/dist/report/report.d.ts +137 -16
  54. package/dist/report/report.js +259 -28
  55. package/dist/report/text/faces.d.ts +17 -19
  56. package/dist/report/text/faces.js +253 -184
  57. package/dist/report/text/plot.js +1 -1
  58. package/dist/report/text/table.js +38 -7
  59. package/dist/report/tree.d.ts +90 -40
  60. package/dist/report/tree.js +252 -94
  61. package/dist/report/types.d.ts +247 -284
  62. package/dist/report/types.js +4 -3
  63. package/dist/report/web.d.ts +21 -5
  64. package/dist/report/web.js +42 -16
  65. package/dist/results/select.d.ts +38 -16
  66. package/dist/results/select.js +73 -25
  67. package/dist/results/types.d.ts +49 -14
  68. package/dist/runner/feedback/sink.d.ts +110 -0
  69. package/dist/runner/types.d.ts +513 -22
  70. package/dist/sandbox/docker.d.ts +23 -2
  71. package/dist/sandbox/e2b.d.ts +15 -1
  72. package/dist/sandbox/errors.d.ts +30 -3
  73. package/dist/sandbox/io-retry.d.ts +17 -0
  74. package/dist/sandbox/registry.d.ts +2 -0
  75. package/dist/sandbox/resolve.d.ts +18 -5
  76. package/dist/sandbox/retry.d.ts +11 -1
  77. package/dist/sandbox/types.d.ts +39 -5
  78. package/dist/sandbox/vercel.d.ts +7 -1
  79. package/dist/scoring/coverage.d.ts +30 -0
  80. package/dist/scoring/display.d.ts +21 -0
  81. package/dist/scoring/display.js +120 -0
  82. package/dist/scoring/types.d.ts +103 -20
  83. package/dist/shared/aggregate.d.ts +4 -2
  84. package/dist/shared/aggregate.js +8 -7
  85. package/dist/shared/types.d.ts +28 -0
  86. package/dist/tty-line.d.ts +0 -4
  87. package/dist/util.d.ts +23 -0
  88. package/docs-site/zh/README.md +44 -0
  89. package/docs-site/zh/examples/ai-agent-application.mdx +63 -0
  90. package/docs-site/zh/examples/coding-agent-extensions.mdx +57 -0
  91. package/docs-site/zh/examples/index.mdx +50 -0
  92. package/docs-site/zh/{concepts → explanation}/adapter.mdx +31 -13
  93. package/docs-site/zh/{concepts → explanation}/assert.mdx +7 -7
  94. package/docs-site/zh/{concepts → explanation}/drive.mdx +8 -8
  95. package/docs-site/zh/{concepts → explanation}/evals.mdx +4 -4
  96. package/docs-site/zh/{concepts → explanation}/experiment.mdx +8 -8
  97. package/docs-site/zh/{concepts → explanation}/hitl.mdx +8 -8
  98. package/docs-site/zh/{concepts → explanation}/judge.mdx +5 -5
  99. package/docs-site/zh/{concepts → explanation}/overview.mdx +11 -11
  100. package/docs-site/zh/{guides → explanation}/runner.mdx +18 -8
  101. package/docs-site/zh/{concepts → explanation}/tier.mdx +6 -6
  102. package/docs-site/zh/{guides → how-to}/agent-feedback-loop.mdx +35 -33
  103. package/docs-site/zh/{guides → how-to}/authoring.mdx +35 -2
  104. package/docs-site/zh/{guides → how-to}/ci-integration.mdx +23 -12
  105. package/docs-site/zh/{guides → how-to}/connect-otel.mdx +6 -6
  106. package/docs-site/zh/{guides → how-to}/connect-your-agent.mdx +47 -21
  107. package/docs-site/zh/{guides → how-to}/custom-reports.mdx +34 -39
  108. package/docs-site/zh/{guides → how-to}/dataset-fanout.mdx +25 -3
  109. package/docs-site/zh/{guides → how-to}/experiments.mdx +12 -5
  110. package/docs-site/zh/how-to/publish-report.mdx +105 -0
  111. package/docs-site/zh/{guides → how-to}/reporters.mdx +2 -2
  112. package/docs-site/zh/{guides → how-to}/sandbox-agent.mdx +56 -7
  113. package/docs-site/zh/how-to/sandbox-providers.mdx +350 -0
  114. package/docs-site/zh/{guides → how-to}/scoring-guide.mdx +4 -4
  115. package/docs-site/zh/{guides → how-to}/viewing-results.mdx +82 -39
  116. package/docs-site/zh/{guides → how-to}/write-experiment.mdx +6 -4
  117. package/docs-site/zh/{guides → how-to}/write-send.mdx +30 -14
  118. package/docs-site/zh/index.mdx +24 -26
  119. package/docs-site/zh/introduction.mdx +8 -8
  120. package/docs-site/zh/reference/builtin-agents.mdx +32 -5
  121. package/docs-site/zh/reference/capabilities.mdx +8 -8
  122. package/docs-site/zh/reference/cli.mdx +40 -12
  123. package/docs-site/zh/reference/define-agent.mdx +58 -5
  124. package/docs-site/zh/reference/define-config.mdx +1 -1
  125. package/docs-site/zh/reference/define-eval.mdx +42 -9
  126. package/docs-site/zh/reference/events.mdx +3 -3
  127. package/docs-site/zh/reference/expect.mdx +26 -1
  128. package/docs-site/zh/{guides → reference}/official-adapters.mdx +32 -8
  129. package/docs-site/zh/{guides → reference}/report-components.mdx +45 -33
  130. package/docs-site/zh/{guides → reference}/results-data.mdx +21 -13
  131. package/docs-site/zh/troubleshooting/debug-sandbox.mdx +57 -0
  132. package/docs-site/zh/troubleshooting/debugging.mdx +212 -0
  133. package/docs-site/zh/{quickstart.mdx → tutorials/quickstart.mdx} +5 -17
  134. package/package.json +10 -2
  135. package/src/agents/ai-sdk-otel.test.ts +1 -0
  136. package/src/agents/ai-sdk.test.ts +3 -0
  137. package/src/agents/ai-sdk.ts +3 -0
  138. package/src/agents/bub-install-spec.test.ts +34 -0
  139. package/src/agents/bub-install-spec.ts +32 -0
  140. package/src/agents/bub.ts +31 -32
  141. package/src/agents/claude-code.test.ts +130 -9
  142. package/src/agents/claude-code.ts +76 -4
  143. package/src/agents/codex.test.ts +189 -40
  144. package/src/agents/codex.ts +155 -14
  145. package/src/agents/coding-cli-versions.test.ts +15 -0
  146. package/src/agents/coding-cli-versions.ts +3 -0
  147. package/src/agents/index.ts +13 -2
  148. package/src/agents/langgraph.test.ts +204 -0
  149. package/src/agents/langgraph.ts +495 -0
  150. package/src/agents/marketplace.ts +85 -0
  151. package/src/agents/native-config.test.ts +179 -0
  152. package/src/agents/native-config.ts +267 -0
  153. package/src/agents/openai-compat.test.ts +1 -0
  154. package/src/agents/openai-compat.ts +1 -1
  155. package/src/agents/openclaw.test.ts +31 -0
  156. package/src/agents/openclaw.ts +171 -0
  157. package/src/agents/plugin-config.test.ts +1 -0
  158. package/src/agents/sdk-streams.test.ts +79 -0
  159. package/src/agents/sdk-streams.ts +55 -10
  160. package/src/agents/skills.test.ts +1 -0
  161. package/src/agents/streaming.test.ts +3 -9
  162. package/src/agents/streaming.ts +2 -2
  163. package/src/agents/types.ts +71 -8
  164. package/src/agents/ui-message-stream.test.ts +3 -0
  165. package/src/cli.ts +446 -124
  166. package/src/context/context.test.ts +51 -12
  167. package/src/context/context.ts +162 -30
  168. package/src/context/session.test.ts +2 -1
  169. package/src/context/session.ts +115 -7
  170. package/src/context/types.ts +30 -12
  171. package/src/define.test.ts +13 -8
  172. package/src/define.ts +25 -4
  173. package/src/expect/index.ts +53 -23
  174. package/src/i18n/en.ts +81 -17
  175. package/src/i18n/zh-CN.ts +80 -17
  176. package/src/o11y/cost.test.ts +1 -0
  177. package/src/o11y/execution-tree.test.ts +1 -20
  178. package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
  179. package/src/o11y/otlp/parse.test.ts +1 -0
  180. package/src/o11y/otlp/turn-otel.test.ts +1 -0
  181. package/src/o11y/parsers/bub.test.ts +1 -0
  182. package/src/o11y/parsers/claude-code.test.ts +1 -34
  183. package/src/o11y/parsers/openclaw.test.ts +154 -0
  184. package/src/o11y/parsers/openclaw.ts +310 -0
  185. package/src/o11y/prices.json +746 -311
  186. package/src/o11y/tool-names.test.ts +1 -0
  187. package/src/o11y/types.ts +16 -2
  188. package/src/report/aggregate.ts +178 -61
  189. package/src/report/built-in/index.tsx +9 -0
  190. package/src/report/components.tsx +625 -279
  191. package/src/report/compute.ts +723 -491
  192. package/src/report/dual-render.test.tsx +741 -1024
  193. package/src/report/flag.ts +104 -12
  194. package/src/report/format.ts +32 -12
  195. package/src/report/index.ts +119 -46
  196. package/src/report/load.ts +3 -2
  197. package/src/report/locale.ts +136 -65
  198. package/src/report/metrics.ts +108 -25
  199. package/src/report/primitives.tsx +196 -45
  200. package/src/report/react/AttemptList.tsx +30 -43
  201. package/src/report/react/DeltaTable.tsx +63 -45
  202. package/src/report/react/EvalList.tsx +0 -0
  203. package/src/report/react/ExperimentComparison.tsx +73 -0
  204. package/src/report/react/ExperimentList.tsx +50 -32
  205. package/src/report/react/MetricBars.tsx +5 -4
  206. package/src/report/react/MetricLine.tsx +13 -8
  207. package/src/report/react/MetricMatrix.tsx +2 -2
  208. package/src/report/react/MetricScatter.tsx +86 -34
  209. package/src/report/react/MetricTable.tsx +4 -76
  210. package/src/report/react/ScopeSummary.tsx +86 -0
  211. package/src/report/react/Scoreboard.tsx +28 -10
  212. package/src/report/react/cell.tsx +2 -2
  213. package/src/report/react/chart-math.test.ts +85 -0
  214. package/src/report/react/chart-math.ts +101 -22
  215. package/src/report/react/enhance.js +89 -5
  216. package/src/report/react/fixtures.ts +114 -154
  217. package/src/report/react/index.tsx +24 -39
  218. package/src/report/react/render.test.tsx +138 -158
  219. package/src/report/react/styles.css +243 -82
  220. package/src/report/report.test.ts +779 -841
  221. package/src/report/report.ts +423 -41
  222. package/src/report/text/faces.ts +290 -193
  223. package/src/report/text/plot.ts +1 -1
  224. package/src/report/text/table.ts +44 -7
  225. package/src/report/tree.ts +362 -104
  226. package/src/report/types.ts +261 -271
  227. package/src/report/web.ts +63 -20
  228. package/src/results/annotated-source.test.ts +62 -9
  229. package/src/results/annotated-source.ts +64 -6
  230. package/src/results/attempt-evidence.test.ts +13 -11
  231. package/src/results/attempt-evidence.ts +20 -13
  232. package/src/results/attempt-source.ts +6 -3
  233. package/src/results/copy.ts +150 -60
  234. package/src/results/host-equivalence.test.ts +34 -20
  235. package/src/results/index.ts +12 -4
  236. package/src/results/locator.test.ts +1 -22
  237. package/src/results/open.ts +15 -5
  238. package/src/results/publish.ts +149 -0
  239. package/src/results/results.test.ts +89 -54
  240. package/src/results/select.ts +104 -34
  241. package/src/results/truncate.ts +90 -0
  242. package/src/results/types.ts +43 -14
  243. package/src/results/writer.ts +31 -13
  244. package/src/runner/attempt.test.ts +138 -7
  245. package/src/runner/attempt.ts +603 -104
  246. package/src/runner/discover.test.ts +47 -0
  247. package/src/runner/discover.ts +36 -2
  248. package/src/runner/eval-source.test.ts +1 -27
  249. package/src/runner/feedback/agent.test.ts +504 -0
  250. package/src/runner/feedback/agent.ts +409 -0
  251. package/src/runner/feedback/ci.test.ts +562 -0
  252. package/src/runner/feedback/ci.ts +401 -0
  253. package/src/runner/feedback/coordinator.test.ts +317 -0
  254. package/src/runner/feedback/coordinator.ts +397 -0
  255. package/src/runner/feedback/failure.ts +40 -0
  256. package/src/runner/feedback/human.test.ts +616 -0
  257. package/src/runner/feedback/human.ts +535 -0
  258. package/src/runner/feedback/index.ts +66 -0
  259. package/src/runner/feedback/io.ts +78 -0
  260. package/src/runner/feedback/profile.test.ts +50 -0
  261. package/src/runner/feedback/profile.ts +58 -0
  262. package/src/runner/feedback/reducer.test.ts +395 -0
  263. package/src/runner/feedback/reducer.ts +260 -0
  264. package/src/runner/feedback/renderer.ts +82 -0
  265. package/src/runner/feedback/sink.ts +203 -0
  266. package/src/runner/feedback/testing.ts +106 -0
  267. package/src/runner/ledger.test.ts +230 -0
  268. package/src/runner/ledger.ts +329 -0
  269. package/src/runner/report.test.ts +128 -3
  270. package/src/runner/report.ts +33 -9
  271. package/src/runner/reporters/artifacts.ts +8 -2
  272. package/src/runner/reporters/braintrust.test.ts +8 -7
  273. package/src/runner/reporters/braintrust.ts +9 -2
  274. package/src/runner/reporters/index.ts +2 -2
  275. package/src/runner/reporters/json.test.ts +162 -0
  276. package/src/runner/reporters/json.ts +35 -8
  277. package/src/runner/reporters/shared.ts +1 -5
  278. package/src/runner/run.test.ts +760 -3
  279. package/src/runner/run.ts +243 -37
  280. package/src/runner/sandbox-prep.ts +3 -42
  281. package/src/runner/timing.ts +158 -0
  282. package/src/runner/types.ts +518 -22
  283. package/src/sandbox/checkpoint.test.ts +55 -0
  284. package/src/sandbox/checkpoint.ts +29 -8
  285. package/src/sandbox/cli-commands.ts +407 -0
  286. package/src/sandbox/docker.ts +115 -16
  287. package/src/sandbox/e2b-agent-template.test.ts +56 -0
  288. package/src/sandbox/e2b-agent-template.ts +94 -0
  289. package/src/sandbox/e2b.ts +74 -9
  290. package/src/sandbox/errors.ts +111 -4
  291. package/src/sandbox/index.ts +2 -0
  292. package/src/sandbox/io-retry.test.ts +58 -0
  293. package/src/sandbox/io-retry.ts +45 -0
  294. package/src/sandbox/keep-registry.test.ts +86 -0
  295. package/src/sandbox/keep-registry.ts +142 -0
  296. package/src/sandbox/keep.ts +178 -0
  297. package/src/sandbox/paths.test.ts +1 -0
  298. package/src/sandbox/paths.ts +19 -8
  299. package/src/sandbox/registry.ts +20 -3
  300. package/src/sandbox/resolve.ts +76 -11
  301. package/src/sandbox/retry.test.ts +70 -0
  302. package/src/sandbox/retry.ts +46 -4
  303. package/src/sandbox/types.ts +44 -6
  304. package/src/sandbox/vercel.ts +43 -20
  305. package/src/scoring/collector.ts +60 -17
  306. package/src/scoring/coverage.ts +95 -0
  307. package/src/scoring/diff.ts +81 -0
  308. package/src/scoring/display.test.ts +121 -0
  309. package/src/scoring/display.ts +133 -0
  310. package/src/scoring/evidence.test.ts +189 -0
  311. package/src/scoring/judge.test.ts +142 -0
  312. package/src/scoring/judge.ts +15 -18
  313. package/src/scoring/scoped.ts +217 -50
  314. package/src/scoring/types.ts +117 -20
  315. package/src/scoring/verdict.ts +16 -4
  316. package/src/shared/aggregate.ts +8 -6
  317. package/src/shared/types.ts +31 -0
  318. package/src/show/compose.ts +50 -67
  319. package/src/show/index.ts +127 -56
  320. package/src/show/render.ts +662 -131
  321. package/src/show/report-host.test.ts +188 -0
  322. package/src/show/report-host.ts +375 -0
  323. package/src/show/show.test.ts +320 -54
  324. package/src/tty-line.ts +8 -26
  325. package/src/util.test.ts +1 -0
  326. package/src/util.ts +41 -0
  327. package/src/view/app/App.test.tsx +69 -0
  328. package/src/view/app/App.tsx +144 -48
  329. package/src/view/app/components/AttemptModal.tsx +423 -11
  330. package/src/view/app/components/CodeView.tsx +41 -14
  331. package/src/view/app/components/CopyControls.tsx +2 -2
  332. package/src/view/app/i18n.ts +37 -17
  333. package/src/view/app/lib/attempt-route.test.ts +1 -0
  334. package/src/view/app/lib/verdict.ts +7 -9
  335. package/src/view/app/main.tsx +13 -8
  336. package/src/view/app/pages/{RunsPage.tsx → AttemptsPage.tsx} +6 -6
  337. package/src/view/app/types.ts +4 -1
  338. package/src/view/artifact-serving.test.ts +2 -1
  339. package/src/view/client-dist/app.css +1 -1
  340. package/src/view/client-dist/app.js +17 -17
  341. package/src/view/data.test.ts +10 -3
  342. package/src/view/data.ts +155 -49
  343. package/src/view/index.ts +56 -41
  344. package/src/view/server.ts +37 -15
  345. package/src/view/shared/types.ts +34 -5
  346. package/src/view/styles.css +227 -0
  347. package/src/view/view-report.test.ts +167 -62
  348. package/dist/report/built-ins/experiment-comparison.d.ts +0 -1
  349. package/dist/report/built-ins/experiment-comparison.js +0 -13
  350. package/dist/report/built-ins/index.d.ts +0 -1
  351. package/dist/report/built-ins/index.js +0 -2
  352. package/dist/report/react/GroupSummary.d.ts +0 -8
  353. package/dist/report/react/GroupSummary.js +0 -8
  354. package/dist/report/react/RunOverview.d.ts +0 -8
  355. package/dist/report/react/RunOverview.js +0 -12
  356. package/docs-site/zh/example/ai-agent-application.mdx +0 -152
  357. package/docs-site/zh/example/claude-code-codex-plugin.mdx +0 -167
  358. package/docs-site/zh/example/claude-code-codex-skill.mdx +0 -152
  359. package/docs-site/zh/example/showcase.mdx +0 -39
  360. package/docs-site/zh/guides/publish-report.mdx +0 -91
  361. package/docs-site/zh/guides/sandbox-providers.mdx +0 -102
  362. package/src/report/built-in-user-parity.test.tsx +0 -640
  363. package/src/report/built-ins/experiment-comparison.tsx +0 -19
  364. package/src/report/built-ins/index.ts +0 -2
  365. package/src/report/react/GroupSummary.tsx +0 -66
  366. package/src/report/react/RunOverview.tsx +0 -109
  367. package/src/runner/reporters/console.ts +0 -70
  368. package/src/runner/reporters/live.test.ts +0 -56
  369. package/src/runner/reporters/live.ts +0 -247
  370. package/src/runner/reporters/quiet.test.ts +0 -66
  371. package/src/runner/reporters/quiet.ts +0 -49
  372. package/src/runner/reporters/table.ts +0 -277
  373. /package/docs-site/zh/{example/tier1-ai-sdk-v7.mdx → examples/integrations/ai-sdk-v7.mdx} +0 -0
  374. /package/docs-site/zh/{example/tier1-claude-sdk.mdx → examples/integrations/claude-sdk.mdx} +0 -0
  375. /package/docs-site/zh/{example/tier1-codex-sdk.mdx → examples/integrations/codex-sdk.mdx} +0 -0
  376. /package/docs-site/zh/{example/tier1-langgraph.mdx → examples/integrations/langgraph.mdx} +0 -0
  377. /package/docs-site/zh/{example/tier1-pi-sdk.mdx → examples/integrations/pi-sdk.mdx} +0 -0
  378. /package/docs-site/zh/{guides → how-to}/fixtures.mdx +0 -0
@@ -1,5 +1,5 @@
1
1
  // text 面的字符坐标图:MetricScatter / MetricLine 共用。
2
- // 形态照 docs-site/zh/guides/report-components.mdx 的示例块:y 轴刻度 + │ 边框,
2
+ // 形态照 docs-site/zh/reference/report-components.mdx 的示例块:y 轴刻度 + │ 边框,
3
3
  // 点用字母标注、图例列在图下;lower-better 的轴反向,「好」的角落恒在右上。
4
4
  import { padDisplay, padStartDisplay, stringWidth } from "./layout.js";
5
5
  function makeScale(values, cells, invert) {
@@ -5,8 +5,8 @@
5
5
  //
6
6
  // 列宽按显示宽度算(CJK 记 2 列);null 渲染 —,不补 0;超宽先折最宽的左对齐列,
7
7
  // 压到下限仍放不下就从右侧丢列并如实报数(「截断报剩余」是既有契约,不在这里破例)。
8
- import { countText, localeText } from "../locale.js";
9
- import { renderAlignedRows, stringWidth, wrapDisplay } from "./layout.js";
8
+ import { countText, localeText, resolveLocalizedText } from "../locale.js";
9
+ import { charDisplayWidth, renderAlignedRows, stringWidth, wrapDisplay } from "./layout.js";
10
10
  const MISSING_MARK = "—";
11
11
  /** 列间距,与 renderAlignedRows 的 join(" ") 一致。 */
12
12
  const COLUMN_GAP = 3;
@@ -47,12 +47,36 @@ function fitWidths(natural, align, available) {
47
47
  }
48
48
  return { widths, hidden };
49
49
  }
50
- /** 逻辑行 物理行:每格折到自己的列宽,行高取最高的那格,矮格补空串。 */
51
- function toPhysicalRows(cells, widths) {
50
+ /** 按显示宽度截到 width(不够放 `…` 时原样返回)。 */
51
+ function truncateDisplay(text, width) {
52
+ if (stringWidth(text) <= width)
53
+ return text;
54
+ let out = "";
55
+ let used = 0;
56
+ for (const ch of text) {
57
+ const w = charDisplayWidth(ch.codePointAt(0));
58
+ if (used + w > width)
59
+ break;
60
+ out += ch;
61
+ used += w;
62
+ }
63
+ return out;
64
+ }
65
+ /** 列的 maxLines 收口:超出的行丢弃,最后一行以 `…` 如实标注被收口。 */
66
+ function clampCellLines(lines, maxLines, width) {
67
+ if (maxLines === undefined || lines.length <= maxLines)
68
+ return lines;
69
+ const kept = lines.slice(0, Math.max(1, maxLines));
70
+ const last = kept[kept.length - 1];
71
+ kept[kept.length - 1] = `${truncateDisplay(last, Math.max(1, width - 1))}…`;
72
+ return kept;
73
+ }
74
+ /** 逻辑行 → 物理行:每格折到自己的列宽,列带 maxLines 就收口,行高取最高的那格,矮格补空串。 */
75
+ function toPhysicalRows(cells, widths, maxLines) {
52
76
  const wrapped = cells.map((cell, c) =>
53
77
  // 放得下就原样保留:wrapDisplay 会把连续空格折成一个,而 DeltaTable 的
54
78
  // "50% → 62% +12pp" 这类格子内含固定间距 —— 不折行时一个字节都不能动。
55
- !cell.includes("\n") && stringWidth(cell) <= widths[c] ? [cell] : wrapDisplay(cell, widths[c]));
79
+ clampCellLines(!cell.includes("\n") && stringWidth(cell) <= widths[c] ? [cell] : wrapDisplay(cell, widths[c]), maxLines[c], widths[c]));
56
80
  const height = Math.max(...wrapped.map((lines) => lines.length), 1);
57
81
  const out = [];
58
82
  for (let i = 0; i < height; i++)
@@ -69,7 +93,7 @@ export function renderTableText(props, ctx) {
69
93
  const hasLocator = props.rows.some((row) => row.locator !== undefined);
70
94
  if (props.columns.length === 0 && !hasLocator)
71
95
  return "";
72
- const header = props.columns.map((column) => column.header);
96
+ const header = props.columns.map((column) => resolveLocalizedText(column.header, locale));
73
97
  const align = props.columns.map((column) => column.align ?? "left");
74
98
  const body = props.rows.map((row) => props.columns.map((column) => cellText(row, column.key)));
75
99
  if (hasLocator) {
@@ -80,7 +104,14 @@ export function renderTableText(props, ctx) {
80
104
  const matrix = [header, ...body];
81
105
  const natural = header.map((_, c) => Math.max(...matrix.map((row) => stringWidth(row[c] ?? ""))));
82
106
  const { widths, hidden } = fitWidths(natural, align, ctx.width);
83
- const physical = matrix.flatMap((row) => toPhysicalRows(row.slice(0, widths.length), widths));
107
+ const maxLines = props.columns.map((column) => column.maxLines);
108
+ if (hasLocator)
109
+ maxLines.push(undefined);
110
+ // 表头不参与 maxLines 收口:表头是自己写的短词,收口只服务数据格。
111
+ const physical = [
112
+ ...toPhysicalRows(header.slice(0, widths.length), widths, widths.map(() => undefined)),
113
+ ...body.flatMap((row) => toPhysicalRows(row.slice(0, widths.length), widths, maxLines)),
114
+ ];
84
115
  const table = renderAlignedRows(physical, align);
85
116
  return hidden > 0 ? `${table}\n${countText(locale, "table.columnsHidden", hidden)}` : table;
86
117
  }
@@ -1,16 +1,32 @@
1
1
  import type { ReactNode } from "react";
2
2
  import type { AttemptLocator } from "../results/locator.ts";
3
+ import type { Results, Scope } from "../results/types.ts";
3
4
  import { type ReportLocale } from "./locale.ts";
5
+ import type { ReportInput } from "./types.ts";
6
+ import type { ReportMeta } from "./report.ts";
4
7
  /** 标准 jsx-runtime 元素形状;text 宿主只认 type / props,不管 $$typeof。 */
5
8
  export interface ReportElement {
6
9
  type: unknown;
7
10
  props: Record<string, unknown>;
8
11
  key?: unknown;
9
12
  }
10
- /** 报告树节点:元素、文本、数组 / Fragment 的儿子们,或渲染为空的空值。 */
11
- export type ReportNode = ReportElement | string | number | boolean | null | undefined | ReportNode[];
12
- /** faces 的私有键:text 宿主与树校验靠它识别双面组件。 */
13
+ /**
14
+ * 报告树节点,形状穷尽(docs/feature/reports/library/layout.md「树的节点」):
15
+ * 元素、数组 / Fragment(展平保序),或条件渲染的空分支(渲染为空)。
16
+ * 裸字符串与数字**不是**节点——自由文本必须经 <Text> 携带,树校验遇到时按完整用户反馈拒绝。
17
+ */
18
+ export type ReportNode = ReportElement | readonly ReportNode[] | null | undefined | boolean;
19
+ /** 挂 faces 的私有键:管线与树校验靠它识别双面组件。 */
13
20
  export declare const COMPONENT_FACES: unique symbol;
21
+ /** 挂组合函数的私有键:resolve 阶段靠它识别组合组件。 */
22
+ export declare const COMPONENT_COMPOSE: unique symbol;
23
+ /** Tabs / Tab 的结构角色标记:树校验的配对规则靠它,不 import primitives(避免环)。 */
24
+ export declare const COMPONENT_ROLE: unique symbol;
25
+ /**
26
+ * children 是不透明值(自由文本 / CSS 字符串)而非报告树的组件标记(Text / Style):
27
+ * resolve 与 validate 不下钻它们的 children——那是组件自己的 props,不是树。
28
+ */
29
+ export declare const COMPONENT_RAW_CHILDREN: unique symbol;
14
30
  export interface TextContext {
15
31
  /** 可用列宽;Row 分栏后变窄。 */
16
32
  width: number;
@@ -20,6 +36,11 @@ export interface TextContext {
20
36
  render(node: ReportNode, width?: number): string;
21
37
  /** 下钻命令,通证据室:`niceeval show @<locator>`。 */
22
38
  attemptCommand(locator: AttemptLocator): string;
39
+ /**
40
+ * 组索引一类「按实验收窄」命令的生成;宿主注入以携带完整上下文(--results / --report /
41
+ * --page 与位置参数),默认 `niceeval show --experiment <id>`。非契约字段,官方组件内部用。
42
+ */
43
+ experimentCommand(experimentIdPrefix: string): string;
23
44
  }
24
45
  export interface WebContext {
25
46
  /** 证据室深链,同 view 的 attempt 路由(`#/attempt/@<locator>`,单段、不透明)。 */
@@ -27,73 +48,102 @@ export interface WebContext {
27
48
  /** chrome 文案的 locale;官方组件渲染面经上下文读取,宿主外默认 "en"。 */
28
49
  locale: ReportLocale;
29
50
  }
51
+ /** 双面组件解析面的上下文:宿主注入的数据来源;props 显式给出 input 时以 props 为准。 */
52
+ export interface ResolveContext {
53
+ input: ReportInput;
54
+ }
55
+ /** 组合组件的上下文:宿主 Scope、结果根完整读取面与规范化后的报告声明。 */
56
+ export interface ComposeContext {
57
+ /** 宿主注入的 Scope。 */
58
+ scope: Scope;
59
+ /** 结果根完整读取面;历史视图从这里自行挑 Snapshot[]。 */
60
+ results: Results;
61
+ /** 规范化后的报告声明,只读(docs/feature/reports/library/layout.md「自定义组件」)。 */
62
+ report: ReportMeta;
63
+ }
30
64
  export interface ComponentFaces<P, R = P> {
31
65
  /**
32
- * 可选的数据解析面:把声明式 props(selection + 计算选项)在渲染前解析成纯数据 props(R)
33
- * 宿主的 {@link resolveReportTree} build 之后、validate / render 之前调用它——这是整条
34
- * 管线里唯一允许 await / IO 的组件级步骤;渲染面(web / text)只看已解析的 R,保持同步、零 IO。
35
- * 不实现 resolve 时 R = P,组件被当作纯数据组件直接渲染。
66
+ * 组件唯一的异步 / IO 面:把作者写下的 props 规范化成渲染 props(R)。宿主管线在
67
+ * resolve 阶段调用它,按「同引用 input + 深相等 spec」在一次页渲染内记忆化;
68
+ * 渲染面(web / text)只看已解析的 R,保持同步、零 IO。不实现 resolve 时 R = P
36
69
  */
37
- resolve?(props: P): Promise<R>;
70
+ resolve?(props: P, context: ResolveContext): R | Promise<R>;
38
71
  /** 真 React JSX 在这个面里;返回静态可渲染的 ReactNode。只看已解析的 R。 */
39
72
  web(props: R, ctx: WebContext): ReactNode;
40
73
  text(props: R, ctx: TextContext): string;
41
74
  }
42
75
  /**
43
- * 双面组件的产物:可直接用于 JSX(React 把它当函数组件调用,走 web 面),
44
- * text 宿主经 COMPONENT_FACES 调 text 面。R(解析后 props 形态)在存储边界抹成 any——
76
+ * 报告组件的产物:可直接用于 JSX。双面组件当普通 React 组件调用时走 web 面(只接受
77
+ * 数据形态 props);组合组件只在报告管线内展开,宿主外直接渲染报错。R 在存储边界抹成 any——
45
78
  * 树遍历只按 ComponentFaces 的结构调用 resolve / web / text,不需要在类型层追踪 R。
46
79
  */
47
80
  export type ReportComponent<P> = ((props: P) => ReactNode) & {
48
- [COMPONENT_FACES]: ComponentFaces<P, any>;
81
+ [COMPONENT_FACES]?: ComponentFaces<P, any>;
82
+ [COMPONENT_COMPOSE]?: (props: P, ctx: ComposeContext) => ReportNode | Promise<ReportNode>;
83
+ [COMPONENT_ROLE]?: "tabs" | "tab";
84
+ [COMPONENT_RAW_CHILDREN]?: true;
49
85
  displayName?: string;
50
86
  };
51
87
  /** web 宿主用:在给定 WebContext 下同步渲染(React 静态渲染本身是同步的)。 */
52
88
  export declare function runWithWebContext<T>(ctx: WebContext, fn: () => T): T;
53
89
  /** 官方组件的装配用:宿主上下文激活时才把 ctx.attemptHref 当默认下钻。 */
54
90
  export declare function isHostWebContextActive(): boolean;
55
- /**
56
- * 定义一个双面组件:faces 两键必填 —— 少实现一个面编译不过,配对是结构义务。
57
- * 基础实现不 import react;产物以可调用组件的形状兼容 React 渲染。
58
- */
91
+ /** 函数形态:组合组件,只装配已有组件,可以异步;ctx 携带 scope / results / report。 */
92
+ export declare function defineComponent<P>(compose: (props: P, context: ComposeContext) => ReportNode | Promise<ReportNode>): ReportComponent<P>;
93
+ /** 对象形态:双面组件,自己渲染;text web 两面必填,可选 resolve 承担取数。 */
59
94
  export declare function defineComponent<P, R = P>(faces: ComponentFaces<P, R>): ReportComponent<P>;
60
95
  export declare function facesOf(type: unknown): ComponentFaces<unknown> | undefined;
96
+ export declare function composeOf(type: unknown): ((props: unknown, ctx: ComposeContext) => ReportNode | Promise<ReportNode>) | undefined;
97
+ /**
98
+ * resolve 记忆化的深相等:只递归比较可序列化值(普通对象 / 数组 / 原始值);
99
+ * 函数与 Metric / Dimension / NumericAxis 一类携带函数的实例按引用比较——
100
+ * 共享计算的成立条件是引用同一实例,引用不同的等价定义只是各算一次,不构成错误。
101
+ */
102
+ export declare function deepEqualSpec(a: unknown, b: unknown): boolean;
103
+ /** 一次页渲染内的记忆化缓存:键 = 计算函数引用 → (同引用 input + 深相等 spec) 命中。 */
104
+ export declare class ResolveMemo {
105
+ private readonly entries;
106
+ fetch(fn: unknown, input: unknown, spec: unknown, compute: () => Promise<unknown>): Promise<unknown>;
107
+ }
108
+ /** resolveReportTree 的环境:宿主注入的 Scope / 读取面 / 规范化声明。 */
109
+ export interface ResolveEnv {
110
+ scope: Scope;
111
+ results: Results;
112
+ report: ReportMeta;
113
+ /** 一次页渲染一份;跨页共享缓存时由宿主显式传同一实例。 */
114
+ memo?: ResolveMemo;
115
+ }
116
+ /** 官方 spec 组件在 resolve 内取数的记忆化入口;经内部扩展的 ResolveContext 传递。 */
117
+ export interface InternalResolveContext extends ResolveContext {
118
+ /** 按 (计算函数引用, 同引用 input, 深相等 options) 记忆化地调用计算函数。 */
119
+ memoFetch<T>(dataFn: unknown, input: unknown, options: unknown, compute: () => Promise<T>): Promise<T>;
120
+ }
121
+ /** 组件 resolve 里安全取记忆化入口:经宿主管线时在场,手工直调 resolve 时退化为直接计算。 */
122
+ export declare function memoFetchOf(ctx: ResolveContext): InternalResolveContext["memoFetch"];
61
123
  /**
62
- * 报告 build 之后、树校验与 text/web 渲染之前的解析遍历:把声明式数据组件(实现了
63
- * `faces.resolve` 的双面组件,如 selection 形态的 MetricScatter)的 props
64
- * 就地换成算好的数据形态 props(三个实体列表没有 `resolve` 面,不经这一步——它们的 `items`
65
- * 由报告作者在 `build()` 里直接 `await .data(selection)` 备好)。计算发生在这里(唯一允许
66
- * await 的组件级步骤,连同报告函数体自己的 `build()`),两个渲染面
67
- * 之后都只看已解析的树、保持同步零 IO。遍历形状与 {@link validateReportTree} /
68
- * {@link renderNodeToText} 一致:
69
- *
70
- * - 同层数组兄弟并行解析(`Promise.all`),保持原始顺序 / keys;
71
- * - 双面组件带 resolve 的:调 `faces.resolve(props)` 换 props(有 children 再递归解析);
72
- * - 双面组件无 resolve 的(Row / Col / Section / RunOverview…):只递归 children,自身 props
73
- * 原样保留(title / className 等不能动);
74
- * - 普通函数组件:同步调用展开,展开结果继续解析(与 validate / render 对函数组件的处理一致);
75
- * - 字符串 intrinsic(<div>):原样返回,交给随后的 validateReportTree 报同一条错误。
76
- *
77
- * resolver 跑完后,树里已没有函数组件 / 未解析 props;validate / render 里对这两者的分支在
78
- * 正常管线下是 no-op,但保留着——手搭树直接调 validate / render(不过 resolver)的低层用法仍需要。
124
+ * 管线的 resolve 阶段:递归展开组合组件(以 (props, ctx) 调用并 await 返回树)、执行双面
125
+ * 组件的解析面;同层 sibling 并行取数且不改变节点顺序;带 resolve 的组件按「同引用 input +
126
+ * 深相等 spec」记忆化。非法节点(React 组件、未经 defineComponent 的普通函数、任意 HTML
127
+ * intrinsic)在展开遇到时立即以完整用户反馈拒绝,不为非法节点取数。
79
128
  */
80
- export declare function resolveReportTree(node: ReportNode): Promise<ReportNode>;
129
+ export declare function resolveReportTree(node: ReportNode, env: ResolveEnv): Promise<ReportNode>;
81
130
  /**
82
- * 渲染前树校验:页面树里只放双面组件、排版原语与普通组合函数,字符串 intrinsic
83
- * (<div>)报错、指名组件路径。这是运行时校验而非编译期(标准 JSX 下 TS 把一切
84
- * JSX 表达式统一成 JSX.Element);两个宿主渲染前跑同一遍 —— 不做单侧宽容,否则
85
- * 对着 view 写的页面到 show 才炸。校验只下钻 children(children 就是报告树);
86
- * 普通函数组件调用展开(渲染面纯同步,重复调用无副作用)。
131
+ * 管线的 validate 阶段:确保展开后树中每个组件都有 text 和 web 两面。校验只看节点资格,
132
+ * 不限定树形:根节点可以是单个组件、Col Tabs,宿主不强制任何最外层容器。
133
+ * 裸字符串 / 数字、HTML intrinsic、无两面资格的函数都以完整用户反馈拒绝;
134
+ * Tabs / Tab 的结构配对(空 Tabs、游离 Tab、非 Tab 直接子节点)也在这里校验。
87
135
  */
88
- export declare function validateReportTree(node: ReportNode, path?: string[]): void;
136
+ export declare function validateReportTree(node: ReportNode, path?: string[], insideTabs?: boolean): void;
89
137
  export interface TextRenderOptions {
90
138
  /** 终端可用列宽;默认 80。 */
91
139
  width?: number;
92
140
  /** 下钻命令的生成;宿主注入,默认 `niceeval show @<locator>`(真实可跑的 CLI 语法)。 */
93
141
  attemptCommand?: (locator: AttemptLocator) => string;
142
+ /** 组索引命令的生成;宿主注入以携带 --results / --report / --page 等上下文。 */
143
+ experimentCommand?: (experimentIdPrefix: string) => string;
94
144
  /** chrome 文案的 locale;默认 "en"(`niceeval show` 现有输出不变)。 */
95
145
  locale?: ReportLocale;
96
146
  }
97
147
  export declare function createTextContext(options?: TextRenderOptions): TextContext;
98
- /** text 宿主的遍历渲染:双面组件走 text 面,普通函数调用展开,块之间以换行相接。 */
148
+ /** text 宿主的遍历渲染:双面组件走 text 面,块之间以换行相接。只吃已 resolve + validate 的树。 */
99
149
  export declare function renderNodeToText(node: ReportNode, ctx: TextContext): string;