niceeval 0.11.4-canary.20 → 0.12.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 (181) hide show
  1. package/INDEX.md +1 -0
  2. package/dist/i18n/en.d.ts +9 -1
  3. package/dist/i18n/en.js +11 -2
  4. package/dist/i18n/zh-CN.d.ts +10 -2
  5. package/dist/i18n/zh-CN.js +11 -2
  6. package/dist/record/attempt-evidence.d.ts +1 -1
  7. package/dist/record/open.js +25 -0
  8. package/dist/report/assets/series-encoding.d.ts +36 -0
  9. package/dist/report/assets/series-encoding.js +104 -0
  10. package/dist/report/built-in/result-components.js +12 -2
  11. package/dist/report/components/attempt-detail/compute.d.ts +8 -1
  12. package/dist/report/components/attempt-detail/compute.js +19 -1
  13. package/dist/report/components/attempt-detail/index.js +25 -3
  14. package/dist/report/components/attempt-detail/validate.js +3 -2
  15. package/dist/report/components/entity-lists/compute.d.ts +6 -0
  16. package/dist/report/components/entity-lists/compute.js +55 -8
  17. package/dist/report/components/entity-lists/content.d.ts +2 -0
  18. package/dist/report/components/entity-lists/content.js +59 -6
  19. package/dist/report/components/entity-lists/index.d.ts +21 -1
  20. package/dist/report/components/entity-lists/index.js +40 -7
  21. package/dist/report/components/entity-lists/validate.js +21 -0
  22. package/dist/report/components/fixtures.js +2 -0
  23. package/dist/report/definition/cell.d.ts +22 -0
  24. package/dist/report/definition/cell.js +23 -9
  25. package/dist/report/definition/primitives/chart.js +125 -25
  26. package/dist/report/definition/primitives/conversation.d.ts +1 -1
  27. package/dist/report/definition/primitives/conversation.js +5 -3
  28. package/dist/report/definition/primitives.js +32 -7
  29. package/dist/report/definition/tree.d.ts +5 -2
  30. package/dist/report/definition/tree.js +1 -0
  31. package/dist/report/index.d.ts +5 -5
  32. package/dist/report/index.js +2 -2
  33. package/dist/report/model/aggregate.d.ts +14 -1
  34. package/dist/report/model/aggregate.js +34 -2
  35. package/dist/report/model/conversions.d.ts +1 -0
  36. package/dist/report/model/conversions.js +4 -1
  37. package/dist/report/model/format.d.ts +6 -5
  38. package/dist/report/model/format.js +30 -9
  39. package/dist/report/model/locale.d.ts +19 -3
  40. package/dist/report/model/locale.js +31 -5
  41. package/dist/report/model/types.d.ts +41 -4
  42. package/dist/report/presentation.d.ts +53 -6
  43. package/dist/report/presentation.js +40 -5
  44. package/dist/report/react/index.d.ts +3 -3
  45. package/dist/report/react/index.js +1 -1
  46. package/dist/report/slices/compute.js +52 -4
  47. package/dist/report/slices/content.d.ts +2 -1
  48. package/dist/report/slices/content.js +48 -15
  49. package/dist/report/slices/validate.js +23 -0
  50. package/dist/report/tasks.d.ts +7 -1
  51. package/dist/report/tasks.js +5 -3
  52. package/dist/runner/types.d.ts +30 -10
  53. package/dist/sample/index.d.ts +0 -9
  54. package/dist/sample/index.js +0 -18
  55. package/dist/sandbox/backend.d.ts +1 -1
  56. package/dist/sandbox/commands.d.ts +1 -1
  57. package/dist/sandbox/compose.d.ts +2 -1
  58. package/dist/sandbox/docker.d.ts +28 -7
  59. package/dist/sandbox/e2b.d.ts +11 -0
  60. package/dist/sandbox/identity.d.ts +6 -1
  61. package/dist/sandbox/layer.d.ts +36 -3
  62. package/dist/sandbox/local.d.ts +9 -0
  63. package/dist/sandbox/types.d.ts +14 -8
  64. package/dist/sandbox/vercel.d.ts +9 -0
  65. package/docs-site/zh/reference/builtin-agents.mdx +2 -0
  66. package/docs-site/zh/reference/cli.mdx +1 -0
  67. package/docs-site/zh/reference/define-agent.mdx +13 -9
  68. package/docs-site/zh/reference/define-config.mdx +8 -0
  69. package/docs-site/zh/reference/official-adapters.mdx +1 -1
  70. package/docs-site/zh/reference/results-data.mdx +1 -1
  71. package/docs-site/zh/tutorials/deploy-report-site.mdx +157 -0
  72. package/docs-site/zh/tutorials/publish-report.mdx +1 -1
  73. package/docs-site/zh/tutorials/rerun-and-cache.mdx +1 -1
  74. package/docs-site/zh/tutorials/sandbox-providers.mdx +19 -4
  75. package/package.json +1 -1
  76. package/src/agents/codex-env.test.ts +8 -1
  77. package/src/agents/codex.ts +8 -0
  78. package/src/agents/coding-cli-versions.ts +22 -6
  79. package/src/cli.ts +23 -1
  80. package/src/i18n/en.ts +14 -3
  81. package/src/i18n/zh-CN.ts +13 -2
  82. package/src/record/attempt-evidence.ts +1 -1
  83. package/src/record/open.ts +21 -0
  84. package/src/record/results.test.ts +74 -13
  85. package/src/record/truncate.ts +32 -7
  86. package/src/record/writer.ts +39 -8
  87. package/src/report/assets/series-encoding.tsx +177 -0
  88. package/src/report/assets/styles.css +97 -5
  89. package/src/report/built-in/result-components.tsx +23 -2
  90. package/src/report/components/attempt-detail/attempt-components.test.tsx +41 -0
  91. package/src/report/components/attempt-detail/compute.ts +20 -2
  92. package/src/report/components/attempt-detail/index.tsx +32 -2
  93. package/src/report/components/attempt-detail/validate.test.ts +1 -0
  94. package/src/report/components/attempt-detail/validate.tsx +3 -1
  95. package/src/report/components/compute.test.ts +196 -0
  96. package/src/report/components/entity-lists/compute.ts +73 -7
  97. package/src/report/components/entity-lists/content.test.ts +14 -8
  98. package/src/report/components/entity-lists/content.ts +63 -6
  99. package/src/report/components/entity-lists/index.tsx +93 -8
  100. package/src/report/components/entity-lists/validate.test.ts +9 -0
  101. package/src/report/components/entity-lists/validate.ts +16 -0
  102. package/src/report/components/fixtures.ts +2 -0
  103. package/src/report/definition/cell.ts +46 -11
  104. package/src/report/definition/conversation.test.tsx +5 -1
  105. package/src/report/definition/primitives/chart.tsx +197 -32
  106. package/src/report/definition/primitives/conversation.tsx +7 -4
  107. package/src/report/definition/primitives.tsx +81 -9
  108. package/src/report/definition/tree.ts +6 -2
  109. package/src/report/index.ts +15 -2
  110. package/src/report/model/aggregate.ts +40 -2
  111. package/src/report/model/conversions.ts +5 -0
  112. package/src/report/model/format.ts +32 -9
  113. package/src/report/model/locale.ts +35 -5
  114. package/src/report/model/presentation.test.ts +23 -1
  115. package/src/report/model/types.ts +40 -4
  116. package/src/report/presentation.test.tsx +179 -19
  117. package/src/report/presentation.ts +114 -11
  118. package/src/report/react/index.tsx +13 -2
  119. package/src/report/runtime/dual-render.test.tsx +38 -2
  120. package/src/report/slices/compute.ts +59 -4
  121. package/src/report/slices/content.ts +55 -16
  122. package/src/report/slices/delta-table.test.ts +138 -3
  123. package/src/report/slices/validate.test.ts +29 -0
  124. package/src/report/slices/validate.ts +16 -0
  125. package/src/report/tasks.ts +12 -2
  126. package/src/runner/accept.test.ts +328 -10
  127. package/src/runner/accept.ts +239 -72
  128. package/src/runner/attempt.test.ts +25 -13
  129. package/src/runner/attempt.ts +9 -9
  130. package/src/runner/config-identity.test.ts +25 -0
  131. package/src/runner/config-identity.ts +6 -7
  132. package/src/runner/feedback/coordinator.test.ts +51 -0
  133. package/src/runner/feedback/coordinator.ts +23 -0
  134. package/src/runner/feedback/failure.test.ts +15 -0
  135. package/src/runner/feedback/failure.ts +7 -0
  136. package/src/runner/feedback/human.test.ts +548 -27
  137. package/src/runner/feedback/human.ts +321 -47
  138. package/src/runner/feedback/index.ts +10 -0
  139. package/src/runner/feedback/input-guard.test.ts +251 -0
  140. package/src/runner/feedback/input-guard.ts +171 -0
  141. package/src/runner/feedback/reducer.ts +1 -0
  142. package/src/runner/fingerprint.test.ts +24 -0
  143. package/src/runner/gate-lease.test.ts +38 -14
  144. package/src/runner/ledger.test.ts +10 -7
  145. package/src/runner/ledger.ts +9 -2
  146. package/src/runner/lock.test.ts +40 -16
  147. package/src/runner/manifest.ts +8 -9
  148. package/src/runner/reporters/artifacts.ts +25 -3
  149. package/src/runner/run.test.ts +61 -0
  150. package/src/runner/run.ts +34 -9
  151. package/src/runner/sandbox-pool.test.ts +216 -12
  152. package/src/runner/sandbox-pool.ts +20 -2
  153. package/src/runner/types.ts +30 -10
  154. package/src/sample/index.ts +0 -16
  155. package/src/sample/sample.test.ts +78 -0
  156. package/src/sandbox/backend.ts +1 -1
  157. package/src/sandbox/commands.ts +4 -7
  158. package/src/sandbox/compose.test.ts +26 -1
  159. package/src/sandbox/compose.ts +7 -3
  160. package/src/sandbox/docker.test.ts +66 -1
  161. package/src/sandbox/docker.ts +89 -65
  162. package/src/sandbox/dockerfile-build.ts +4 -1
  163. package/src/sandbox/e2b-agent-template.test.ts +18 -1
  164. package/src/sandbox/e2b-agent-template.ts +22 -6
  165. package/src/sandbox/e2b.test.ts +64 -0
  166. package/src/sandbox/e2b.ts +27 -5
  167. package/src/sandbox/identity.ts +7 -2
  168. package/src/sandbox/layer.test.ts +23 -4
  169. package/src/sandbox/layer.ts +127 -43
  170. package/src/sandbox/link.test.ts +5 -2
  171. package/src/sandbox/local.test.ts +8 -8
  172. package/src/sandbox/local.ts +28 -6
  173. package/src/sandbox/operations.test.ts +4 -4
  174. package/src/sandbox/operations.ts +5 -5
  175. package/src/sandbox/runtime.ts +18 -3
  176. package/src/sandbox/types.ts +14 -8
  177. package/src/sandbox/vercel.test.ts +58 -3
  178. package/src/sandbox/vercel.ts +38 -6
  179. package/src/show/index.ts +11 -30
  180. package/src/show/render.test.ts +23 -1
  181. package/src/show/render.ts +6 -3
