niceeval 0.5.4 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/INDEX.md +55 -0
  2. package/dist/agents/types.d.ts +321 -0
  3. package/dist/context/types.d.ts +335 -0
  4. package/dist/i18n/core.d.ts +11 -0
  5. package/dist/i18n/en.d.ts +181 -0
  6. package/dist/i18n/index.d.ts +5 -0
  7. package/dist/i18n/zh-CN.d.ts +183 -0
  8. package/dist/o11y/otlp/parse.d.ts +3 -0
  9. package/dist/o11y/otlp/receiver.d.ts +21 -0
  10. package/dist/o11y/otlp/turn-otel.d.ts +43 -0
  11. package/dist/o11y/types.d.ts +190 -0
  12. package/dist/report/aggregate.d.ts +57 -0
  13. package/dist/report/aggregate.js +212 -0
  14. package/dist/report/built-ins/experiment-comparison.d.ts +1 -0
  15. package/dist/report/built-ins/experiment-comparison.js +13 -0
  16. package/dist/report/built-ins/index.d.ts +1 -0
  17. package/dist/report/built-ins/index.js +2 -0
  18. package/dist/report/components.d.ts +180 -0
  19. package/dist/report/components.js +132 -0
  20. package/dist/report/compute.d.ts +106 -0
  21. package/dist/report/compute.js +600 -0
  22. package/dist/report/flag.d.ts +6 -0
  23. package/dist/report/flag.js +8 -0
  24. package/dist/report/format.d.ts +26 -0
  25. package/dist/report/format.js +109 -0
  26. package/dist/report/index.d.ts +19 -0
  27. package/dist/report/index.js +30 -0
  28. package/dist/report/load.d.ts +12 -0
  29. package/dist/report/load.js +56 -0
  30. package/dist/report/locale.d.ts +94 -0
  31. package/dist/report/locale.js +183 -0
  32. package/dist/report/metrics.d.ts +21 -0
  33. package/dist/report/metrics.js +115 -0
  34. package/dist/report/primitives.d.ts +64 -0
  35. package/dist/report/primitives.js +113 -0
  36. package/dist/report/react/AttemptList.d.ts +23 -0
  37. package/dist/report/react/AttemptList.js +19 -0
  38. package/dist/report/react/DeltaTable.d.ts +8 -0
  39. package/dist/report/react/DeltaTable.js +24 -0
  40. package/dist/report/react/EvalList.d.ts +10 -0
  41. package/dist/report/react/EvalList.js +0 -0
  42. package/dist/report/react/ExperimentList.d.ts +11 -0
  43. package/dist/report/react/ExperimentList.js +67 -0
  44. package/dist/report/react/GroupSummary.d.ts +8 -0
  45. package/dist/report/react/GroupSummary.js +8 -0
  46. package/dist/report/react/MetricBars.d.ts +10 -0
  47. package/dist/report/react/MetricBars.js +48 -0
  48. package/dist/report/react/MetricLine.d.ts +9 -0
  49. package/dist/report/react/MetricLine.js +68 -0
  50. package/dist/report/react/MetricMatrix.d.ts +10 -0
  51. package/dist/report/react/MetricMatrix.js +23 -0
  52. package/dist/report/react/MetricScatter.d.ts +9 -0
  53. package/dist/report/react/MetricScatter.js +96 -0
  54. package/dist/report/react/MetricTable.d.ts +11 -0
  55. package/dist/report/react/MetricTable.js +26 -0
  56. package/dist/report/react/RunOverview.d.ts +8 -0
  57. package/dist/report/react/RunOverview.js +12 -0
  58. package/dist/report/react/Scoreboard.d.ts +8 -0
  59. package/dist/report/react/Scoreboard.js +26 -0
  60. package/dist/report/react/cell.d.ts +9 -0
  61. package/dist/report/react/cell.js +9 -0
  62. package/dist/report/react/chart-math.d.ts +14 -0
  63. package/dist/report/react/chart-math.js +68 -0
  64. package/dist/report/react/colors.d.ts +14 -0
  65. package/dist/report/react/colors.js +45 -0
  66. package/dist/report/react/fixtures.d.ts +19 -0
  67. package/dist/report/react/fixtures.js +398 -0
  68. package/dist/report/react/format.d.ts +3 -0
  69. package/dist/report/react/format.js +7 -0
  70. package/dist/report/react/index.d.ts +6 -0
  71. package/dist/report/react/index.js +14 -0
  72. package/dist/report/report.d.ts +24 -0
  73. package/dist/report/report.js +49 -0
  74. package/dist/report/text/faces.d.ts +29 -0
  75. package/dist/report/text/faces.js +541 -0
  76. package/dist/report/text/layout.d.ts +75 -0
  77. package/dist/report/text/layout.js +173 -0
  78. package/dist/report/text/plot.d.ts +37 -0
  79. package/dist/report/text/plot.js +81 -0
  80. package/dist/report/text/table.d.ts +8 -0
  81. package/dist/report/text/table.js +86 -0
  82. package/dist/report/tree.d.ts +99 -0
  83. package/dist/report/tree.js +228 -0
  84. package/dist/report/types.d.ts +408 -0
  85. package/dist/report/types.js +4 -0
  86. package/dist/report/web.d.ts +15 -0
  87. package/dist/report/web.js +37 -0
  88. package/dist/results/locator.d.ts +75 -0
  89. package/dist/results/locator.js +0 -0
  90. package/dist/results/select.d.ts +45 -0
  91. package/dist/results/select.js +230 -0
  92. package/dist/results/source-hash.d.ts +9 -0
  93. package/dist/results/types.d.ts +204 -0
  94. package/dist/runner/eval-source.d.ts +22 -0
  95. package/dist/runner/fingerprint.d.ts +23 -0
  96. package/dist/runner/types.d.ts +332 -0
  97. package/dist/sandbox/docker-stream.d.ts +24 -0
  98. package/dist/sandbox/docker.d.ts +84 -0
  99. package/dist/sandbox/e2b.d.ts +31 -0
  100. package/dist/sandbox/errors.d.ts +4 -0
  101. package/dist/sandbox/local-files.d.ts +6 -0
  102. package/dist/sandbox/paths.d.ts +4 -0
  103. package/dist/sandbox/registry.d.ts +13 -0
  104. package/dist/sandbox/resolve.d.ts +40 -0
  105. package/dist/sandbox/retry.d.ts +10 -0
  106. package/dist/sandbox/shell.d.ts +11 -0
  107. package/dist/sandbox/source-files.d.ts +13 -0
  108. package/dist/sandbox/types.d.ts +203 -0
  109. package/dist/sandbox/vercel.d.ts +37 -0
  110. package/dist/scoring/types.d.ts +70 -0
  111. package/dist/shared/aggregate.d.ts +29 -0
  112. package/dist/shared/aggregate.js +55 -0
  113. package/dist/shared/types.d.ts +27 -0
  114. package/dist/shared/verdict.d.ts +27 -0
  115. package/dist/shared/verdict.js +34 -0
  116. package/dist/tty-line.d.ts +6 -0
  117. package/dist/types.d.ts +7 -0
  118. package/dist/util.d.ts +22 -0
  119. package/docs-site/zh/concepts/adapter.mdx +7 -7
  120. package/docs-site/zh/concepts/assert.mdx +19 -18
  121. package/docs-site/zh/concepts/evals.mdx +12 -11
  122. package/docs-site/zh/concepts/experiment.mdx +2 -2
  123. package/docs-site/zh/concepts/judge.mdx +9 -9
  124. package/docs-site/zh/concepts/overview.mdx +3 -3
  125. package/docs-site/zh/concepts/tier.mdx +6 -6
  126. package/docs-site/zh/example/claude-code-codex-plugin.mdx +9 -5
  127. package/docs-site/zh/example/claude-code-codex-skill.mdx +12 -7
  128. package/docs-site/zh/guides/agent-feedback-loop.mdx +237 -78
  129. package/docs-site/zh/guides/connect-otel.mdx +3 -3
  130. package/docs-site/zh/guides/connect-your-agent.mdx +2 -2
  131. package/docs-site/zh/guides/custom-reports.mdx +196 -36
  132. package/docs-site/zh/guides/experiments.mdx +7 -1
  133. package/docs-site/zh/guides/fixtures.mdx +4 -2
  134. package/docs-site/zh/guides/official-adapters.mdx +31 -9
  135. package/docs-site/zh/guides/publish-report.mdx +4 -4
  136. package/docs-site/zh/guides/report-components.mdx +194 -55
  137. package/docs-site/zh/guides/reporters.mdx +2 -2
  138. package/docs-site/zh/guides/results-data.mdx +61 -34
  139. package/docs-site/zh/guides/runner.mdx +2 -2
  140. package/docs-site/zh/guides/sandbox-agent.mdx +3 -2
  141. package/docs-site/zh/guides/{sandbox-backends.mdx → sandbox-providers.mdx} +12 -12
  142. package/docs-site/zh/guides/viewing-results.mdx +200 -79
  143. package/docs-site/zh/guides/write-experiment.mdx +9 -1
  144. package/docs-site/zh/guides/write-send.mdx +4 -3
  145. package/docs-site/zh/index.mdx +4 -3
  146. package/docs-site/zh/introduction.mdx +2 -1
  147. package/docs-site/zh/quickstart.mdx +5 -3
  148. package/docs-site/zh/reference/builtin-agents.mdx +38 -13
  149. package/docs-site/zh/reference/capabilities.mdx +1 -1
  150. package/docs-site/zh/reference/cli.mdx +36 -13
  151. package/docs-site/zh/reference/define-agent.mdx +15 -13
  152. package/docs-site/zh/reference/define-config.mdx +1 -1
  153. package/docs-site/zh/reference/define-eval.mdx +3 -3
  154. package/docs-site/zh/reference/events.mdx +9 -3
  155. package/docs-site/zh/reference/expect.mdx +13 -8
  156. package/package.json +10 -6
  157. package/src/agents/bub.ts +129 -42
  158. package/src/agents/claude-code.test.ts +152 -0
  159. package/src/agents/claude-code.ts +127 -13
  160. package/src/agents/codex.test.ts +192 -0
  161. package/src/agents/codex.ts +151 -12
  162. package/src/agents/index.ts +9 -3
  163. package/src/agents/manifest.ts +41 -0
  164. package/src/agents/plugin-config.test.ts +94 -0
  165. package/src/agents/shared.ts +33 -2
  166. package/src/agents/skills.test.ts +214 -0
  167. package/src/agents/skills.ts +304 -0
  168. package/src/agents/streaming.ts +5 -5
  169. package/src/agents/types.ts +59 -3
  170. package/src/cli.ts +74 -47
  171. package/src/context/context.test.ts +20 -2
  172. package/src/context/control-flow.ts +1 -1
  173. package/src/context/session.test.ts +92 -1
  174. package/src/context/session.ts +23 -1
  175. package/src/context/types.ts +4 -4
  176. package/src/define.test.ts +8 -8
  177. package/src/define.ts +11 -11
  178. package/src/expect/index.ts +5 -5
  179. package/src/i18n/en.ts +33 -15
  180. package/src/i18n/zh-CN.ts +37 -21
  181. package/src/index.ts +1 -1
  182. package/src/o11y/execution-tree.test.ts +452 -0
  183. package/src/o11y/execution-tree.ts +367 -0
  184. package/src/o11y/otlp/receiver.ts +1 -1
  185. package/src/o11y/otlp/select.ts +7 -3
  186. package/src/o11y/parsers/claude-code.test.ts +175 -0
  187. package/src/o11y/parsers/claude-code.ts +32 -0
  188. package/src/o11y/types.ts +6 -1
  189. package/src/report/aggregate.ts +26 -20
  190. package/src/report/built-in-user-parity.test.tsx +640 -0
  191. package/src/report/built-ins/experiment-comparison.tsx +19 -0
  192. package/src/report/built-ins/index.ts +2 -0
  193. package/src/report/components.tsx +225 -50
  194. package/src/report/compute.ts +335 -54
  195. package/src/report/dual-render.test.tsx +1129 -0
  196. package/src/report/flag.ts +1 -1
  197. package/src/report/format.ts +35 -2
  198. package/src/report/index.ts +47 -14
  199. package/src/report/load.ts +1 -1
  200. package/src/report/locale.ts +229 -0
  201. package/src/report/metrics.ts +39 -15
  202. package/src/report/primitives.tsx +100 -2
  203. package/src/report/react/AttemptList.tsx +113 -0
  204. package/src/report/react/DeltaTable.tsx +9 -6
  205. package/src/report/react/EvalList.tsx +0 -0
  206. package/src/report/react/ExperimentList.tsx +220 -0
  207. package/src/report/react/GroupSummary.tsx +66 -0
  208. package/src/report/react/MetricBars.tsx +24 -13
  209. package/src/report/react/MetricLine.tsx +21 -21
  210. package/src/report/react/MetricMatrix.tsx +8 -4
  211. package/src/report/react/MetricScatter.tsx +126 -96
  212. package/src/report/react/MetricTable.tsx +115 -15
  213. package/src/report/react/RunOverview.tsx +48 -26
  214. package/src/report/react/Scoreboard.tsx +15 -7
  215. package/src/report/react/cell.tsx +18 -9
  216. package/src/{view/app/lib/chart.ts → report/react/chart-math.ts} +2 -6
  217. package/src/report/react/colors.ts +24 -15
  218. package/src/report/react/enhance.js +168 -0
  219. package/src/report/react/fixtures.ts +169 -34
  220. package/src/report/react/format.ts +1 -1
  221. package/src/report/react/index.tsx +21 -6
  222. package/src/report/react/render.test.tsx +180 -31
  223. package/src/report/react/styles.css +432 -213
  224. package/src/report/report.test.ts +398 -94
  225. package/src/report/report.ts +29 -11
  226. package/src/report/text/faces.ts +344 -96
  227. package/src/report/text/layout.ts +76 -11
  228. package/src/report/text/table.ts +98 -0
  229. package/src/report/tree.ts +103 -20
  230. package/src/report/types.ts +184 -25
  231. package/src/report/web.ts +46 -19
  232. package/src/results/annotated-source.test.ts +146 -0
  233. package/src/results/annotated-source.ts +128 -0
  234. package/src/results/attempt-evidence.test.ts +158 -0
  235. package/src/results/attempt-evidence.ts +158 -0
  236. package/src/results/attempt-source.ts +48 -0
  237. package/src/results/copy.ts +154 -139
  238. package/src/results/format.ts +54 -47
  239. package/src/results/host-equivalence.test.ts +527 -0
  240. package/src/results/index.ts +56 -14
  241. package/src/results/locator.test.ts +198 -0
  242. package/src/results/locator.ts +0 -0
  243. package/src/results/open.ts +392 -175
  244. package/src/results/results.test.ts +943 -494
  245. package/src/results/select.ts +129 -23
  246. package/src/results/skipped-notice.ts +0 -0
  247. package/src/results/source-hash.ts +28 -0
  248. package/src/results/types.ts +98 -62
  249. package/src/results/writer.ts +304 -176
  250. package/src/runner/attempt.test.ts +170 -0
  251. package/src/runner/attempt.ts +48 -13
  252. package/src/runner/discover.test.ts +65 -0
  253. package/src/runner/discover.ts +6 -2
  254. package/src/runner/eval-source.test.ts +121 -0
  255. package/src/runner/eval-source.ts +45 -0
  256. package/src/runner/fingerprint.ts +54 -1
  257. package/src/runner/remote-sandbox.ts +1 -1
  258. package/src/runner/report.test.ts +6 -8
  259. package/src/runner/report.ts +5 -4
  260. package/src/runner/reporters/artifacts.ts +27 -41
  261. package/src/runner/reporters/braintrust.test.ts +3 -3
  262. package/src/runner/reporters/braintrust.ts +1 -1
  263. package/src/runner/reporters/console.ts +6 -6
  264. package/src/runner/reporters/json.ts +4 -4
  265. package/src/runner/reporters/live.test.ts +56 -0
  266. package/src/runner/reporters/live.ts +36 -10
  267. package/src/runner/reporters/quiet.test.ts +66 -0
  268. package/src/runner/reporters/quiet.ts +49 -0
  269. package/src/runner/reporters/shared.ts +5 -5
  270. package/src/runner/reporters/table.ts +17 -17
  271. package/src/runner/run.ts +61 -102
  272. package/src/runner/types.ts +43 -32
  273. package/src/sandbox/checkpoint.ts +1 -1
  274. package/src/sandbox/docker.ts +15 -2
  275. package/src/sandbox/e2b.ts +11 -5
  276. package/src/sandbox/errors.ts +13 -0
  277. package/src/sandbox/index.ts +3 -3
  278. package/src/sandbox/local-files.ts +1 -1
  279. package/src/sandbox/registry.ts +6 -5
  280. package/src/sandbox/resolve.ts +38 -23
  281. package/src/sandbox/retry.test.ts +68 -0
  282. package/src/sandbox/retry.ts +44 -0
  283. package/src/sandbox/types.ts +24 -24
  284. package/src/sandbox/vercel.ts +17 -3
  285. package/src/scoring/collector.ts +3 -3
  286. package/src/scoring/judge.ts +2 -2
  287. package/src/scoring/scoped.ts +13 -1
  288. package/src/scoring/types.ts +7 -7
  289. package/src/scoring/verdict.ts +4 -4
  290. package/src/shared/aggregate.ts +23 -3
  291. package/src/shared/types.ts +2 -2
  292. package/src/shared/{outcome.ts → verdict.ts} +15 -15
  293. package/src/show/compose.ts +12 -132
  294. package/src/show/index.ts +119 -95
  295. package/src/show/render.ts +462 -159
  296. package/src/show/show.test.ts +471 -253
  297. package/src/source-loc.ts +1 -1
  298. package/src/tty-line.ts +32 -0
  299. package/src/types.ts +2 -2
  300. package/src/util.test.ts +21 -1
  301. package/src/util.ts +5 -1
  302. package/src/view/app/App.tsx +33 -198
  303. package/src/view/app/components/AttemptModal.tsx +6 -6
  304. package/src/view/app/components/CodeView.tsx +2 -2
  305. package/src/view/app/components/CopyControls.tsx +32 -36
  306. package/src/view/app/components/SkippedRunsBanner.tsx +140 -0
  307. package/src/view/app/components/ui/badge.tsx +1 -1
  308. package/src/view/app/components/ui/dialog.tsx +2 -2
  309. package/src/view/app/i18n.ts +40 -31
  310. package/src/view/app/lib/artifact-url.ts +1 -1
  311. package/src/view/app/lib/attempt-route.test.ts +37 -47
  312. package/src/view/app/lib/attempt-route.ts +26 -26
  313. package/src/view/app/lib/rows.ts +9 -112
  314. package/src/view/app/lib/verdict.ts +25 -0
  315. package/src/view/app/main.tsx +9 -12
  316. package/src/view/app/pages/RunsPage.tsx +4 -4
  317. package/src/view/app/pages/TracesPage.tsx +3 -3
  318. package/src/view/app/shared.ts +0 -1
  319. package/src/view/app/types.ts +6 -51
  320. package/src/view/artifact-serving.test.ts +136 -0
  321. package/src/view/client-dist/app.css +1 -1
  322. package/src/view/client-dist/app.js +21 -21
  323. package/src/view/data.test.ts +214 -143
  324. package/src/view/data.ts +166 -120
  325. package/src/view/index.ts +23 -11
  326. package/src/view/server.ts +52 -17
  327. package/src/view/shared/types.ts +22 -31
  328. package/src/view/styles.css +117 -327
  329. package/src/view/view-report.test.ts +146 -98
  330. package/src/report/default-report.tsx +0 -222
  331. package/src/report/dual-face.test.tsx +0 -527
  332. package/src/report/react/CaseList.tsx +0 -70
  333. package/src/view/app/components/CostScoreChart.tsx +0 -147
  334. package/src/view/app/components/ExperimentTable.tsx +0 -284
  335. package/src/view/app/components/GroupSelector.tsx +0 -61
  336. package/src/view/app/components/primitives.tsx +0 -43
  337. package/src/view/app/lib/outcome.ts +0 -82
