niceeval 0.8.0 → 0.9.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 (143) hide show
  1. package/INDEX.md +77 -45
  2. package/dist/agents/types.d.ts +28 -6
  3. package/dist/i18n/en.d.ts +2 -0
  4. package/dist/i18n/zh-CN.d.ts +2 -0
  5. package/dist/report/built-in/index.d.ts +3 -2
  6. package/dist/report/built-in/index.js +7 -8
  7. package/dist/report/built-in/standard.d.ts +1 -0
  8. package/dist/report/built-in/standard.js +30 -0
  9. package/dist/report/components.d.ts +72 -6
  10. package/dist/report/components.js +159 -10
  11. package/dist/report/compute.d.ts +31 -4
  12. package/dist/report/compute.js +131 -12
  13. package/dist/report/index.d.ts +4 -4
  14. package/dist/report/index.js +3 -2
  15. package/dist/report/locale.d.ts +39 -1
  16. package/dist/report/locale.js +69 -0
  17. package/dist/report/react/AttemptList.d.ts +3 -1
  18. package/dist/report/react/AttemptList.js +3 -3
  19. package/dist/report/react/CopyFixPrompt.d.ts +12 -0
  20. package/dist/report/react/CopyFixPrompt.js +12 -0
  21. package/dist/report/react/HeroCard.d.ts +13 -0
  22. package/dist/report/react/HeroCard.js +35 -0
  23. package/dist/report/react/PoweredBy.d.ts +5 -0
  24. package/dist/report/react/PoweredBy.js +7 -0
  25. package/dist/report/react/ScopeWarnings.d.ts +12 -0
  26. package/dist/report/react/ScopeWarnings.js +18 -0
  27. package/dist/report/react/TraceWaterfall.d.ts +14 -0
  28. package/dist/report/react/TraceWaterfall.js +22 -0
  29. package/dist/report/react/index.d.ts +6 -1
  30. package/dist/report/react/index.js +6 -0
  31. package/dist/report/report.d.ts +22 -6
  32. package/dist/report/report.js +66 -53
  33. package/dist/report/scope-warnings.d.ts +28 -0
  34. package/dist/report/scope-warnings.js +101 -0
  35. package/dist/report/text/faces.d.ts +19 -1
  36. package/dist/report/text/faces.js +61 -0
  37. package/dist/report/tree.js +6 -1
  38. package/dist/report/types.d.ts +45 -10
  39. package/dist/report/web.d.ts +5 -4
  40. package/dist/report/web.js +7 -22
  41. package/dist/results/select.d.ts +15 -2
  42. package/dist/results/select.js +75 -10
  43. package/dist/results/types.d.ts +26 -11
  44. package/dist/runner/fingerprint.d.ts +3 -3
  45. package/dist/runner/sandbox-selection.d.ts +12 -0
  46. package/dist/runner/types.d.ts +18 -6
  47. package/dist/sandbox/types.d.ts +12 -0
  48. package/docs-site/zh/explanation/evals.mdx +2 -1
  49. package/docs-site/zh/explanation/experiment.mdx +2 -0
  50. package/docs-site/zh/how-to/custom-reports.mdx +22 -6
  51. package/docs-site/zh/how-to/publish-report.mdx +6 -8
  52. package/docs-site/zh/how-to/viewing-results.mdx +3 -3
  53. package/docs-site/zh/how-to/write-experiment.mdx +40 -1
  54. package/docs-site/zh/reference/builtin-agents.mdx +40 -3
  55. package/docs-site/zh/reference/cli.mdx +1 -2
  56. package/docs-site/zh/reference/define-eval.mdx +8 -0
  57. package/docs-site/zh/reference/official-adapters.mdx +10 -5
  58. package/docs-site/zh/reference/report-components.mdx +2 -2
  59. package/docs-site/zh/reference/results-data.mdx +2 -4
  60. package/package.json +2 -1
  61. package/src/agents/bub.ts +13 -1
  62. package/src/agents/claude-code.test.ts +43 -1
  63. package/src/agents/claude-code.ts +32 -14
  64. package/src/agents/codex.test.ts +168 -1
  65. package/src/agents/codex.ts +51 -15
  66. package/src/agents/mcp.ts +31 -0
  67. package/src/agents/post-setup.ts +33 -0
  68. package/src/agents/types.ts +28 -7
  69. package/src/cli.ts +9 -11
  70. package/src/context/context.ts +11 -5
  71. package/src/define.ts +3 -0
  72. package/src/i18n/en.ts +5 -2
  73. package/src/i18n/zh-CN.ts +5 -1
  74. package/src/index.ts +1 -0
  75. package/src/report/built-in/index.tsx +8 -7
  76. package/src/report/built-in/standard.tsx +59 -0
  77. package/src/report/components.tsx +231 -17
  78. package/src/report/compute.ts +146 -21
  79. package/src/report/dual-render.test.tsx +139 -12
  80. package/src/report/index.ts +20 -1
  81. package/src/report/locale.ts +83 -1
  82. package/src/report/react/AttemptList.tsx +13 -1
  83. package/src/report/react/CopyFixPrompt.tsx +37 -0
  84. package/src/report/react/HeroCard.tsx +59 -0
  85. package/src/report/react/PoweredBy.tsx +20 -0
  86. package/src/report/react/ScopeWarnings.tsx +74 -0
  87. package/src/report/react/TraceWaterfall.tsx +78 -0
  88. package/src/report/react/enhance.js +14 -0
  89. package/src/report/react/index.tsx +11 -0
  90. package/src/report/react/styles.css +187 -7
  91. package/src/report/report.test.ts +2 -20
  92. package/src/report/report.ts +97 -62
  93. package/src/report/scope-warnings.ts +155 -0
  94. package/src/report/site-components.test.tsx +526 -0
  95. package/src/report/text/faces.ts +66 -0
  96. package/src/report/tree.ts +8 -1
  97. package/src/report/types.ts +51 -11
  98. package/src/report/web.ts +7 -40
  99. package/src/results/copy.ts +15 -78
  100. package/src/results/host-equivalence.test.ts +5 -1
  101. package/src/results/open.ts +5 -4
  102. package/src/results/publish.ts +4 -146
  103. package/src/results/results.test.ts +86 -9
  104. package/src/results/select.ts +78 -10
  105. package/src/results/types.ts +27 -7
  106. package/src/runner/attempt.ts +10 -9
  107. package/src/runner/discover.test.ts +9 -1
  108. package/src/runner/discover.ts +3 -3
  109. package/src/runner/fingerprint.ts +9 -4
  110. package/src/runner/ledger.test.ts +30 -1
  111. package/src/runner/ledger.ts +26 -4
  112. package/src/runner/run.ts +5 -1
  113. package/src/runner/sandbox-selection.test.ts +131 -0
  114. package/src/runner/sandbox-selection.ts +110 -0
  115. package/src/runner/types.ts +19 -2
  116. package/src/sandbox/types.ts +6 -0
  117. package/src/show/index.ts +17 -10
  118. package/src/show/render.ts +11 -11
  119. package/src/show/report-host.test.ts +32 -15
  120. package/src/show/report-host.ts +5 -4
  121. package/src/show/show.test.ts +140 -3
  122. package/src/view/app/App.test.tsx +78 -17
  123. package/src/view/app/App.tsx +17 -78
  124. package/src/view/app/components/CopyControls.tsx +4 -42
  125. package/src/view/app/i18n.ts +5 -227
  126. package/src/view/app/lib/rows.ts +3 -21
  127. package/src/view/app/shared.ts +1 -3
  128. package/src/view/app/types.ts +2 -2
  129. package/src/view/artifact-serving.test.ts +1 -1
  130. package/src/view/client-dist/app.css +1 -1
  131. package/src/view/client-dist/app.js +20 -20
  132. package/src/view/data.ts +2 -13
  133. package/src/view/index.ts +1 -12
  134. package/src/view/server.ts +0 -2
  135. package/src/view/shared/types.ts +11 -6
  136. package/src/view/site-parity.test.ts +1 -1
  137. package/src/view/site.ts +1 -1
  138. package/src/view/styles.css +6 -266
  139. package/src/view/view-report.test.ts +64 -27
  140. package/src/view/app/components/LazyArtifact.tsx +0 -51
  141. package/src/view/app/components/SkippedRunsBanner.tsx +0 -140
  142. package/src/view/app/pages/AttemptsPage.tsx +0 -80
  143. package/src/view/app/pages/TracesPage.tsx +0 -35