@@ -1,6 +1,46 @@
1
1
  // 指标视图 TableContent 投影:compute *Data → Table 原语可直接消费的形状。
2
- import { localizedMessage } from "../model/locale.js";
3
- export function deltaTableContent(data) {
2
+ import { DEFAULT_REPORT_LOCALE, localizedMessage } from "../model/locale.js";
3
+ import { formatMetricValue, formatPlainNumber, formatPoints, formatTimeDistance, verdictMark } from "../model/format.js";
4
+ /**
5
+ * 带符号的美元/tokens 差值:复用 `formatMetricValue` 折终值(内建 unit 格式不分 locale,
6
+ * presentation.md「unit 决定格式」),只在外面补一个恒定的正负号——负值 `formatMetricValue`
7
+ * 已经自带 "-",这里只需要给非负值补 "+"。
8
+ */
9
+ function signedMetricText(value, unit) {
10
+ const sign = value > 0 ? "+" : "";
11
+ return `${sign}${formatMetricValue(value, unit)}`;
12
+ }
13
+ /** 带符号的挣分差值("+4 pts" / "-4 pts");`formatPointsSuffix` 恒加 "+" 号,不适用于可能为负的差值。 */
14
+ function signedPointsText(value) {
15
+ const sign = value > 0 ? "+" : value < 0 ? "-" : "";
16
+ const abs = Math.abs(value);
17
+ return `${sign}${formatPlainNumber(abs)} ${abs === 1 ? "pt" : "pts"}`;
18
+ }
19
+ /**
20
+ * 一格的判定读法(docs/feature/reports/show/compare.md):有数据时通过制只留判定符(`bare`,
21
+ * 历史执行再接相对时距)、计分制显示挣分;该条件缺席这道题时,记录里有过期结论参考才给
22
+ * `— <判定符> <时距>`(`—` 不被参考替换,它标记「这一格没有可聚合的结果」,参考只是附注),
23
+ * 没有参考就是纯 `notApplicable`。参考不进任何计数——它压根不出现在 `cells` 里,只在这一格
24
+ * 的显示上多一句附注。
25
+ */
26
+ function conditionVerdictCell(cell, reference, locale) {
27
+ if (!cell) {
28
+ if (!reference)
29
+ return { kind: "notApplicable" };
30
+ const mark = verdictMark(reference.verdict === "skipped" ? "skipped" : reference.verdict);
31
+ return { kind: "text", text: `— ${mark} ${formatTimeDistance(reference.staleSinceMs, locale)}` };
32
+ }
33
+ if (cell.evaluationKind === "points") {
34
+ return { kind: "text", text: cell.totalScore !== undefined ? formatPoints(cell.totalScore) : "—" };
35
+ }
36
+ return {
37
+ kind: "verdict",
38
+ verdict: cell.verdict,
39
+ bare: true,
40
+ ...(cell.historical && cell.staleSinceMs !== undefined ? { staleSinceMs: cell.staleSinceMs } : {}),
41
+ };
42
+ }
43
+ export function deltaTableContent(data, locale = DEFAULT_REPORT_LOCALE) {
4
44
  const conditionColumns = data.conditions.flatMap((condition) => [
5
45
  { key: `${condition}:verdict` },
6
46
  { key: `${condition}:tokens` },
@@ -20,31 +60,24 @@ export function deltaTableContent(data) {
20
60
  };
21
61
  for (const condition of data.conditions) {
22
62
  const cell = row.cells[condition];
23
- cells[`${condition}:verdict`] = cell
24
- ? cell.evaluationKind === "points"
25
- ? {
26
- kind: "text",
27
- text: cell.totalScore !== undefined ? String(cell.totalScore) : "—",
28
- }
29
- : { kind: "verdict", verdict: cell.verdict }
30
- : { kind: "notApplicable" };
63
+ cells[`${condition}:verdict`] = conditionVerdictCell(cell, row.references?.[condition], locale);
31
64
  cells[`${condition}:tokens`] =
32
65
  cell?.totalTokens !== undefined
33
- ? { kind: "text", text: String(cell.totalTokens) }
66
+ ? { kind: "metric", metric: { value: cell.totalTokens, unit: "tokens", basis: "eval", samples: 1, total: 1, refs: cell.attempts } }
34
67
  : { kind: "notApplicable" };
35
68
  cells[`${condition}:cost`] =
36
69
  cell?.totalCostUSD !== undefined
37
- ? { kind: "text", text: String(cell.totalCostUSD) }
70
+ ? { kind: "metric", metric: { value: cell.totalCostUSD, unit: "$", basis: "eval", samples: 1, total: 1, refs: cell.attempts } }
38
71
  : { kind: "notApplicable" };
39
72
  }
40
73
  for (const condition of data.conditions.slice(1)) {
41
74
  const delta = row.delta?.[condition];
42
75
  cells[`${condition}:Δscore`] =
43
- delta?.score !== undefined ? { kind: "text", text: String(delta.score) } : { kind: "notApplicable" };
76
+ delta?.score !== undefined ? { kind: "text", text: signedPointsText(delta.score) } : { kind: "notApplicable" };
44
77
  cells[`${condition}:Δtokens`] =
45
- delta?.tokens !== undefined ? { kind: "text", text: String(delta.tokens) } : { kind: "notApplicable" };
78
+ delta?.tokens !== undefined ? { kind: "text", text: signedMetricText(delta.tokens, "tokens") } : { kind: "notApplicable" };
46
79
  cells[`${condition}:Δcost`] =
47
- delta?.costUSD !== undefined ? { kind: "text", text: String(delta.costUSD) } : { kind: "notApplicable" };
80
+ delta?.costUSD !== undefined ? { kind: "text", text: signedMetricText(delta.costUSD, "$") } : { kind: "notApplicable" };
48
81
  }
49
82
  return { key: row.key, cells };
50
83
  }),
@@ -129,6 +129,20 @@ function deltaCellProblem(value, path) {
129
129
  return `"${path}.totalCostUSD" must be a number`;
130
130
  if (typeof value.historical !== "boolean")
131
131
  return `"${path}.historical" must be a boolean`;
132
+ if (value.staleSinceMs !== undefined && typeof value.staleSinceMs !== "number")
133
+ return `"${path}.staleSinceMs" must be a number`;
134
+ return null;
135
+ }
136
+ /** 缺席格的过期结论参考(与 experiment-table 占位行同一份 StaleConclusionReference 形状)。 */
137
+ function staleReferenceProblem(value, path) {
138
+ if (!isObject(value))
139
+ return `"${path}" must be an object { locator, verdict, staleSinceMs }`;
140
+ if (typeof value.locator !== "string")
141
+ return `"${path}.locator" must be a string`;
142
+ if (typeof value.verdict !== "string")
143
+ return `"${path}.verdict" must be a string`;
144
+ if (typeof value.staleSinceMs !== "number")
145
+ return `"${path}.staleSinceMs" must be a number`;
132
146
  return null;
133
147
  }
134
148
  function deltaTotalsProblem(value, path) {
@@ -206,6 +220,15 @@ export const validateDeltaData = (data) => {
206
220
  return `"${path}.delta.${condition}.costUSD" must be a number`;
207
221
  }
208
222
  }
223
+ if (row.references !== undefined) {
224
+ if (!isObject(row.references))
225
+ return `"${path}.references" must be an object`;
226
+ for (const [condition, reference] of Object.entries(row.references)) {
227
+ const problem = staleReferenceProblem(reference, `${path}.references.${condition}`);
228
+ if (problem !== null)
229
+ return problem;
230
+ }
231
+ }
209
232
  return null;
210
233
  });