package/src/show/index.ts CHANGED
@@ -1,53 +1,71 @@
1
1
  // niceeval show —— 终端宿主(行为规范:docs-site/zh/guides/viewing-results.mdx;
2
- // 宿主组合语义:docs/reports.md「宿主输入的组合语义」)。
2
+ // 宿主组合语义:docs/feature/reports/architecture.md「Selection 是计算入口」)。
3
3
  //
4
- // 位置参数 = eval id 前缀(选「看哪些 eval」),flag 选「看哪个切面」:
5
- // 裸跑 / 前缀 报告槽 —— 内置默认报告的 text 面(show show --report <内置默认报告>)
4
+ // 位置参数 = eval id 前缀,或 `@<locator>`(精确指名单个 attempt,见 results/locator.ts):
5
+ // 裸跑 / 多 eval 前缀 默认 ExperimentComparison text 面( eval 前缀仍进入详情)
6
6
  // 恰好一个 eval 单 eval 详情(attempt / 断言明细,宿主本体)
7
- // --transcript / --trace / --diff[=路径] 证据切面(宿主本体):出现即走证据室,不渲染报告槽
7
+ // @<locator> 精确 attempt:无证据 flag 紧凑全景;带 flag → 对应证据切面
8
+ // --eval / --execution / --diff[=路径] 证据切面(宿主本体):出现即走证据室,不渲染报告槽
8
9
  // --history 跨 run 时间轴(内置趋势视图),与 --report 互斥