package/src/cli.ts CHANGED
@@ -17,7 +17,7 @@ import { planCarry } from "./runner/fingerprint.ts";
17
17
  import { failureDetailFromResult } from "./runner/feedback/failure.ts";
18
18
  import { stopAllSandboxes, liveSandboxCount } from "./sandbox/registry.ts";
19
19
  import { evalLevelStats } from "./shared/verdict.ts";
20
- import { sandboxRecommendedConcurrency } from "./sandbox/resolve.ts";
20
+ import { prepareRunSandboxes, resolvedSandboxRecommendedConcurrency } from "./runner/sandbox-selection.ts";
21
21
  import { Json, JUnit } from "./runner/reporters/json.ts";
22
22
  import { Artifacts as ArtifactsReporter } from "./runner/reporters/artifacts.ts";
23
23
  import {
@@ -105,7 +105,6 @@ interface Flags {
105
105
  timing?: "summary" | "full";
106
106
  keepSandbox?: "failed" | "all";
107
107
  all: boolean;
108
- allowSensitiveArtifacts: boolean;
109
108
  window?: string;
110
109
  sandboxPath?: string;
111
110
  leaveRunning: boolean;
@@ -156,8 +155,6 @@ const FLAG_OPTIONS = {
156
155
  out: { type: "string" },
157
156
  /** `view` 命令专用:指定本地服务器监听端口。 */
158
157
  port: { type: "string" },
159
- /** `view --out` 专用:对非发布根(快照没有 publish:{redaction:"applied"} 标记)导出时的显式确认——静态站会原样携带未消毒的证据文件。 */
160
- "allow-sensitive-artifacts": { type: "boolean" },
161
158
  // show 的证据切面 / 时间轴 / 报告装载(docs-site/zh/how-to/viewing-results.mdx)。
162
159
  // 证据切面只认 `@<locator>`(或收窄到单个 eval 的前缀)选出的那一个 attempt——不再有
163
160
  // 数字 `--attempt`,选哪个 attempt 由 locator 精确指名,不是「先选 eval 再挑第几次」。
@@ -181,7 +178,7 @@ const FLAG_OPTIONS = {
181
178
  snapshot: { type: "string" },
182
179
  /** `show` / `view` 命令专用:用文件默认导出的 `defineReport(...)` 替换两者共用的默认报告。 */
183
180
  report: { type: "string" },
184
- /** `show` / `view` 命令专用:选择多页报告的页(页 id 见 `show --report` 的页索引);`view` 里定初始页。 */
181
+ /** `show` / `view` 命令专用:选择报告的初始页;`show` 渲染该页并在尾部附其余页索引,`view` 以它作初始路由。未命中的页 id 按用法错误退出并列出可用页 id。 */
185
182
  page: { type: "string" },
186
183
  /** 只打印本次会匹配到的 eval × 运行配置,不实际执行(按下面 `--output` 选中的 profile 给出预览)。 */
187
184
  dry: { type: "boolean" },
@@ -307,7 +304,6 @@ function parseArgs(argv: string[]): { command: string; positionals: string[]; fl
307
304
  timing: values.timing === true ? (timingMode ?? "summary") : undefined,
308
305
  keepSandbox: values["keep-sandbox"] === true ? (keepSandboxTier ?? "failed") : undefined,
309
306
  all: values.all === true,
310
- allowSensitiveArtifacts: values["allow-sensitive-artifacts"] === true,
311
307
  window: values.window as string | undefined,
312
308
  sandboxPath: values.path as string | undefined,
313
309
  leaveRunning: values["leave-running"] === true,
@@ -472,7 +468,7 @@ function evalsFilterFromExperiment(
472
468
  ): (id: string) => boolean {
473
469
  const patternFilter = makeFilter(patterns);
474
470
  let expFilter: (id: string) => boolean = () => true;
475
- if (Array.isArray(evals)) expFilter = (id) => evals.includes(id) || evals.some((e) => id.startsWith(e + "/"));
471
+ if (Array.isArray(evals)) expFilter = makeFilter(evals);
476
472
  else if (typeof evals === "function") expFilter = evals;
477
473
  return (id) => expFilter(id) && patternFilter(id);
478
474
  }
@@ -591,7 +587,7 @@ async function main(): Promise<void> {
591
587
  ...(flags.page !== undefined ? { page: flags.page } : {}),
592
588
  };
593
589
  if (flags.out) {
594
- const out = await buildView({ input: viewInput.input, out: flags.out, allowSensitiveArtifacts: flags.allowSensitiveArtifacts, scan }).catch(exitOnViewUserError);
590
+ const out = await buildView({ input: viewInput.input, out: flags.out, scan }).catch(exitOnViewUserError);
595
591
  process.stdout.write(t("cli.view.exportedDir", { out }));
596
592
  process.exit(0);
597
593
  }
@@ -775,6 +771,9 @@ async function main(): Promise<void> {
775
771
  process.exit(1);
776
772
  }
777
773
 
774
+ // environments 查表在 dry-run 与真实运行共用的规划边界完成;缺表项在任何沙箱/agent 花费前穷举失败。
775
+ prepareRunSandboxes(evals, agentRuns, config.sandbox);
776
+
778
777
  if (flags.dry) {
779
778
  // --dry 只按所选 profile 打印计划,不运行、不落盘 —— 三种 profile 各自的展示逻辑
780
779
  // 都在 runner/feedback/{human,agent,ci}.ts 里,这里只负责拼数据、选函数、写流、退出。
@@ -830,7 +829,7 @@ async function main(): Promise<void> {
830
829
  // envelope 展示的"携入"就会和 run.ts 真实调度的"携入"对不上(见 memory 的
831
830
  // live-carry-row-shows-waiting-forever)。
832
831
  const priorResults = flags.force ? undefined : await loadLatestResultsPerEval(join(cwd, ".niceeval"));
833
- const carryPlan = priorResults?.length ? await planCarry(evals, agentRuns, priorResults) : undefined;
832
+ const carryPlan = priorResults?.length ? await planCarry(evals, agentRuns, priorResults, config.sandbox) : undefined;
834
833
  const reusedFailures = (carryPlan?.carriedResults ?? [])
835
834
  .map(failureDetailFromResult)
836
835
  .filter((failure) => failure !== undefined);
@@ -838,8 +837,7 @@ async function main(): Promise<void> {
838
837
  // 无全局默认:并发上限由 sandbox provider 的推荐值决定(多个 agentRun 各有 sandbox 时取
839
838
  // 最小值,最保守的 provider 决定上限)。同一个值既进 RunFeedbackPlan.shape,也传给 runEvals——
840
839
  // 两处必须是同一个数字,dashboard 展示的并发上限不能和真实调度的并发上限对不上。
841
- const sandboxRecs = agentRuns.map((r) => sandboxRecommendedConcurrency(r.sandbox));
842
- const sandboxDefaultConcurrency = sandboxRecs.length > 0 ? Math.min(...sandboxRecs) : 10;
840
+ const sandboxDefaultConcurrency = resolvedSandboxRecommendedConcurrency(evals, agentRuns, config.sandbox);
843
841
  const maxConcurrency =
844
842
  flags.maxConcurrency ??
845
843
  envNumber("NICEEVAL_MAX_CONCURRENCY") ??
@@ -165,7 +165,7 @@ export function createEvalContext(deps: ContextDeps): { context: TestContext; st
165
165
  return brief(value, 4000);
166
166
  }
167
167
 
168
- /** 失败断言的 evidence:被检查值自带命令摘要(CommandResult.command)时就是「命令行本身」。 */
168
+ /** evidence 不区分 pass/fail(与 judge 同口径):被检查值自带命令摘要(CommandResult.command)时就是「命令行本身」。 */
169
169
  function checkedValueEvidence(value: unknown): string | undefined {
170
170
  const command = asCommandResult(value)?.command;
171
171
  return typeof command === "string" && command.length > 0 ? command : undefined;
@@ -378,12 +378,15 @@ export function createEvalContext(deps: ContextDeps): { context: TestContext; st
378
378
  evaluate: async (sc) => {
379
379
  const resolved = await resolveValue(value, sc);
380
380
  const score = await assertion.score(resolved);
381
- if (computePassed(spec.severity, spec.threshold, score)) return score;
381
+ const evidence = checkedValueEvidence(resolved);
382
+ if (computePassed(spec.severity, spec.threshold, score)) {
383
+ return evidence !== undefined ? { score, evidence } : score;
384
+ }
382
385
  return {
383
386
  score,
384
387
  expected: assertion.expected,
385
388
  received: previewCheckedValue(resolved),
386
- ...(checkedValueEvidence(resolved) !== undefined ? { evidence: checkedValueEvidence(resolved) } : {}),
389
+ ...(evidence !== undefined ? { evidence } : {}),
387
390
  };
388
391
  },
389
392
  };
@@ -395,18 +398,21 @@ export function createEvalContext(deps: ContextDeps): { context: TestContext; st
395
398
  const score = await assertion.score(v);
396
399
  // require 恒为硬门槛(不过即中止 eval),判定口径与 finalize 同一份 computePassed。
397
400
  const passed = computePassed("gate", assertion.threshold, score);
401
+ const evidence = checkedValueEvidence(v);
398
402
  collector.record({
399
403
  name: assertion.name,
400
404
  severity: "gate",
401
405
  threshold: assertion.threshold,
402
406
  evaluate: () =>
403
407
  passed
404
- ? score
408
+ ? evidence !== undefined
409
+ ? { score, evidence }
410
+ : score
405
411
  : {
406
412
  score,
407
413
  expected: assertion.expected,
408
414
  received: previewCheckedValue(v),
409
- ...(checkedValueEvidence(v) !== undefined ? { evidence: checkedValueEvidence(v) } : {}),
415
+ ...(evidence !== undefined ? { evidence } : {}),
410
416
  },
411
417
  });
412
418
  if (!passed) throw new EvalRequirementFailed(assertion.name);
package/src/define.ts CHANGED
@@ -55,6 +55,9 @@ export function defineEval(def: EvalDef): EvalDef {
55
55
  if (typeof def.test !== "function") {
56
56
  throw new Error(t("define.evalTestRequired"));
57
57
  }
58
+ if (def.environment !== undefined && def.environment.trim().length === 0) {
59
+ throw new Error(t("define.evalEnvironmentEmpty"));
60
+ }
58
61
  return def;
59
62
  }
60
63
 
package/src/i18n/en.ts CHANGED
@@ -24,6 +24,8 @@ export const en = {
24
24
  "skill.repoAmbiguous": "Repo skill {{source}} contains multiple skills; select which ones to enable with `skills: [...]`. Available: {{available}}.",
25
25
  "skill.repoUnknownSkill": "Repo skill {{source}} (ref: {{ref}}) has no skill named \"{{skill}}\". Available: {{available}}.",
26
26
  "skill.copyFailed": "Could not install skill \"{{name}}\" into {{dest}}:\n{{tail}}",
27
+ "mcp.ambiguousTransport":
28
+ "MCP server \"{{name}}\" specifies both \"command\" and \"url\" — pick one transport: \"command\" for a local stdio server, \"url\" for a remote Streamable HTTP endpoint.",
27
29
  "plugin.marketplaceFailed": "Could not connect {{agent}} marketplace \"{{name}}\" (source: {{source}}, ref: {{ref}}):\n{{tail}}",
28
30
  "plugin.marketplaceVerifyFailed": "Could not read back the registered marketplace list after adding {{agent}} marketplace \"{{name}}\" ({{command}}):\n{{tail}}",
29
31
  "plugin.marketplaceNameMismatch":
@@ -83,8 +85,8 @@ export const en = {
83
85
  " --diff[=file] sandbox workspace file-change summary; =file expands one file\n" +
84
86
  " --history per experiment × eval execution timeline (mutually exclusive with --report)\n" +
85
87
  " --results <dir> pin a results root --experiment <id> one experiment\n" +
86
- " --report <file> custom report --page <id> pick a page (multi-page\n" +
87
- " reports print a page index with copyable commands)\n" +
88
+ " --report <file> custom report --page <id> pick the initial page (multi-page\n" +
89
+ " reports render it, then list the rest as a page index with copyable commands)\n" +
88
90
  " niceeval list list discovered evals\n" +
89
91
  " niceeval view [eval-id-prefix…] [--out dir] [--port n] [--no-open]\n" +
90
92
  " report pages + evidence rooms; --report <file> swaps in your report\n" +
@@ -151,6 +153,7 @@ export const en = {
151
153
  "context.turnFailedDefault": "This send returned failed (turn status = failed)",
152
154
  "define.agentNameRequired": "defineAgent requires name.",
153
155
  "define.evalIdRejected": "defineEval does not accept id; ids are derived from file paths.",
156
+ "define.evalEnvironmentEmpty": "defineEval environment must be a non-empty profile id when provided.",
154
157
  "define.evalTestRequired": "defineEval requires an async test(t) function.",
155
158
  "define.experimentAgentRequired": "defineExperiment requires agent.",
156
159
  "define.experimentFlagNotJson": "experiment.flags.{{key}} is not JSON-serializable (functions / undefined / cycles / bigint are not allowed); flags are persisted verbatim into result snapshots and must be plain JSON.",
package/src/i18n/zh-CN.ts CHANGED
@@ -22,6 +22,8 @@ export const zhCN = {
22
22
  "skill.repoAmbiguous": "repo skill {{source}} 里有多个 skill,必须用 `skills: [...]` 明确选择要启用哪些。可选:{{available}}。",
23
23
  "skill.repoUnknownSkill": "repo skill {{source}}(ref: {{ref}})里没有名为 \"{{skill}}\" 的 skill。可选:{{available}}。",
24
24
  "skill.copyFailed": "skill \"{{name}}\" 装进 {{dest}} 失败:\n{{tail}}",
25
+ "mcp.ambiguousTransport":
26
+ "MCP server \"{{name}}\" 同时给出了 command 和 url——二选一:本地 stdio 进程写 command,远程 Streamable HTTP 端点写 url。",
25
27
  "plugin.marketplaceFailed": "{{agent}} marketplace \"{{name}}\" 连接失败(source: {{source}}, ref: {{ref}}):\n{{tail}}",
26
28
  "plugin.marketplaceVerifyFailed": "{{agent}} marketplace \"{{name}}\" add 后回读注册列表失败({{command}}):\n{{tail}}",
27
29
  "plugin.marketplaceNameMismatch":
@@ -79,7 +81,8 @@ export const zhCN = {
79
81
  " --diff[=文件] agent 归因的文件改动摘要;=文件 按窗口展开单个文件\n" +
80
82
  " --history 逐 experiment × eval 的执行时间轴(与 --report 互斥)\n" +
81
83
  " --results <目录> 钉死结果根 --experiment <id> 只看该实验\n" +
82
- " --report <文件> 自定义报告 --page <id> 选页(多页报告先输出页索引)\n" +
84
+ " --report <文件> 自定义报告 --page <id> 定初始页(多页报告渲染该页,\n" +
85
+ " 尾部再附其余页索引)\n" +
83
86
  " niceeval list 列出发现到的 eval\n" +
84
87
  " niceeval view [eval-id 前缀…] [--out 目录] [--port n] [--no-open]\n" +
85
88
  " 报告页 + 证据室;--report <文件> 整槽换成自定义报告(与 show 同一文件)\n" +
@@ -145,6 +148,7 @@ export const zhCN = {
145
148
  "context.turnFailedDefault": "本轮 send 返回 failed(turn status = failed)",
146
149
  "define.agentNameRequired": "defineAgent 需要 name。",
147
150
  "define.evalIdRejected": "defineEval 不接受 id —— id 由文件路径推导。",
151
+ "define.evalEnvironmentEmpty": "defineEval 的 environment 如有提供,必须是非空的 profile id。",
148
152
  "define.evalTestRequired": "defineEval 需要一个 async test(t) 函数。",
149
153
  "define.experimentAgentRequired": "defineExperiment 需要 agent。",
150
154
  "define.experimentFlagNotJson": "experiment.flags.{{key}} 不是可 JSON 序列化的值(函数 / undefined / 循环引用 / bigint 不允许);flags 会原样进入结果快照,必须是纯 JSON。",
package/src/index.ts CHANGED
@@ -35,6 +35,7 @@ export type {
35
35
  RunShape,
36
36
  AssertionResult,
37
37
  ExperimentRunInfo,
38
+ SandboxRunInfo,
38
39
  DiffData,
39
40
  DiffView,
40
41
  ScriptResult,
@@ -1,9 +1,10 @@
1
- // niceeval/report/built-in —— 包里自带的一个报告文件,没有任何私有钩子
2
- // (docs/feature/reports/library/built-in.md)。裸 `niceeval show` 与 `niceeval view`
3
- // 装载的就是这份默认导出:一份普通 defineReport,与用户的 --report 文件同层、
4
- // 走同一条 装载 → resolve → validate → render 管线。「builtin」不是装载逻辑里的类别,
5
- // 只是宿主默认拿哪个值的事实。
1
+ // niceeval/report/built-in —— 内建视图的家:每个内建视图是一份普通 defineReport 成品,
2
+ // 有自己的名字、一个源文件,按名字具名导出;默认导出恒等于 standard——裸宿主装载的那份
3
+ // (docs/feature/reports/library/built-in.md)。新增内建视图 = 新文件 + 新具名导出,
4
+ // 不需要注册表,也不改变装载管线。
6
5
 
7
- import { ExperimentComparison, defineReport } from "../index.ts";
6
+ import { standard } from "./standard.tsx";
8
7
 
9
- export default defineReport(<ExperimentComparison />);
8
+ export { standard };
9
+
10
+ export default standard;
@@ -0,0 +1,59 @@
1
+ // standard —— 内建视图之一:报告 / Attempts / 追踪三页的通用结果站,没有任何私有钩子
2
+ // (docs/feature/reports/library/built-in.md)。裸 `niceeval show` 与 `niceeval view`
3
+ // 装载的就是它:一份普通 defineReport,与用户的 --report 文件同层、走同一条
4
+ // 装载 → resolve → validate → render 管线。「builtin」不是装载逻辑里的类别,
5
+ // 只是宿主默认拿哪个值的事实;用户报告经 defineReport({ extends: standard, … }) 整站复用。
6
+ //
7
+ // 三页站点:report(Hero + 警告 + 批量修复 prompt + 实验对比)、attempts(带过滤的
8
+ // attempt 全列表)、traces(执行瀑布)。裸宿主导航上能看到的一切内容都在这份定义里;
9
+ // 宿主保留的只有机器(docs/feature/reports/architecture.md「宿主保留的只有机器」)。
10
+
11
+ import {
12
+ AttemptList,
13
+ Col,
14
+ CopyFixPrompt,
15
+ ExperimentComparison,
16
+ Hero,
17
+ ScopeWarnings,
18
+ TraceWaterfall,
19
+ defineReport,
20
+ } from "../index.ts";
21
+
22
+ export const standard = defineReport({
23
+ pages: [
24
+ {
25
+ id: "report",
26
+ title: { en: "Report", "zh-CN": "报告" },
27
+ content: (
28
+ <Col>
29
+ <Hero />
30
+ <ScopeWarnings />
31
+ <CopyFixPrompt />
32
+ <ExperimentComparison />
33
+ </Col>
34
+ ),
35
+ },
36
+ {
37
+ id: "attempts",
38
+ title: "Attempts",
39
+ content: (
40
+ <Col>
41
+ <Hero />
42
+ <ScopeWarnings />
43
+ <AttemptList filter />
44
+ </Col>
45
+ ),
46
+ },
47
+ {
48
+ id: "traces",
49
+ title: { en: "Traces", "zh-CN": "追踪" },
50
+ content: (
51
+ <Col>
52
+ <Hero />
53
+ <ScopeWarnings />
54
+ <TraceWaterfall />
55
+ </Col>
56
+ ),
57
+ },
58
+ ],
59
+ });