211
234
  if (rowsProblem !== null)
@@ -6,7 +6,7 @@ import type { AttemptIdentity } from "../record/locator.ts";
6
6
  import { type SourceContent } from "../record/annotated-source.ts";
7
7
  import type { EvalResult, CommandExitEvidence, PhaseTiming, SandboxBuildRecord, TimingActivity, TraceSpan } from "../types.ts";
8
8
  import { type EvidenceRow, type MetricValue } from "./model/calculation.ts";
9
- import type { AttemptAssertionsData, AttemptConversationData, AttemptDiagnosticsData, AttemptDiffData, AttemptErrorData, AttemptFixPromptData, AttemptSummaryData, AttemptTraceData, DeltaData, ExperimentListItem, HeroData, SampleSummaryContent, StabilityMatrixData, UsageTableData } from "./model/types.ts";
9
+ import type { AttemptAssertionsData, AttemptConversationData, AttemptDiagnosticsData, AttemptDiffData, AttemptErrorData, AttemptFactsData, AttemptFixPromptData, AttemptSummaryData, AttemptTraceData, DeltaData, ExperimentListItem, HeroData, SampleSummaryContent, StabilityMatrixData, UsageTableData } from "./model/types.ts";
10
10
  import type { CalloutGroup } from "./definition/primitives/callouts-logic.ts";