9
- // --report <文件> 整槽换成用户报告;位置前缀 / --run / --experiment 先收窄选集再注入
10
- // --run <目录> 结果根换成该目录;--experiment 选集只留该实验;--attempt 指定详情/证据的 attempt
10
+ // --report <文件> 整槽换成用户报告;位置前缀 / --run / --experiment 先收窄 Selection 再注入
11
+ // --run <目录> 结果根换成该目录;--experiment Selection 只留该实验
11
12
  //
12
- // 数据全部走 niceeval/results 的读取面(openResults + 合成选集),不自己爬目录。
13
+ // 数据全部走 niceeval/results 的读取面(openResults + 合成 Selection + loadAttemptEvidence),
14
+ // 不自己爬目录;证据可用性只由 loadAttemptEvidence 在单 Attempt 页面计算。
13
15
 
14
16
  import { existsSync } from "node:fs";
15
17
  import { join, resolve } from "node:path";
16
- import { openResults, type AttemptRef, type Results } from "../results/index.ts";
17
- import { defineReport, renderReportToText, type ReportDefinition } from "../report/report.ts";
18
- import { ReportLoadError, loadReportFile } from "../report/load.ts";
19
- import { DefaultReport } from "../report/default-report.tsx";
20
- import { t } from "../i18n/index.ts";
21
18
  import {
22
- composeShowSelection,
23
- evalHistory,
24
- experimentHistory,
25
- filterExperiments,
26
- } from "./compose.ts";
19
+ openResults,
20
+ resolveLocator,
21
+ loadAttemptEvidence,
22
+ ATTEMPT_LOCATOR_PREFIX,
23
+ LocatorNotFoundError,
24
+ MalformedLocatorError,
25
+ } from "../results/index.ts";
26
+ // report.ts / load.ts have no JSX of their own, but ReportDefinition / ReportLoadError must
27
+ // come from the SAME module instance ExperimentComparison (built-ins, .tsx) is built
28
+ // against — `unique symbol` branding and `instanceof` are keyed by declaration site, so a raw
29
+ // src copy and the compiled dist copy of "the same" ReportDefinition are, to TypeScript and to
30
+ // `instanceof`, two different types. The package-owned report runtime ships as precompiled
31
+ // ESM (dist/report/**, built by `pnpm run build:report`, immune to a consumer's cwd/tsconfig
32
+ // when niceeval is linked in — see tsconfig.report-build.json); show pulls all of it from
33
+ // there, not just the .tsx-touching pieces.
34
+ import { renderReportToText } from "../../dist/report/report.js";
35
+ import { ExperimentComparison } from "../../dist/report/built-ins/index.js";
36
+ import { ReportLoadError, loadReportFile } from "../../dist/report/load.js";
37
+ import { detectLocale, t } from "../i18n/index.ts";
38
+ import { foldEvalVerdict } from "../shared/verdict.ts";
39
+ import { selectCurrentResults, filterExperiments } from "../results/select.ts";
40
+ import { evalHistory, experimentHistory } from "./compose.ts";
27
41
  import {
28
42
  attemptArtifactsPath,
43
+ attemptEvidenceHeader,
44
+ attemptIndexLine,
45
+ attemptOverviewText,
29
46
  attemptsOfEval,
30
47
  diffText,
31
- displayAttemptNumber,
32
48
  evalDetailText,
33
49
  evalHistoryText,
50
+ evalSourceText,
51
+ executionText,
34
52
  experimentHistoryText,
35
53
  pickDetailAttempt,
36
- traceText,
37
- transcriptText,
54
+ skippedRunsText,
55
+ verdictReasonLine,
38
56
  } from "./render.ts";
39
57
 
40
58
  export interface ShowFlags {
41
- transcript?: boolean;
42
- trace?: boolean;
59
+ /** 该 attempt 运行时保存的 Eval 源码,断言标回源码行(证据切面)。 */
60
+ eval?: boolean;
61
+ /** 该 attempt 的标准执行事件流 + OTel enrichment(证据切面)。 */
62
+ execution?: boolean;
43
63
  /** --diff(文件级摘要)。 */
44
64
  diff?: boolean;
45
65
  /** --diff=<路径>(单个文件的完整改动;路径必须 = 连写,位置参数永远留给 eval id 前缀)。 */
46
66
  diffPath?: string;
47
67
  history?: boolean;
48
68
  experiment?: string;
49
- /** 人看的 1 计序号(详情块显示的 attempt 3 就传 3)。 */
50
- attempt?: number;
51
69
  run?: string;
52
70
  report?: string;
53
71
  }
@@ -63,33 +81,13 @@ export interface ShowIO {
63
81
  /** 可预期的用户错误:打一句英文直说问题与下一步,退出码 1,不抛堆栈。 */
64
82
  class ShowError extends Error {}
65
83
 
66
- /** 内置默认报告:报告槽的出厂填充 —— `niceeval show` ≡ `show --report <这一份>`。 */
67
- const builtinDefaultReport: ReportDefinition = defineReport(() => ({
68
- type: DefaultReport,
69
- props: {},
70
- }));
71
-
72
84
  function clampWidth(columns: number | undefined): number {
73
85
  if (!Number.isFinite(columns) || (columns ?? 0) <= 0) return 80;
74
86
  return Math.max(40, Math.min(columns as number, 160));
75
87
  }
76
88
 
77
89
  // --report 的装载移到中性模块(两个宿主共用),show 的导出面与错误行为不变。
78
- export { loadReportFile } from "../report/load.ts";
79
-
80
- /** 报告里的下钻命令:AttemptRef → `niceeval show <eval id>`(查不到时退 view 深链)。 */
81
- function makeAttemptCommand(results: Results): (ref: AttemptRef) => string {
82
- const byRef = new Map<string, string>();
83
- for (const run of results.runDirs) {
84
- for (const attempt of run.attempts) {
85
- byRef.set(`${attempt.ref.run}/${attempt.ref.result}`, attempt.evalId);
86
- }
87
- }
88
- return (ref) => {
89
- const id = byRef.get(`${ref.run}/${ref.result}`);
90
- return id !== undefined ? `niceeval show ${id}` : `niceeval view "#/attempt/${ref.run}/${ref.result}"`;
91
- };
92
- }
90
+ export { loadReportFile } from "../../dist/report/load.js";
93
91
 
94
92
  export async function runShow(
95
93
  cwd: string,
@@ -122,9 +120,9 @@ async function show(
122
120
  flags: ShowFlags,
123
121
  io: { out: (s: string) => void; err: (s: string) => void; width: number; now: number },
124
122
  ): Promise<void> {
125
- const evidence = flags.transcript === true || flags.trace === true || flags.diff === true || flags.diffPath !== undefined;
123
+ const evidence = flags.eval === true || flags.execution === true || flags.diff === true || flags.diffPath !== undefined;
126
124
 
127
- // 组合语义矩阵(docs/reports.md):--history 与 --report 互斥,先于任何 IO 报出来。
125
+ // 组合语义矩阵(docs/feature/reports/show.md「选择结果范围」):--history 与 --report 互斥,先于任何 IO 报出来。
128
126
  if (flags.history && flags.report !== undefined) {
129
127
  throw new ShowError(t("cli.show.historyReportConflict"));
130
128
  }
@@ -136,13 +134,47 @@ async function show(
136
134
 
137
135
  const results = await openResults(root);
138
136
  if (results.experiments.length === 0) {
139
- const skipped =
140
- results.skipped.length > 0
141
- ? `\n${results.skipped.map((s) => ` skipped ${s.dir} (${s.reason})`).join("\n")}\n`
142
- : "";
137
+ const skipped = results.skipped.length > 0 ? `\n${skippedRunsText(results.skipped, root, cwd)}\n` : "";
143
138
  throw new ShowError(t("cli.show.noResults", { root }) + skipped);
144
139
  }
145
140
 
141
+ // `@<locator>` 位置参数:身份直达单个 attempt,与 eval id 前缀匹配完全不同的语义
142
+ // (`@` 打头对 eval id 天然无歧义,见 locator.ts),必须在下面的前缀匹配逻辑之前分流掉,
143
+ // 不然 "@1x7f3q" 会被当成一个谁都匹配不到的 eval id 前缀,报「no eval match」这种文不对题的
144
+ // 错误。这一步只解析并渲染出「当前 show 对单个已解析 attempt 能渲染的东西」(单 eval 详情 /
145
+ // 三个证据切面)——真正的 `--eval`/`--execution`/`--diff` 统一 attempt 全景是后续阶段。
146
+ const locatorArg = patterns.find((p) => p.startsWith(ATTEMPT_LOCATOR_PREFIX));
147
+ if (locatorArg !== undefined) {
148
+ if (patterns.length !== 1) {
149
+ throw new ShowError(
150
+ `An attempt locator ("${locatorArg}") must be the only positional argument; got ${patterns.length}: ${patterns.join(", ")}.`,
151
+ );
152
+ }
153
+ let attempt;
154
+ try {
155
+ attempt = resolveLocator(results, locatorArg);
156
+ } catch (e) {
157
+ if (e instanceof MalformedLocatorError) throw new ShowError(t("cli.show.locatorMalformed", { message: e.message }));
158
+ if (e instanceof LocatorNotFoundError) throw new ShowError(t("cli.show.locatorNotFound", { message: e.message }));
159
+ throw e;
160
+ }
161
+ const attemptEvidence = await loadAttemptEvidence(attempt);
162
+ const header = attemptEvidenceHeader(attemptEvidence);
163
+ const artifactPath = attemptArtifactsPath(attempt, cwd);
164
+ if (evidence) {
165
+ const blocks: string[] = [];
166
+ if (flags.eval) blocks.push(evalSourceText(attemptEvidence, { header, artifactPath, width: io.width }));
167
+ if (flags.execution) blocks.push(executionText(attemptEvidence, { header, artifactPath, width: io.width }));
168
+ if (flags.diff || flags.diffPath !== undefined) {
169
+ blocks.push(diffText({ header, diff: attemptEvidence.diff, artifactPath, file: flags.diffPath }));
170
+ }
171
+ io.out(blocks.join("\n\n") + "\n");
172
+ return;
173
+ }
174
+ io.out(attemptOverviewText(attemptEvidence, { header, artifactPath, width: io.width }) + "\n");
175
+ return;
176
+ }
177
+
146
178
  if (flags.experiment !== undefined && filterExperiments(results.experiments, flags.experiment).length === 0) {
147
179
  throw new ShowError(
148
180
  t("cli.show.noExperimentMatch", {
@@ -152,7 +184,7 @@ async function show(
152
184
  );
153
185
  }
154
186
 
155
- const selection = composeShowSelection(results, { experiment: flags.experiment, patterns });
187
+ const selection = selectCurrentResults(results, { experiment: flags.experiment, patterns });
156
188
  const matchedEvalIds = [
157
189
  ...new Set(selection.snapshots.flatMap((s) => s.evals.map((e) => e.id))),
158
190
  ].sort();
@@ -169,31 +201,35 @@ async function show(
169
201
  // 证据切面是宿主本体:出现即走证据室,不渲染报告槽(与默认报告同规则)。
170
202
  if (evidence) {
171
203
  if (matchedEvalIds.length !== 1) {
172
- throw new ShowError(t("cli.show.evidenceNeedsEval", { matched: matchedEvalIds.length }));
204
+ // 撞多个 eval 时不止说「有几个」,直接给紧凑索引(locator + 失败原因)
205
+ // 让 agent 一步摘到 `@<locator>`,不必再跑一轮 `show <eval id>` 才知道选谁。
206
+ const index = matchedEvalIds
207
+ .map((evalId) => {
208
+ const attempts = attemptsOfEval(selection.snapshots, evalId);
209
+ const rep = pickDetailAttempt(attempts);
210
+ const verdict = foldEvalVerdict(attempts.map((a) => a.result));
211
+ return attemptIndexLine({
212
+ evalId,
213
+ verdict,
214
+ locator: rep?.locator,
215
+ reason: rep ? verdictReasonLine(rep.result) : undefined,
216
+ });
217
+ })
218
+ .join("\n");
219
+ throw new ShowError(t("cli.show.evidenceNeedsEval", { matched: matchedEvalIds.length, index }));
173
220
  }
174
221
  const evalId = matchedEvalIds[0];
175
222
  const attempts = attemptsOfEval(selection.snapshots, evalId);
176
- const picked = pickDetailAttempt(attempts, flags.attempt);
177
- if (!picked) {
178
- throw new ShowError(
179
- t("cli.show.attemptNotFound", {
180
- attempt: flags.attempt ?? "?",
181
- evalId,
182
- available: attempts.map((a) => displayAttemptNumber(a)).join(", ") || "(none)",
183
- }),
184
- );
185
- }
186
- const header = `attempt ${displayAttemptNumber(picked)} · ${picked.experimentId} · ${picked.result.outcome}`;
223
+ const picked = pickDetailAttempt(attempts);
224
+ if (!picked) throw new Error(`internal error: eval "${evalId}" matched by selection but has no attempts`);
225
+ const attemptEvidence = await loadAttemptEvidence(picked);
226
+ const header = attemptEvidenceHeader(attemptEvidence);
187
227
  const artifactPath = attemptArtifactsPath(picked, cwd);
188
228
  const blocks: string[] = [];
189
- if (flags.transcript) {
190
- blocks.push(transcriptText({ header, events: await picked.events(), artifactPath, width: io.width }));
191
- }
192
- if (flags.trace) {
193
- blocks.push(traceText({ header, spans: await picked.trace(), artifactPath, width: io.width }));
194
- }
229
+ if (flags.eval) blocks.push(evalSourceText(attemptEvidence, { header, artifactPath, width: io.width }));
230
+ if (flags.execution) blocks.push(executionText(attemptEvidence, { header, artifactPath, width: io.width }));
195
231
  if (flags.diff || flags.diffPath !== undefined) {
196
- blocks.push(diffText({ header, diff: await picked.diff(), artifactPath, file: flags.diffPath }));
232
+ blocks.push(diffText({ header, diff: attemptEvidence.diff, artifactPath, file: flags.diffPath }));
197
233
  }
198
234
  io.out(blocks.join("\n\n") + "\n");
199
235
  return;
@@ -219,20 +255,13 @@ async function show(
219
255
  return;
220
256
  }
221
257
 
222
- // 单 eval 详情(宿主本体);--report 在场时报告槽优先,前缀只用来收窄选集。
258
+ // 单 eval 详情(宿主本体);--report 在场时报告槽优先,前缀只用来收窄 Selection。
259
+ // 挑哪个 attempt 展开明细不再收数字 --attempt——pickDetailAttempt 的默认启发式
260
+ // (最新一次失败,没有失败挑最新一次)是唯一路径;精确选某一次走 `@<locator>`。
223
261
  if (flags.report === undefined && patterns.length > 0 && matchedEvalIds.length === 1) {
224
262
  const evalId = matchedEvalIds[0];
225
263
  const attempts = attemptsOfEval(selection.snapshots, evalId);
226
- const detail = pickDetailAttempt(attempts, flags.attempt);
227
- if (flags.attempt !== undefined && !detail) {
228
- throw new ShowError(
229
- t("cli.show.attemptNotFound", {
230
- attempt: flags.attempt,
231
- evalId,
232
- available: attempts.map((a) => displayAttemptNumber(a)).join(", ") || "(none)",
233
- }),
234
- );
235
- }
264
+ const detail = pickDetailAttempt(attempts);
236
265
  io.out(
237
266
  evalDetailText({
238
267
  evalId,
@@ -246,18 +275,13 @@ async function show(
246
275
  return;
247
276
  }
248
277
 
249
- if (flags.attempt !== undefined) {
250
- // --attempt 只对单 eval 的详情/证据生效;报告槽/榜单下无从对位。
251
- throw new ShowError(t("cli.show.attemptNeedsEval"));
252
- }
253
-
254
- // 报告槽:--report 整槽替换,否则内置默认报告(同一条渲染路径)。
255
- const definition =
256
- flags.report !== undefined ? await loadReportFile(cwd, flags.report) : builtinDefaultReport;
257
- const text = await renderReportToText(
258
- definition,
259
- { selection, results },
260
- { width: io.width, attemptCommand: makeAttemptCommand(results) },
261
- );
278
+ // show 与裸 view 选择同一个普通默认 definition,这里只是渲染 text 面。
279
+ // --report 替换同一个报告槽。locale = CLI 界面语言(NICEEVAL_LANG / LC_* / LANG 检测):报告 chrome 文案跟随
280
+ // 终端语言(docs/feature/reports/library.md「locale:渲染面的语言」);Locale 与 ReportLocale 同为
281
+ // "en" | "zh-CN",直接传递。
282
+ const definition = flags.report === undefined ? ExperimentComparison : await loadReportFile(cwd, flags.report);
283
+ // attemptCommand 留给 renderReportToText 的默认值:AttemptLocator 已经是可直接 `niceeval show
284
+ // @<locator>` 的真实 CLI 语法,不需要再反查 eval id 拼一条近似命令(见 tree.ts 的默认实现)。
285
+ const text = await renderReportToText(definition, { selection, results }, { width: io.width, locale: detectLocale() });
262
286
  io.out(text + "\n");
263
287
  }