11
11
  import type { CopyBlockContent } from "./definition/primitives/copy-block.tsx";
12
12
  import { type DeltaTableOptions, type StabilityMatrixOptions } from "./slices/compute.ts";
@@ -32,6 +32,11 @@ export interface StandardOverviewResult {
32
32
  summary: SampleSummaryContent;
33
33
  charts: readonly StandardOverviewChartResult[];
34
34
  experiments: readonly ExperimentListItem[];
35
+ /**
36
+ * 「只看新执行」开关的另一态(experiment-table.md「只看新执行」);Sample 里既无历史执行
37
+ * 也无过期结论时为 null——一个永远不改变行集的控件只会让人怀疑自己看漏了什么。
38
+ */
39
+ freshExperiments: readonly ExperimentListItem[] | null;
35
40
  }
36
41
  export interface ComparisonCoverageResult {
37
42
  common: number;
@@ -122,6 +127,7 @@ export interface AttemptDetailsResult {
122
127
  conversation: ConversationResult;
123
128
  diagnostics: AttemptDiagnosticsData | null;
124
129
  usage: UsageResult;
130
+ facts: AttemptFactsData | null;
125
131
  trace: AttemptTraceData | null;
126
132
  diff: DiffResult;
127
133
  }
@@ -7,8 +7,8 @@ import { compactAssertionSummary, primaryAssertionSummary, summaryText } from ".
7
7
  import { firstLine } from "../util.js";
8
8
  import { aggregate, agent, costUSD, experiment, passRate, totalScore, } from "./model/calculation.js";
9
9
  import { attemptCostUSD } from "./model/metrics.js";
10
- import { attemptAssertionsData, attemptConversationData, attemptDiagnosticsData, attemptDiffData, attemptErrorData, attemptFixPromptData, attemptSummaryData, attemptTraceData, usageTableData, } from "./components/attempt-detail/compute.js";
11
- import { experimentListData } from "./components/entity-lists/compute.js";
10
+ import { attemptAssertionsData, attemptConversationData, attemptDiagnosticsData, attemptDiffData, attemptErrorData, attemptFactsData, attemptFixPromptData, attemptSummaryData, attemptTraceData, usageTableData, } from "./components/attempt-detail/compute.js";
11
+ import { experimentListData, hasHistoricalOrStale } from "./components/entity-lists/compute.js";
12
12
  import { sampleSummary } from "./components/summaries/compute.js";
13
13
  import { evaluationKindComposition } from "./model/evaluation-kind.js";
14
14
  import { heroData, } from "./components/site-components/compute.js";
@@ -115,7 +115,8 @@ export async function standardOverviewResult(sample) {
115
115
  experimentListData(sample),
116
116
  Promise.all(chartPromises),
117
117
  ]);
118
- return { hero, notices, diagnostics, fixPrompt, summary, charts, experiments };
118
+ const freshExperiments = hasHistoricalOrStale(experiments) ? await experimentListData(sample.freshOnly()) : null;
119
+ return { hero, notices, diagnostics, fixPrompt, summary, charts, experiments, freshExperiments };
119
120
  }
120
121
  export async function comparisonResult(sample, options) {
121
122
  const data = await deltaTableData(sample, options);
@@ -305,6 +306,7 @@ export async function attemptDetailsResult(attempt) {
305
306
  conversation,
306
307
  diagnostics: attemptDiagnosticsData(attempt),
307
308
  usage,
309
+ facts: attemptFactsData(attempt),
308
310
  trace: attemptTraceData(attempt),
309
311
  diff,
310
312
  };
@@ -1,6 +1,6 @@
1
1
  import type { JsonValue, LocalizedText, ScopedFeedback, SourceArtifact, Verdict } from "../shared/types.ts";
2
2
  import type { AttemptFailureClassifier } from "../shared/failure-class.ts";
3
- import type { O11ySummary, StreamEvent, TraceSpan, Usage } from "../o11y/types.ts";
3
+ import type { O11ySummary, StreamEvent, TraceSpan, Truncation, Usage } from "../o11y/types.ts";
4
4
  import type { Agent, AgentSetupManifest } from "../agents/types.ts";
5
5
  import type { SandboxLayer } from "../sandbox/layer.ts";
6
6
  import type { LinkedRunPlan } from "../sandbox/plan.ts";
@@ -161,10 +161,10 @@ export interface PhaseTiming {
161
161
  }
162
162
  /**
163
163
  * `commands.json` 的一条落盘记录(见 docs/feature/record/architecture.md「commandsjson」):
164
- * 四个公开 `Sandbox.run*()` 方法的最外层调用返回非零 `exitCode` 时,Runner 在
165
- * `CommandResult` 交还调用方**之前**登记的完整证据——Eval 后续即使只把 `.slice(-N)` 拼进
166
- * 异常消息,这份证据仍然完整。只记非零退出;成功命令的输出不进第二份 artifact,provider 内部
167
- * 实现步骤与 Agent 自己调用的 shell 不经过这层包装,不伪装成这里的命令。
164
+ * 四个公开 `Sandbox.run*()` 方法的最外层调用返回时,Runner 在 `CommandResult` 交还调用方
165
+ * **之前**登记的完整证据——Eval 后续即使只把 `.slice(-N)` 拼进异常消息,这份证据仍然完整。
166
+ * 成功与非零退出都记录;provider 内部实现步骤与 Agent 自己调用的 shell 不经过这层包装,
167
+ * 不伪装成这里的命令。
168
168
  */
169
169
  export interface CommandExitEvidence {
170
170
  /** 与 `PhaseTiming.children` 中 `key === "sandbox.command"` 的 `TimingActivity.id` 相同,唯一关联命令证据卡与 `--timing` 的 command 节点。 */
@@ -176,10 +176,14 @@ export interface CommandExitEvidence {
176
176
  exitCode: number;
177
177
  /** 是否由 checked run*OrThrow 公开调用产生;非零 + checked 才是失败展示语义。 */
178
178
  checked: boolean;
179
- /** 不截断落盘;`CommandOptions.sensitiveValues` 命中的已知值已替换为 `<redacted>`。 */
179
+ /** `CommandOptions.sensitiveValues` 命中的已知值已替换为 `<redacted>`;超过每流 64 KiB 时
180
+ * 在落盘序列化时截断,见 `truncated`。 */
180
181
  stdout: string;
181
- /** 不截断落盘,同 `stdout` 的已知敏感值边界。 */
182
+ /** 同 `stdout` 的已知敏感值边界与截断规则。 */
182
183
  stderr: string;
184
+ /** `stdout` / `stderr` 超过每流上限时的结构化截断标记(`path` 为 `"stdout"` 或 `"stderr"`);
185
+ * 只由 writer 在落盘时刻写入,运行时与调用方拿到的仍是完整值。 */
186
+ truncated?: Truncation[];
183
187
  }
184
188
  /** `commands.json` 的落盘形状。 */
185
189
  export type CommandsArtifact = CommandExitEvidence[];
@@ -252,7 +256,7 @@ export interface DiagnosticRecord {
252
256
  }
253
257
  /**
254
258
  * `--accept` 跨过的一条具名差异(`EvalResult.carriedAccepting` 的成员)。
255
- * `selector` 与 CLI 上写下的那个字面量同一个词表,`from` / `to` 是有界值摘要;
259
+ * `selector` 与 CLI 上写下的那个字面量同一个词表,`from` / `to` 是完整值的字符串投影;
256
260
  * 某一侧没有这个键(新增 / 删除)时该侧省略。
257
261
  */
258
262
  export interface CarriedAcceptance {
@@ -281,7 +285,7 @@ export interface AcceptedResult {
281
285
  fingerprint: string;
282
286
  /** 当前项目按本次配置重算出的指纹。 */
283
287
  acceptedFingerprint: string;
284
- /** 新旧 manifest/config 的有界差异摘要。 */
288
+ /** 新旧 manifest/config 的完整差异清单。 */
285
289
  differences: AcceptedDifference[];
286
290
  }
287
291
  /** 自动重试吸收的一次物理 send 失败;不进入逻辑会话事件流。 */
@@ -397,7 +401,7 @@ export interface EvalResult {
397
401
  };
398
402
  /** agent 归因增量:逐 send 窗口的 delta 序列(落盘为 diff.json;文件级视图由读取面派生)。 */
399
403
  diff?: DiffArtifact;
400
- /** 非零 Sandbox 命令的 stdout/stderr 证据(落盘为 commands.json);只记非零退出,见 `CommandExitEvidence`。 */
404
+ /** Sandbox 命令的 stdout/stderr 证据(落盘为 commands.json);成功与非零退出都记录,见 `CommandExitEvidence`。 */
401
405
  commands?: CommandExitEvidence[];
402
406
  rawTranscript?: string;
403
407
  /** 携带条目(--resume 合入)专用:artifact 目录(相对结果根目录),指向原快照里的落盘。 */
@@ -501,6 +505,15 @@ export interface InvocationShape {
501
505
  * 省略只出现在没有携带规划的直调场景。
502
506
  */
503
507
  manifests?: ReadonlyMap<string, RunManifests>;
508
+ /**
509
+ * 本次规划期按 experimentId 算好的 Run 级配置身份(见
510
+ * `config-identity.ts` 的 `configIdentityForRun` / `hashConfigHash`)。同一 experiment 内
511
+ * 全部 eval 共享一个值(configHash 只依赖 run 与 Experiment 作者 layer,不依赖逐 eval 的
512
+ * 物理 provider plan);落盘面据此在建 Run 目录时把它写进 `run.json.configHash`,不再只有
513
+ * `niceeval accept` 显式声明。与 `manifests` 同一条路径:runner 显式递给 reporter,
514
+ * 不由落盘面自己猜。省略只出现在没有携带规划的直调场景。
515
+ */
516
+ configHashes?: ReadonlyMap<string, string>;
504
517
  }
505
518
  export interface Reporter {
506
519
  onEvent?(event: ReporterEvent): void | Promise<void>;
@@ -1255,8 +1268,14 @@ export interface FailureDetail {
1255
1268
  assertion?: PrimaryAssertionSummary;
1256
1269
  /** 仅 errored 使用:结构化执行错误发生时所在的阶段。failed 是断言 outcome,不带 phase。 */
1257
1270
  phase?: LifecyclePhase;
1271
+ /** 仅 errored 且没有结构化主断言摘要(真正的执行错误,而非 assertion-unavailable)时携带:
1272
+ * `AttemptError.code` 原样透出,human 单行事实行拼成 `errored · <phase> · <code>`。 */
1273
+ code?: string;
1258
1274
  /** 完整时间归属;attempt 形态同时投影上面的 phase,run 形态保留共享 timing node。 */
1259
1275
  origin?: TimingOrigin;
1276
+ /** 该 attempt 的 `AttemptRecord.facts` 键数;缺失或为空对象时省略。结束反馈的 FAILURES 面板
1277
+ * 只据此给一条行内提示(有才提示),完整键值表留给 `niceeval show @<locator>`。 */
1278
+ factsCount?: number;
1260
1279
  }
1261
1280
  /** 带发生时间的失败通知;复用失败以 FailureDetail 静态进入 plan,不伪装成刚发生的事件。 */
1262
1281
  export interface FailureNotice extends FailureDetail {
@@ -1479,6 +1498,7 @@ export type DurableFeedbackEvent = {
1479
1498
  reason: string;
1480
1499
  assertion?: PrimaryAssertionSummary;
1481
1500
  phase?: LifecyclePhase;
1501
+ code?: string;
1482
1502
  origin?: TimingOrigin;
1483
1503
  } | {
1484
1504
  type: "diagnostic";
@@ -100,12 +100,3 @@ export declare function isNewerSnapshotPlacement(a: Pick<Run, "startedAt" | "dir
100
100
  * 包内使用,不进公共 barrel。
101
101
  */
102
102
  export declare function filterExperiments(experiments: Experiment[], filter?: string | string[]): Experiment[];
103
- /**
104
- * 时效标注(`↩` + 人话时距)的粒度选择:选粒度最大的单位,四舍五入。结构化形态是单源——
105
- * entity-lists 渲染面的紧凑时距("3d")与曾经的 stale-run message 用同一套阈值,
106
- * 阈值不写两份(docs/feature/reports/library.md「时效标注」)。
107
- */
108
- export declare function gapParts(fromIso: string, toIso: string): {
109
- n: number;
110
- unit: "second" | "minute" | "hour" | "day";
111
- };
@@ -384,21 +384,3 @@ export function filterExperiments(experiments, filter) {
384
384
  const matched = new Set(prefixes.flatMap((p) => matchExperimentSelector(ids, p)));
385
385
  return experiments.filter((exp) => matched.has(exp.id));
386
386
  }
387
- /**
388
- * 时效标注(`↩` + 人话时距)的粒度选择:选粒度最大的单位,四舍五入。结构化形态是单源——
389
- * entity-lists 渲染面的紧凑时距("3d")与曾经的 stale-run message 用同一套阈值,
390
- * 阈值不写两份(docs/feature/reports/library.md「时效标注」)。
391
- */
392
- export function gapParts(fromIso, toIso) {
393
- const ms = Math.max(0, Date.parse(toIso) - Date.parse(fromIso));
394
- const seconds = Math.round(ms / 1000);
395
- if (seconds < 90)
396
- return { n: seconds, unit: "second" };
397
- const minutes = Math.round(seconds / 60);
398
- if (minutes < 90)
399
- return { n: minutes, unit: "minute" };
400
- const hours = Math.round(minutes / 60);
401
- if (hours < 36)
402
- return { n: hours, unit: "hour" };
403
- return { n: Math.round(hours / 24), unit: "day" };
404
- }
@@ -7,7 +7,7 @@ export type SandboxBackendSupport<T> = {
7
7
  readonly _tag: "Unsupported";
8
8
  };
9
9
  export interface SandboxBackendCapabilities {
10
- /** Provider 能否兑现 CommandOptions.root 的提权语义;runner 私有基础设施按这项能力选择身份。 */
10
+ /** Provider 能否兑现 CommandOptions.user 的 root 覆盖;runner 私有基础设施按这项能力选择身份。 */
11
11
  readonly rootCommands: SandboxBackendSupport<true>;
12
12
  readonly appendLog: SandboxBackendSupport<(line: string) => Promise<void>>;
13
13
  readonly suspend: SandboxBackendSupport<() => Promise<void>>;
@@ -5,7 +5,7 @@ export type MaybePromise<T> = T | Promise<T>;
5
5
  export interface SandboxCommandOptions {
6
6
  readonly cwd?: string;
7
7
  readonly env?: Readonly<globalThis.Record<string, string>>;
8
- readonly root?: boolean;
8
+ readonly user?: string;
9
9
  readonly timeoutMs?: number;
10
10
  readonly stdin?: string;
11
11
  }
@@ -175,8 +175,9 @@ export interface DockerComposeProviderMaterializationPlan {
175
175
  readonly evalId: string;
176
176
  readonly profile: string;
177
177
  readonly mainService: string;
178
- readonly executionUser?: string;
178
+ readonly user?: string;
179
179
  readonly env: Readonly<Record<string, string>>;
180
+ readonly pathPrepend?: readonly string[];
180
181
  readonly projectName?: string;
181
182
  readonly collection: ComposeBuildCollection;
182
183
  readonly caseKey: import("./identity.ts").CaseKey;
@@ -43,10 +43,15 @@ export interface DockerSandboxOptions {
43
43
  */
44
44
  workdir?: string;
45
45
  /**
46
- * 默认执行身份。`"image"` = 容器镜像声明的 USER(空则 root)——Terminal-Bench 等
47
- * 需要改系统文件的 Compose main 必须用它;省略 = 内置非 root `SANDBOX_USER`。
46
+ * 覆盖整个 Sandbox 的默认执行身份;省略时沿用镜像 `USER`(未声明按 Docker 语义是 root)、
47
+ * Compose service `user:` 或其镜像 `USER`。
48
48
  */
49
- executionUser?: "image" | string;
49
+ user?: string;
50
+ /**
51
+ * 按序前置到受管 `PATH` 的目录;省略 = 不改 PATH(见 docs/feature/sandbox/library.md
52
+ * 「PATH:受管变量与 pathPrepend」)。
53
+ */
54
+ pathPrepend?: readonly string[];
50
55
  }
51
56
  /** `stop()` 时是否销毁容器。Compose 主容器由资源组 `compose down` 回收,附着句柄只松绑。 */
52
57
  export type DockerSandboxReleaseMode = "destroy" | "detach";
@@ -71,10 +76,16 @@ export declare class DockerSandbox implements SandboxProviderBackend, SandboxReu
71
76
  private provisionToken?;
72
77
  private runIdentity?;
73
78
  private releaseMode;
74
- /** 默认 docker exec User;`opts.root` 仍可提到 root。 */
75
- private defaultUser;
79
+ /** 起点覆盖(factory `user`);省略 = 沿用镜像/Compose 声明的默认身份。 */
80
+ private readonly userOverride?;
81
+ /** factory `pathPrepend`;按声明顺序前置到受管 PATH,省略 = 空数组。 */
82
+ private readonly pathPrepend;
83
+ /** 下面三项由 `resolveDefaultIdentity()` 探测得出,构造期先给出安全占位值。 */
76
84
  private defaultHome;
77
85
  private defaultUserName;
86
+ private defaultIsRoot;
87
+ private npmGlobalDir;
88
+ private sandboxPath;
78
89
  readonly capabilities: {
79
90
  rootCommands: import("./backend.ts").SandboxBackendSupport<true>;
80
91
  appendLog: import("./backend.ts").SandboxBackendSupport<(line: string) => Promise<void>>;
@@ -89,6 +100,8 @@ export declare class DockerSandbox implements SandboxProviderBackend, SandboxReu
89
100
  setCommandDeadline: import("./backend.ts").SandboxBackendSupport<(deadlineAt?: number) => void>;
90
101
  };
91
102
  constructor(options?: DockerSandboxOptions);
103
+ /** 受管 PATH:`pathPrepend` 按声明顺序前置到 npm 全局 bin + 系统默认路径。 */
104
+ private managedPath;
92
105
  /** 复用下由池在每次借出时换成承接者自己的 deadline(见 sandbox/deadline.ts)。 */
93
106
  setCommandDeadline(deadlineAt?: number): void;
94
107
  /**
@@ -113,6 +126,14 @@ export declare class DockerSandbox implements SandboxProviderBackend, SandboxReu
113
126
  static create(options?: DockerSandboxOptions): Promise<DockerSandbox>;
114
127
  /** 拉镜像、起容器、装基础工具、备好工作区与 npm 前缀。 */
115
128
  private initialize;
129
+ /**
130
+ * 探测 Sandbox 默认执行身份(`this.userOverride` 未设置时即容器/镜像的默认身份)的
131
+ * uid、用户名与家目录:省略 `User` 字段的 exec 沿用容器默认身份,`$HOME` 由容器内
132
+ * `/etc/passwd` 解析,不在 runner 侧维护一张 UID → 家目录的映射表。
133
+ */
134
+ private resolveDefaultIdentity;
135
+ /** chown 目标:factory 覆盖时原样复用(接受 name / uid[:gid]),否则用探测出的用户名。 */
136
+ private chownTarget;
116
137
  /** 确保镜像在本地,缺了就拉。 */
117
138
  private ensureImage;
118
139
  /**
@@ -126,8 +147,8 @@ export declare class DockerSandbox implements SandboxProviderBackend, SandboxReu
126
147
  /** 容器短 ID(像 Docker CLI 那样取前 12 位)。 */
127
148
  get sandboxId(): string;
128
149
  /**
129
- * 在容器里跑一条命令。默认以非 root 的 node 用户跑;`opts.root` 为真则以 root 跑
130
- * (setup 装系统依赖用)。
150
+ * 在容器里跑一条命令。默认沿用 Sandbox 的默认执行身份(factory `user` 覆盖后的身份,
151
+ * 否则镜像声明的 USER);`opts.user` 只覆盖这一条命令。
131
152
  */
132
153
  runCommand(cmd: string, args?: readonly string[], opts?: CommandOptions): Promise<CommandResult>;
133
154
  /** 以 root 跑命令(provider 内部用:容器初始化、属主收敛)。 */
@@ -19,6 +19,13 @@ interface E2BSandboxCreateOptions {
19
19
  readonly deadlineAt?: number;
20
20
  readonly runtime?: "node20" | "node24";
21
21
  readonly template?: string;
22
+ /** 覆盖整个 Sandbox 的默认执行身份;省略时沿用 template 的默认用户。 */
23
+ readonly user?: string;
24
+ /**
25
+ * 按序前置到受管 `PATH` 的目录;省略 = 不改 PATH(见 docs/feature/sandbox/library.md
26
+ * 「PATH:受管变量与 pathPrepend」)。
27
+ */
28
+ readonly pathPrepend?: readonly string[];
22
29
  readonly provisionToken?: string;
23
30
  /** 运行时已解析的实例寿命;bounded attempt 不能退回 E2B 的 SDK 默认值。 */
24
31
  readonly lifetime: E2BSandboxLifetime;
@@ -44,6 +51,10 @@ export declare class E2BSandbox implements SandboxProviderBackend, SandboxReuseC
44
51
  private retired;
45
52
  /** 已实际请求的实例寿命;复用下续期一律续到这个值(滑动窗口)。 */
46
53
  private lifetime;
54
+ /** 起点覆盖(factory `user`);省略 = 沿用 template 的默认用户。 */
55
+ private readonly userOverride?;
56
+ /** factory `pathPrepend`;按声明顺序前置到受管 PATH,省略 = 空数组。 */
57
+ private readonly pathPrepend;
47
58
  readonly sandboxId: string;
48
59
  private deadlineAt?;
49
60
  readonly capabilities: {
@@ -30,7 +30,12 @@ export interface CaseKeyInput {
30
30
  readonly composeBytes?: string;
31
31
  readonly overlayBytes?: string;
32
32
  readonly buildKeys: readonly BuildKey[];
33
- readonly serviceImageDigests?: Readonly<globalThis.Record<string, string>>;
33
+ /**
34
+ * 无 build 的 Compose service 的声明 image ref(已 pin 时含 digest,未 pin 时是原始 tag 文本)。
35
+ * 只收声明值——不得填入 `docker inspect` 等本地 daemon 解析出的实际 digest,否则并行 docker
36
+ * 活动会让身份在两次独立规划之间漂移(见 memory/compose-case-identity-digest-flap.md)。
37
+ */
38
+ readonly serviceImageRefs?: Readonly<globalThis.Record<string, string>>;
34
39
  readonly bindMountDigests?: Readonly<globalThis.Record<string, string>>;
35
40
  /** env_file / config / secret 的非敏感内容(或内容摘要)。 */
36
41
  readonly configContents?: Readonly<globalThis.Record<string, string>>;
@@ -22,7 +22,8 @@ export interface DockerComposeSandboxOptions {
22
22
  readonly file: string | URL;
23
23
  readonly workspaceService: string;
24
24
  readonly build?: "on-demand" | "prebuilt";
25
- readonly executionUser?: string;
25
+ /** 覆盖整个 Sandbox 的默认执行身份;省略时沿用 Compose service `user:` 或其镜像 `USER`。 */
26
+ readonly user?: string;
26
27
  readonly env?: Readonly<globalThis.Record<string, string>>;
27
28
  /** Compose 插值所需凭据;value 只进私有 runtime binding,identity 只认变量名与 revision。 */
28
29
  readonly credentialEnv?: Readonly<globalThis.Record<string, {
@@ -30,27 +31,50 @@ export interface DockerComposeSandboxOptions {
30
31
  readonly revision?: string;
31
32
  }>>;
32
33
  readonly lifetimeMs?: number;
34
+ /**
35
+ * 按序前置到受管 `PATH` 的目录;作用于本 Sandbox 内全部受管命令(agent 进程、两层 prepare、
36
+ * ensure/install),hooks 与子进程自然继承。PATH 本身是受管变量,不接受经 `env` 覆盖——
37
+ * 需要扩展 PATH 用这个字段(见 docs/feature/sandbox/library.md「PATH:受管变量与
38
+ * pathPrepend」)。省略 = 不改 PATH。
39
+ */
40
+ readonly pathPrepend?: readonly string[];
33
41
  }
34
42
  export interface DockerfileSandboxOptions {
35
43
  readonly context: string | URL;
36
44
  readonly dockerfile?: string;
37
45
  readonly buildArgs?: Readonly<globalThis.Record<string, string>>;
46
+ /** 覆盖整个 Sandbox 的默认执行身份;省略时沿用构建出的镜像 `USER`。 */
47
+ readonly user?: string;
38
48
  readonly lifetimeMs?: number;
49
+ /** 按序前置到受管 `PATH` 的目录;省略 = 不改 PATH(见 docs/feature/sandbox/library.md)。 */
50
+ readonly pathPrepend?: readonly string[];
39
51
  }
40
52
  export interface DockerImageSandboxOptions {
41
53
  readonly image: string;
54
+ /** 覆盖整个 Sandbox 的默认执行身份;省略时沿用镜像 `USER`(未声明按 Docker 语义是 root)。 */
55
+ readonly user?: string;
42
56
  readonly lifetimeMs?: number;
57
+ /** 按序前置到受管 `PATH` 的目录;省略 = 不改 PATH(见 docs/feature/sandbox/library.md)。 */
58
+ readonly pathPrepend?: readonly string[];
43
59
  }
44
60
  export interface E2BSandboxOptions {
45
61
  readonly template: string;
62
+ /** 覆盖整个 Sandbox 的默认执行身份;省略时沿用 template 的默认用户。 */
63
+ readonly user?: string;
46
64
  readonly lifetimeMs?: number;
65
+ /** 按序前置到受管 `PATH` 的目录;省略 = 不改 PATH(见 docs/feature/sandbox/library.md)。 */
66
+ readonly pathPrepend?: readonly string[];
47
67
  }
48
68
  export interface VercelSandboxOptions {
49
69
  readonly snapshotId: string;
50
70
  readonly lifetimeMs?: number;
71
+ /** 按序前置到受管 `PATH` 的目录;省略 = 不改 PATH(见 docs/feature/sandbox/library.md)。 */
72
+ readonly pathPrepend?: readonly string[];
51
73
  }
52
74
  export interface LocalSandboxOptions {
53
75
  readonly dir?: string;
76
+ /** 按序前置到受管 `PATH` 的目录;省略 = 不改 PATH(见 docs/feature/sandbox/library.md)。 */
77
+ readonly pathPrepend?: readonly string[];
54
78
  }
55
79
  export interface CustomProviderSandboxOptions {
56
80
  readonly name: string;
@@ -309,7 +333,7 @@ export declare function sandboxLayer(): SandboxLayer<"command-only">;
309
333
  /** @internal Provider factory 用它一次性绑定纯数据声明与 Effect planner。 */
310
334
  export declare function defineSandboxTemplate(definition: SandboxTemplateDefinition): SandboxLayer<"template-bearing">;
311
335
  export type SandboxExecutionUser = {
312
- readonly _tag: "ImageDefault";
336
+ readonly _tag: "EnvironmentDefault";
313
337
  } | {
314
338
  readonly _tag: "Configured";
315
339
  readonly value: string;
@@ -324,34 +348,43 @@ export interface DockerComposeProviderPlan {
324
348
  readonly file: SandboxLocation;
325
349
  readonly workspaceService: string;
326
350
  readonly build: "on-demand" | "prebuilt";
327
- readonly executionUser: SandboxExecutionUser;
351
+ readonly user: SandboxExecutionUser;
328
352
  readonly env: Readonly<Record<string, string>>;
329
353
  readonly collection: ComposeBuildCollection;
330
354
  readonly lifetime: SandboxProviderLifetime;
355
+ readonly pathPrepend: readonly string[];
331
356
  }
332
357
  export interface DockerfileProviderPlan {
333
358
  readonly context: SandboxLocation;
334
359
  readonly dockerfile: string;
335
360
  readonly buildArgs: Readonly<Record<string, string>>;
361
+ readonly user: SandboxExecutionUser;
336
362
  readonly build: DockerfileBuildIdentity;
337
363
  readonly buildKey: BuildKey;
338
364
  readonly platform: string;
339
365
  readonly lifetime: SandboxProviderLifetime;
366
+ readonly pathPrepend: readonly string[];
340
367
  }
341
368
  export interface DockerImageProviderPlan {
342
369
  readonly image: string;
370
+ readonly user: SandboxExecutionUser;
343
371
  readonly lifetime: SandboxProviderLifetime;
372
+ readonly pathPrepend: readonly string[];
344
373
  }
345
374
  export interface E2BProviderPlan {
346
375
  readonly template: string;
376
+ readonly user: SandboxExecutionUser;
347
377
  readonly lifetime: SandboxProviderLifetime;
378
+ readonly pathPrepend: readonly string[];
348
379
  }
349
380
  export interface VercelProviderPlan {
350
381
  readonly snapshotId: string;
351
382
  readonly lifetime: SandboxProviderLifetime;
383
+ readonly pathPrepend: readonly string[];
352
384
  }
353
385
  export interface LocalProviderPlan {
354
386
  readonly directory: string;
387
+ readonly pathPrepend: readonly string[];
355
388
  }
356
389
  export interface CustomProviderPlan {
357
390
  readonly name: string;
@@ -7,6 +7,11 @@ export interface LocalSandboxOptions {
7
7
  timeout?: number;
8
8
  /** attempt deadline 的截止时刻(epoch ms);单条命令按剩余量取上限(见 deadline.ts)。 */
9
9
  deadlineAt?: number;
10
+ /**
11
+ * 按序前置到宿主 `PATH` 的目录;省略 = 不改 PATH(见 docs/feature/sandbox/library.md
12
+ * 「PATH:受管变量与 pathPrepend」)。
13
+ */
14
+ pathPrepend?: readonly string[];
10
15
  /**
11
16
  * 内部测试用:覆盖「当前目录」的解析起点(省略 `dir` 时向上找 git 根、显式 `dir` 时的相对路径
12
17
  * 基准都从它算)。生产路径(runtime.ts 的 provider materializer)从不传这个字段,恒用
@@ -26,6 +31,8 @@ export declare class LocalSandbox implements SandboxProviderBackend {
26
31
  private readonly timeout?;
27
32
  private deadlineAt?;
28
33
  private readonly ledgerBase;
34
+ /** factory `pathPrepend`;按声明顺序前置到宿主 PATH,省略 = 空数组。 */
35
+ private readonly pathPrepend;
29
36
  readonly capabilities: {
30
37
  rootCommands: import("./backend.ts").SandboxBackendSupport<never>;
31
38
  appendLog: import("./backend.ts").SandboxBackendSupport<never>;
@@ -38,6 +45,8 @@ export declare class LocalSandbox implements SandboxProviderBackend {
38
45
  static create(options?: LocalSandboxOptions): Promise<LocalSandbox>;
39
46
  /** 复用下由池在每次借出时换成承接者自己的 deadline(见 sandbox/deadline.ts)。 */
40
47
  setCommandDeadline(deadlineAt?: number): void;
48
+ /** 宿主 env:`process.env` 叠加 `pathPrepend` 前置后的 PATH,`opts.env` 仍可覆盖任意键(含 PATH)。 */
49
+ private hostEnv;
41
50
  runCommand(cmd: string, args?: readonly string[], opts?: CommandOptions): Promise<CommandResult>;
42
51
  runShell(script: string, opts?: CommandOptions): Promise<CommandResult>;
43
52
  runCommandOrThrow(cmd: string, args?: readonly string[], opts?: CommandOptions): Promise<SuccessfulCommandResult>;