humanish 0.106.1 → 0.107.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 (453) hide show
  1. package/AGENTS.md +4 -4
  2. package/ARCHITECTURE.md +17 -16
  3. package/CHANGELOG.md +14 -0
  4. package/CONTEXT.md +42 -39
  5. package/CONTRIBUTING.md +8 -8
  6. package/README.md +8 -3
  7. package/dist/actors/codex/app-server-client.js +2 -1
  8. package/dist/actors/codex/app-server-trace.d.ts +0 -1
  9. package/dist/actors/codex/app-server-trace.js +1 -3
  10. package/dist/actors/codex/app-server.js +2 -1
  11. package/dist/actors/codex/protocol-compat.d.ts +27 -0
  12. package/dist/actors/codex/protocol-compat.js +357 -0
  13. package/dist/actors/codex/protocol-contract.d.ts +61 -0
  14. package/dist/actors/codex/protocol-contract.js +471 -0
  15. package/dist/actors/codex/qualified-versions.d.ts +30 -3
  16. package/dist/actors/codex/qualified-versions.js +50 -5
  17. package/dist/actors/codex/restricted-executable.d.ts +24 -0
  18. package/dist/actors/codex/restricted-executable.js +97 -22
  19. package/dist/actors/codex/restricted-launch.d.ts +7 -1
  20. package/dist/actors/codex/restricted-launch.js +42 -3
  21. package/dist/actors/codex/restricted-notifications.d.ts +101 -0
  22. package/dist/actors/codex/restricted-notifications.js +277 -0
  23. package/dist/actors/codex/restricted-participant.d.ts +30 -0
  24. package/dist/actors/codex/restricted-participant.js +60 -2
  25. package/dist/actors/codex/restricted-policy.d.ts +9 -1
  26. package/dist/actors/codex/restricted-session.d.ts +14 -1
  27. package/dist/actors/codex/restricted-session.js +50 -17
  28. package/dist/actors/codex/restricted-transport.d.ts +29 -0
  29. package/dist/actors/codex/restricted-transport.js +139 -27
  30. package/dist/actors/codex/restricted-turn.d.ts +19 -4
  31. package/dist/actors/codex/restricted-turn.js +43 -30
  32. package/dist/actors/computer-use/actor.d.ts +1 -1
  33. package/dist/actors/computer-use/actor.js +4 -4
  34. package/dist/actors/computer-use/loop/backstop.js +1 -1
  35. package/dist/actors/computer-use/loop/ending.d.ts +2 -2
  36. package/dist/actors/computer-use/loop/ending.js +2 -2
  37. package/dist/actors/computer-use/loop/spend.d.ts +1 -1
  38. package/dist/actors/computer-use/loop/spend.js +3 -3
  39. package/dist/actors/computer-use/loop/trace.js +2 -2
  40. package/dist/actors/computer-use/loop/types.d.ts +14 -5
  41. package/dist/actors/computer-use/loop.js +4 -4
  42. package/dist/actors/computer-use/openai-provider.d.ts +1 -1
  43. package/dist/actors/computer-use/openai-provider.js +2 -2
  44. package/dist/actors/contract.d.ts +9 -7
  45. package/dist/actors/local-agent/cli.js +1 -1
  46. package/dist/actors/scripted-browser/actor.d.ts +2 -2
  47. package/dist/actors/scripted-browser/journey.js +15 -4
  48. package/dist/actors/scripted-browser/steps.js +18 -0
  49. package/dist/actors/scripted-browser/types.d.ts +11 -1
  50. package/dist/actors/stop-conditions.js +1 -3
  51. package/dist/analysis/automatic-completion.d.ts +13 -8
  52. package/dist/analysis/automatic-completion.js +14 -8
  53. package/dist/analysis/automatic-config.d.ts +1 -1
  54. package/dist/analysis/automatic-config.js +2 -2
  55. package/dist/analysis/automatic.d.ts +10 -4
  56. package/dist/analysis/automatic.js +17 -13
  57. package/dist/analysis/diagnostics.d.ts +23 -0
  58. package/dist/analysis/diagnostics.js +112 -0
  59. package/dist/analysis/evidence-sources.js +2 -2
  60. package/dist/analysis/evidence.js +6 -6
  61. package/dist/analysis/execute.d.ts +7 -1
  62. package/dist/analysis/execute.js +39 -12
  63. package/dist/analysis/job.d.ts +8 -5
  64. package/dist/analysis/job.js +15 -14
  65. package/dist/analysis/load.d.ts +1 -1
  66. package/dist/analysis/load.js +5 -5
  67. package/dist/analysis/provider.d.ts +9 -1
  68. package/dist/analysis/restricted-codex.d.ts +2 -0
  69. package/dist/analysis/restricted-codex.js +10 -1
  70. package/dist/analysis/service.d.ts +2 -0
  71. package/dist/analysis/service.js +31 -12
  72. package/dist/analysis/sharing.d.ts +2 -2
  73. package/dist/analysis/sharing.js +5 -5
  74. package/dist/analysis/store-executions.d.ts +5 -5
  75. package/dist/analysis/store-executions.js +12 -12
  76. package/dist/analysis/store.d.ts +4 -4
  77. package/dist/analysis/store.js +13 -13
  78. package/dist/cli/commands/analysis-signals.d.ts +2 -1
  79. package/dist/cli/commands/analysis-signals.js +4 -1
  80. package/dist/cli/commands/analyze.js +4 -2
  81. package/dist/cli/commands/comms.js +8 -1
  82. package/dist/cli/commands/lab-route-computer-use.d.ts +0 -2
  83. package/dist/cli/commands/lab-route-computer-use.js +26 -14
  84. package/dist/cli/commands/lab-route-preview.d.ts +1 -3
  85. package/dist/cli/commands/lab-route-preview.js +3 -4
  86. package/dist/cli/commands/lab-route-run.d.ts +6 -4
  87. package/dist/cli/commands/lab-route-run.js +6 -2
  88. package/dist/cli/commands/lab-route-scripted.d.ts +0 -2
  89. package/dist/cli/commands/lab-route-scripted.js +0 -1
  90. package/dist/cli/commands/lab-route-shared-world.d.ts +0 -2
  91. package/dist/cli/commands/lab-route-shared-world.js +0 -1
  92. package/dist/cli/commands/lab-route-terminal.d.ts +0 -2
  93. package/dist/cli/commands/lab-route-terminal.js +0 -1
  94. package/dist/cli/commands/lab-run.js +76 -45
  95. package/dist/cli/commands/lab-scorer.d.ts +0 -2
  96. package/dist/cli/commands/lab.js +12 -6
  97. package/dist/cli/commands/observe.js +22 -0
  98. package/dist/cli/commands/run-signals.d.ts +30 -0
  99. package/dist/cli/commands/run-signals.js +146 -0
  100. package/dist/cli/commands/runs.js +10 -8
  101. package/dist/cli/commands/watch.js +12 -10
  102. package/dist/cli/doctor.d.ts +3 -0
  103. package/dist/cli/doctor.js +10 -2
  104. package/dist/cli/io.d.ts +5 -4
  105. package/dist/cli/io.js +12 -8
  106. package/dist/cli/program.js +3 -3
  107. package/dist/cli/renamed-options.d.ts +11 -0
  108. package/dist/cli/renamed-options.js +18 -0
  109. package/dist/cli/telemetry.d.ts +2 -2
  110. package/dist/cli/telemetry.js +1 -1
  111. package/dist/comms/capture-surface.d.ts +1 -1
  112. package/dist/comms/catch-host.d.ts +1 -1
  113. package/dist/comms/connections.js +4 -4
  114. package/dist/comms/external-evidence.d.ts +27 -0
  115. package/dist/comms/external-evidence.js +93 -0
  116. package/dist/comms/lease-store.js +7 -7
  117. package/dist/comms/types.js +1 -1
  118. package/dist/evidence/browser-hygiene.d.ts +1 -1
  119. package/dist/evidence/browser-hygiene.js +1 -1
  120. package/dist/evidence/redaction.js +1 -1
  121. package/dist/evidence/secret-scrub.d.ts +9 -0
  122. package/dist/evidence/secret-scrub.js +96 -0
  123. package/dist/feedback/draft.js +7 -9
  124. package/dist/feedback/export-bundle.js +4 -4
  125. package/dist/feedback/export.js +9 -9
  126. package/dist/feedback/feedback.d.ts +1 -1
  127. package/dist/index.d.ts +3 -6
  128. package/dist/index.js +3 -6
  129. package/dist/keys/key-resolution.d.ts +3 -1
  130. package/dist/keys/key-resolution.js +18 -16
  131. package/dist/lab/adapter-extension.d.ts +28 -6
  132. package/dist/lab/adapter-extension.js +65 -126
  133. package/dist/lab/adapter-scorer-loader.d.ts +25 -5
  134. package/dist/lab/adapter-scorer-loader.js +24 -0
  135. package/dist/lab/composition-rules.js +20 -20
  136. package/dist/lab/config.js +28 -26
  137. package/dist/lab/device-presets.d.ts +2 -2
  138. package/dist/lab/discover.js +1 -3
  139. package/dist/lab/doctor.d.ts +44 -9
  140. package/dist/lab/doctor.js +149 -41
  141. package/dist/lab/init-plan.js +1 -3
  142. package/dist/lab/keys.js +1 -1
  143. package/dist/lab/lab-deps.d.ts +85 -0
  144. package/dist/lab/lab-deps.js +4 -0
  145. package/dist/lab/parse/actors.js +8 -7
  146. package/dist/lab/parse/comms.js +3 -2
  147. package/dist/lab/parse/execution.js +3 -2
  148. package/dist/lab/parse/subject-state.js +2 -1
  149. package/dist/lab/parse/subject.js +2 -1
  150. package/dist/lab/parse/values.d.ts +0 -1
  151. package/dist/lab/parse/values.js +0 -3
  152. package/dist/lab/persona-resolve.d.ts +3 -3
  153. package/dist/lab/persona-resolve.js +4 -4
  154. package/dist/lab/persona.js +1 -3
  155. package/dist/lab/plan-base.d.ts +0 -2
  156. package/dist/lab/plan-base.js +6 -4
  157. package/dist/lab/plan-participants.d.ts +5 -5
  158. package/dist/lab/plan-participants.js +2 -2
  159. package/dist/lab/plan-types.d.ts +22 -4
  160. package/dist/lab/plan.d.ts +3 -11
  161. package/dist/lab/plan.js +18 -42
  162. package/dist/lab/preflight-result.js +0 -2
  163. package/dist/lab/preflight.d.ts +0 -3
  164. package/dist/lab/preflight.js +1 -1
  165. package/dist/lab/requirements.d.ts +20 -0
  166. package/dist/lab/requirements.js +54 -0
  167. package/dist/lab/route-inputs.d.ts +23 -12
  168. package/dist/lab/route-inputs.js +48 -51
  169. package/dist/lab/routing.d.ts +19 -24
  170. package/dist/lab/routing.js +14 -47
  171. package/dist/lab/run-lab-events.d.ts +6 -11
  172. package/dist/lab/run-lab-events.js +3 -11
  173. package/dist/lab/run-lab-homes.d.ts +64 -0
  174. package/dist/lab/run-lab-homes.js +3 -0
  175. package/dist/lab/run-lab-options.d.ts +12 -66
  176. package/dist/lab/run-lab-options.js +45 -275
  177. package/dist/lab/summary.d.ts +9 -4
  178. package/dist/lab/summary.js +15 -8
  179. package/dist/lab/types.d.ts +132 -132
  180. package/dist/lab/validation.d.ts +15 -15
  181. package/dist/lab/validation.js +28 -28
  182. package/dist/lab/warnings.js +20 -19
  183. package/dist/observer/artifact.d.ts +1 -1
  184. package/dist/observer/artifact.js +3 -3
  185. package/dist/observer/data.js +2 -2
  186. package/dist/observer/render.js +2 -2
  187. package/dist/observer/run-routes.d.ts +1 -1
  188. package/dist/observer/run-routes.js +5 -5
  189. package/dist/observer/serve.d.ts +17 -0
  190. package/dist/observer/serve.js +34 -3
  191. package/dist/routes/computer-use/bundle-parts.d.ts +1 -1
  192. package/dist/routes/computer-use/bundle-parts.js +10 -3
  193. package/dist/routes/computer-use/bundle.d.ts +4 -11
  194. package/dist/routes/computer-use/bundle.js +9 -15
  195. package/dist/routes/computer-use/diagnostics.d.ts +1 -1
  196. package/dist/routes/computer-use/diagnostics.js +1 -1
  197. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +10 -10
  198. package/dist/routes/computer-use/e2b-desktop/comms.js +11 -14
  199. package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +2 -2
  200. package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -7
  201. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +13 -13
  202. package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -11
  203. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +3 -3
  204. package/dist/routes/computer-use/e2b-desktop/prepare.js +33 -36
  205. package/dist/routes/computer-use/e2b-desktop/start.d.ts +1 -1
  206. package/dist/routes/computer-use/e2b-desktop/start.js +24 -23
  207. package/dist/routes/computer-use/e2b-desktop/state.d.ts +5 -4
  208. package/dist/routes/computer-use/e2b-desktop/state.js +5 -3
  209. package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +1 -1
  210. package/dist/routes/computer-use/e2b-desktop/teardown.js +29 -17
  211. package/dist/routes/computer-use/external-comms.d.ts +4 -4
  212. package/dist/routes/computer-use/external-comms.js +19 -43
  213. package/dist/routes/computer-use/fanout-bundle.d.ts +3 -3
  214. package/dist/routes/computer-use/fanout-bundle.js +25 -29
  215. package/dist/routes/computer-use/{fanout-lanes.js → fanout-records.js} +25 -19
  216. package/dist/routes/computer-use/in-process-desktop.d.ts +3 -10
  217. package/dist/routes/computer-use/in-process-desktop.js +3 -9
  218. package/dist/routes/computer-use/live-flush.d.ts +7 -5
  219. package/dist/routes/computer-use/live-flush.js +19 -27
  220. package/dist/routes/computer-use/{run-lanes.js → live-phase.js} +12 -11
  221. package/dist/routes/computer-use/local-tree-pack.d.ts +3 -3
  222. package/dist/routes/computer-use/local-tree-pack.js +4 -5
  223. package/dist/routes/computer-use/local-vm.d.ts +11 -8
  224. package/dist/routes/computer-use/local-vm.js +39 -66
  225. package/dist/routes/computer-use/participant-desktop.d.ts +8 -23
  226. package/dist/routes/computer-use/participant-desktop.js +5 -25
  227. package/dist/routes/computer-use/{lanes.d.ts → participant-execution.d.ts} +10 -10
  228. package/dist/routes/computer-use/{lanes.js → participant-execution.js} +35 -22
  229. package/dist/routes/computer-use/participant-facts.d.ts +7 -1
  230. package/dist/routes/computer-use/participant-facts.js +12 -1
  231. package/dist/routes/computer-use/participant-model.d.ts +19 -11
  232. package/dist/routes/computer-use/participant-model.js +49 -25
  233. package/dist/routes/computer-use/participant-prompt.d.ts +3 -3
  234. package/dist/routes/computer-use/participant-prompt.js +4 -4
  235. package/dist/routes/computer-use/participant-runs.d.ts +6 -6
  236. package/dist/routes/computer-use/participant-runs.js +8 -8
  237. package/dist/routes/computer-use/plan.d.ts +21 -29
  238. package/dist/routes/computer-use/plan.js +52 -60
  239. package/dist/routes/computer-use/preflight.d.ts +3 -5
  240. package/dist/routes/computer-use/preflight.js +20 -16
  241. package/dist/routes/computer-use/rerun-selection.js +10 -6
  242. package/dist/routes/computer-use/result.d.ts +1 -1
  243. package/dist/routes/computer-use/result.js +40 -30
  244. package/dist/routes/computer-use/route.d.ts +3 -4
  245. package/dist/routes/computer-use/route.js +21 -19
  246. package/dist/routes/computer-use/self-report.d.ts +2 -2
  247. package/dist/routes/computer-use/self-report.js +4 -4
  248. package/dist/routes/computer-use/setup.d.ts +8 -14
  249. package/dist/routes/computer-use/setup.js +96 -72
  250. package/dist/routes/computer-use/single-bundle.d.ts +8 -11
  251. package/dist/routes/computer-use/single-bundle.js +20 -25
  252. package/dist/routes/computer-use/subject-projection.d.ts +5 -7
  253. package/dist/routes/computer-use/subject-projection.js +20 -19
  254. package/dist/routes/computer-use/types.d.ts +169 -210
  255. package/dist/routes/computer-use/types.js +13 -5
  256. package/dist/routes/preview.js +0 -1
  257. package/dist/routes/scripted/bundle.d.ts +3 -6
  258. package/dist/routes/scripted/bundle.js +11 -16
  259. package/dist/routes/scripted/plan.d.ts +5 -7
  260. package/dist/routes/scripted/plan.js +6 -4
  261. package/dist/routes/scripted/result.d.ts +4 -1
  262. package/dist/routes/scripted/result.js +10 -6
  263. package/dist/routes/scripted/route.js +10 -11
  264. package/dist/routes/scripted/scenario.d.ts +1 -1
  265. package/dist/routes/scripted/scenario.js +1 -1
  266. package/dist/routes/scripted/setup.d.ts +3 -2
  267. package/dist/routes/scripted/setup.js +22 -21
  268. package/dist/routes/scripted/subject.d.ts +8 -3
  269. package/dist/routes/scripted/subject.js +9 -5
  270. package/dist/routes/scripted/surface-records.js +1 -1
  271. package/dist/routes/scripted/surface-sessions.d.ts +2 -2
  272. package/dist/routes/scripted/surface-sessions.js +4 -4
  273. package/dist/routes/scripted/types.d.ts +19 -36
  274. package/dist/routes/scripted/types.js +1 -2
  275. package/dist/routes/shared-world/{seat-records.js → bundle-records.js} +8 -8
  276. package/dist/routes/shared-world/bundle.d.ts +2 -2
  277. package/dist/routes/shared-world/bundle.js +22 -26
  278. package/dist/routes/shared-world/checkpoints.d.ts +4 -4
  279. package/dist/routes/shared-world/checkpoints.js +4 -4
  280. package/dist/routes/shared-world/comms.d.ts +5 -4
  281. package/dist/routes/shared-world/comms.js +28 -41
  282. package/dist/routes/shared-world/external-public.d.ts +5 -5
  283. package/dist/routes/shared-world/external-public.js +19 -20
  284. package/dist/routes/shared-world/handoff.d.ts +4 -4
  285. package/dist/routes/shared-world/handoff.js +50 -50
  286. package/dist/routes/shared-world/lobby-code.d.ts +5 -5
  287. package/dist/routes/shared-world/lobby-code.js +13 -13
  288. package/dist/routes/shared-world/{seats.d.ts → participant-specs.d.ts} +8 -6
  289. package/dist/routes/shared-world/{seats.js → participant-specs.js} +43 -48
  290. package/dist/routes/shared-world/plan.d.ts +2 -6
  291. package/dist/routes/shared-world/plan.js +1 -2
  292. package/dist/routes/shared-world/provenance.d.ts +4 -4
  293. package/dist/routes/shared-world/provenance.js +4 -4
  294. package/dist/routes/shared-world/provisioned.d.ts +3 -2
  295. package/dist/routes/shared-world/provisioned.js +46 -40
  296. package/dist/routes/shared-world/result.js +31 -19
  297. package/dist/routes/shared-world/route.js +37 -41
  298. package/dist/routes/shared-world/setup.d.ts +5 -4
  299. package/dist/routes/shared-world/setup.js +12 -14
  300. package/dist/routes/shared-world/types.d.ts +53 -126
  301. package/dist/routes/shared-world/types.js +2 -2
  302. package/dist/routes/terminal/adapter.d.ts +8 -8
  303. package/dist/routes/terminal/adapter.js +28 -125
  304. package/dist/routes/terminal/bundle.d.ts +7 -12
  305. package/dist/routes/terminal/bundle.js +24 -34
  306. package/dist/routes/terminal/credentials.d.ts +2 -2
  307. package/dist/routes/terminal/credentials.js +16 -16
  308. package/dist/routes/terminal/dry-run.d.ts +1 -1
  309. package/dist/routes/terminal/dry-run.js +9 -11
  310. package/dist/routes/terminal/encoding.d.ts +1 -1
  311. package/dist/routes/terminal/encoding.js +2 -2
  312. package/dist/routes/terminal/ledger.d.ts +6 -6
  313. package/dist/routes/terminal/ledger.js +9 -9
  314. package/dist/routes/terminal/live-finish.d.ts +1 -2
  315. package/dist/routes/terminal/live-finish.js +21 -20
  316. package/dist/routes/terminal/live-sandbox.d.ts +3 -2
  317. package/dist/routes/terminal/live-sandbox.js +20 -20
  318. package/dist/routes/terminal/participant-text.d.ts +23 -0
  319. package/dist/routes/terminal/participant-text.js +165 -0
  320. package/dist/routes/terminal/plan.d.ts +2 -6
  321. package/dist/routes/terminal/plan.js +13 -9
  322. package/dist/routes/terminal/recorder.d.ts +6 -1
  323. package/dist/routes/terminal/recorder.js +12 -4
  324. package/dist/routes/terminal/result.js +4 -4
  325. package/dist/routes/terminal/route.js +26 -26
  326. package/dist/routes/terminal/runtime.d.ts +3 -2
  327. package/dist/routes/terminal/runtime.js +3 -3
  328. package/dist/routes/terminal/sandbox.d.ts +3 -3
  329. package/dist/routes/terminal/sandbox.js +9 -9
  330. package/dist/routes/terminal/session.js +16 -14
  331. package/dist/routes/terminal/token-usage.js +5 -5
  332. package/dist/routes/terminal/trace.d.ts +5 -8
  333. package/dist/routes/terminal/trace.js +9 -64
  334. package/dist/routes/terminal/types.d.ts +85 -93
  335. package/dist/routes/terminal/types.js +9 -4
  336. package/dist/run/active-runs.d.ts +13 -0
  337. package/dist/run/active-runs.js +12 -0
  338. package/dist/run/bundle-shape.d.ts +2 -1
  339. package/dist/run/bundle-shape.js +4 -4
  340. package/dist/run/bundle.d.ts +63 -56
  341. package/dist/run/bundle.js +9 -8
  342. package/dist/run/cost-summary.js +3 -2
  343. package/dist/run/costs.d.ts +6 -6
  344. package/dist/run/costs.js +10 -10
  345. package/dist/run/detail.d.ts +5 -5
  346. package/dist/run/detail.js +6 -6
  347. package/dist/run/dry-run.js +5 -12
  348. package/dist/run/{study-files.d.ts → evidence-files.d.ts} +4 -4
  349. package/dist/run/{study-files.js → evidence-files.js} +5 -5
  350. package/dist/run/feedback-shape.js +1 -1
  351. package/dist/run/judge.d.ts +16 -4
  352. package/dist/run/judge.js +24 -7
  353. package/dist/run/locate.d.ts +2 -0
  354. package/dist/run/locate.js +3 -1
  355. package/dist/run/outcomes.d.ts +3 -3
  356. package/dist/run/outcomes.js +3 -3
  357. package/dist/run/participant-records.d.ts +2 -2
  358. package/dist/run/participant-records.js +2 -2
  359. package/dist/run/paths.js +1 -1
  360. package/dist/run/pricing.d.ts +19 -9
  361. package/dist/run/pricing.js +30 -18
  362. package/dist/run/projection.d.ts +13 -13
  363. package/dist/run/projection.js +8 -8
  364. package/dist/run/reclaim.d.ts +6 -0
  365. package/dist/run/reclaim.js +13 -3
  366. package/dist/run/results.d.ts +1 -1
  367. package/dist/run/run-index.d.ts +1 -1
  368. package/dist/run/run-index.js +11 -11
  369. package/dist/run/run.d.ts +4 -2
  370. package/dist/run/run.js +9 -5
  371. package/dist/run/sandbox-receipts.d.ts +4 -4
  372. package/dist/run/sandbox-receipts.js +4 -4
  373. package/dist/run/shared-world-evidence.d.ts +47 -47
  374. package/dist/run/shared-world-shape.d.ts +3 -3
  375. package/dist/run/shared-world-shape.js +11 -11
  376. package/dist/run/stats.d.ts +5 -5
  377. package/dist/run/stats.js +8 -8
  378. package/dist/run/status.d.ts +16 -6
  379. package/dist/run/status.js +31 -8
  380. package/dist/run/streams.d.ts +26 -19
  381. package/dist/run/terminal-contract.d.ts +5 -5
  382. package/dist/run/terminal-contract.js +4 -4
  383. package/dist/run/transient-comms-secrets.d.ts +5 -0
  384. package/dist/run/transient-comms-secrets.js +12 -0
  385. package/dist/run-lab.d.ts +36 -34
  386. package/dist/run-lab.js +41 -37
  387. package/dist/subject/desktop-cli.d.ts +1 -1
  388. package/dist/subject/desktop-cli.js +1 -1
  389. package/dist/subject/local-tree-archive.d.ts +1 -1
  390. package/dist/subject/local-tree-archive.js +4 -4
  391. package/dist/subject/local-tree.d.ts +2 -2
  392. package/dist/subject/local-tree.js +1 -1
  393. package/dist/subject/node-bootstrap.d.ts +1 -1
  394. package/dist/subject/node-bootstrap.js +4 -4
  395. package/dist/subject/runtime.js +5 -5
  396. package/dist/subject/serve.js +1 -1
  397. package/dist/subject/steps.d.ts +4 -4
  398. package/dist/subject/steps.js +5 -5
  399. package/dist/substrates/e2b/cdp-probe.d.ts +2 -2
  400. package/dist/substrates/e2b/cdp-probe.js +1 -1
  401. package/dist/substrates/e2b/desktop-browser.d.ts +3 -3
  402. package/dist/substrates/e2b/desktop-browser.js +4 -4
  403. package/dist/substrates/e2b/desktop-cdp.d.ts +7 -7
  404. package/dist/substrates/e2b/desktop-cdp.js +4 -4
  405. package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
  406. package/dist/substrates/e2b/desktop-geometry.js +3 -3
  407. package/dist/substrates/e2b/desktop-media.js +2 -2
  408. package/dist/substrates/e2b/sandbox.js +1 -1
  409. package/dist/substrates/e2b/sdk.js +2 -2
  410. package/dist/substrates/local/runtime-host.d.ts +2 -0
  411. package/dist/substrates/local/runtime-host.js +6 -0
  412. package/dist/tui/actions.d.ts +7 -5
  413. package/dist/tui/actions.js +18 -9
  414. package/dist/tui-app.js +42 -42
  415. package/dist/verify/actor.d.ts +10 -10
  416. package/dist/verify/actor.js +15 -15
  417. package/dist/verify/artifacts.d.ts +1 -1
  418. package/dist/verify/artifacts.js +3 -3
  419. package/dist/verify/costs.d.ts +2 -2
  420. package/dist/verify/costs.js +2 -2
  421. package/dist/verify/liveness.d.ts +1 -1
  422. package/dist/verify/liveness.js +4 -1
  423. package/dist/verify/rerun.d.ts +1 -1
  424. package/dist/verify/rerun.js +1 -1
  425. package/dist/verify/shared-world.js +2 -2
  426. package/dist/verify/verify.js +6 -6
  427. package/docs/README.md +1 -1
  428. package/docs/architecture/actor-contract.md +60 -22
  429. package/docs/architecture/desktop-sessions.md +9 -9
  430. package/docs/architecture/external-public-shared-world.md +5 -0
  431. package/docs/architecture/observer.md +4 -4
  432. package/docs/architecture/restricted-codex-analysis.md +36 -2
  433. package/docs/architecture/state-driven-executor.md +4 -5
  434. package/docs/architecture/task-protocol-support.md +3 -5
  435. package/docs/architecture/{terminal-product-lane.md → terminal-product-route.md} +24 -16
  436. package/docs/contracts/run-bundle.md +10 -8
  437. package/docs/contracts/schemas.md +109 -53
  438. package/docs/contracts/study-analysis.md +24 -0
  439. package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +2 -1
  440. package/docs/product/automatic-analysis.md +1 -0
  441. package/docs/ramp/README.md +2 -1
  442. package/package.json +4 -4
  443. package/skills/humanish/SKILL.md +3 -2
  444. package/skills/humanish/agents/openai.yaml +1 -1
  445. package/dist/deprecated.d.ts +0 -90
  446. package/dist/deprecated.js +0 -106
  447. package/dist/lab/bag-overrides.d.ts +0 -18
  448. package/dist/lab/bag-overrides.js +0 -121
  449. package/dist/routes/computer-use/legacy-lane-spec.d.ts +0 -62
  450. package/dist/routes/computer-use/legacy-lane-spec.js +0 -39
  451. /package/dist/routes/computer-use/{fanout-lanes.d.ts → fanout-records.d.ts} +0 -0
  452. /package/dist/routes/computer-use/{run-lanes.d.ts → live-phase.d.ts} +0 -0
  453. /package/dist/routes/shared-world/{seat-records.d.ts → bundle-records.d.ts} +0 -0
@@ -2,15 +2,13 @@ import type { ActorPersonaRef } from "../../actors/contract.js";
2
2
  import type { ScriptedBrowserSessionResult } from "../../actors/scripted-browser/actor.js";
3
3
  import type { BrowserPersonaJourney, BrowserSurface } from "../../actors/scripted-browser/types.js";
4
4
  import type { DesktopResourceObservation } from "../../substrates/e2b/desktop-resources.js";
5
- import { type ReviewSummary, type RunBundle, type RunSubjectProvenance } from "../../run/bundle.js";
6
- import type { RunLabProvenance } from "../../run/status.js";
5
+ import { type ReviewSummary, type RunBundle, type RunSubjectProvenance, type BundleRun } from "../../run/bundle.js";
7
6
  /** What the scripted lab's bundle is built from. */
8
7
  interface ScriptedBundleArgs {
9
- /** Lab provenance for the bundle\'s own `lab` field (#455). */
10
- lab?: RunLabProvenance;
8
+ /** The run this bundle belongs to; the bundle head reads its id, mode, start and lab. */
9
+ run: BundleRun;
11
10
  actorId: string;
12
11
  appUrl: string;
13
- createdAt: string;
14
12
  desktopTemplate?: string;
15
13
  dryRun: boolean;
16
14
  hostDigest?: string;
@@ -18,7 +16,6 @@ interface ScriptedBundleArgs {
18
16
  labId: string;
19
17
  labTitle?: string;
20
18
  persona: ActorPersonaRef;
21
- runId: string;
22
19
  scenarioSource: string;
23
20
  scenarioSourceDigest: string;
24
21
  screenshotsBySurface: Map<string, string[]>;
@@ -14,20 +14,15 @@ import { scriptedSurfaceIds, scriptedSurfaceRecords } from "./surface-records.js
14
14
  */
15
15
  export function buildScriptedLabBundle(args) {
16
16
  const resultBySurface = new Map(args.sessionResults.map((result) => [result.capture.surface.id, result]));
17
- const records = args.surfaces.map((surface, index) => scriptedSurfaceRecords(args, surface, index, resultBySurface.get(surface.id), args.screenshotsBySurface.get(surface.id) ?? []));
17
+ // Each surface's records are stamped with the run's start.
18
+ const context = { ...args, createdAt: args.run.createdAt };
19
+ const records = args.surfaces.map((surface, index) => scriptedSurfaceRecords(context, surface, index, resultBySurface.get(surface.id), args.screenshotsBySurface.get(surface.id) ?? []));
18
20
  const events = scriptedEvents(args);
19
21
  const review = buildScriptedReview(args);
20
22
  const ranLive = args.sessionResults.length > 0 || args.sessionError !== undefined;
21
23
  const cost = args.dryRun ? undefined : scriptedCost(args.subjectDesktop);
22
24
  return {
23
- ...bundleHead({
24
- runId: args.runId,
25
- mode: args.dryRun ? "dry-run" : "live",
26
- participants: args.surfaces.length,
27
- createdAt: args.createdAt,
28
- ...(args.lab === undefined ? {} : { lab: args.lab }),
29
- source: args.source,
30
- }),
25
+ ...bundleHead(args.run, { participants: args.surfaces.length, source: args.source }),
31
26
  persona: {
32
27
  id: args.persona.id,
33
28
  name: `Scripted journey persona (${args.persona.id})`,
@@ -43,7 +38,7 @@ export function buildScriptedLabBundle(args) {
43
38
  },
44
39
  lifecycle: [
45
40
  {
46
- at: args.createdAt,
41
+ at: args.run.createdAt,
47
42
  event: "scripted-lab.run.created",
48
43
  message: `Created scripted-browser lab run with ${args.surfaces.length} surface${args.surfaces.length === 1 ? "" : "s"} (actor ${args.actorId}).`,
49
44
  },
@@ -70,17 +65,17 @@ function scriptedEvents(args) {
70
65
  const events = [
71
66
  {
72
67
  id: "event-000-created",
73
- at: args.createdAt,
68
+ at: args.run.createdAt,
74
69
  level: "info",
75
70
  type: "scripted-lab.run.created",
76
71
  message: `Created scripted-browser lab run for ${args.labId} (actor ${args.actorId}, ${args.surfaces.length} surface${args.surfaces.length === 1 ? "" : "s"}).`,
77
72
  },
78
73
  {
79
74
  id: "event-001-subject",
80
- at: args.createdAt,
75
+ at: args.run.createdAt,
81
76
  level: "info",
82
77
  type: "scripted-lab.subject.declared",
83
- // Invariant 5: provenance recorded or its absence DECLARED. The lab did not provision
78
+ // Invariant 5: provenance recorded or its absence declared. The lab did not provision
84
79
  // this subject on app-url routes; clone routes carry structured subject provenance below.
85
80
  message: args.subject
86
81
  ? `Provisioned synthetic subject: clone of ${args.subject.repo}${args.subject.commit ? `@${args.subject.commit}` : ""}, served + getHost-exposed in-sandbox; env names: ${args.subject.envNames?.join(", ") || "none"} (values never persisted); state provenance: ${args.subject.state.provenance}; evidence host digest: ${args.hostDigest ?? "dry-run"}.`
@@ -88,7 +83,7 @@ function scriptedEvents(args) {
88
83
  },
89
84
  {
90
85
  id: "event-002-spend",
91
- at: args.createdAt,
86
+ at: args.run.createdAt,
92
87
  level: "info",
93
88
  type: "scripted-lab.spend",
94
89
  message: args.subject
@@ -110,7 +105,7 @@ function scriptedEvents(args) {
110
105
  else if (args.sessionError !== undefined) {
111
106
  events.push({
112
107
  id: "event-003-session-error",
113
- at: args.createdAt,
108
+ at: args.run.createdAt,
114
109
  level: "error",
115
110
  type: "scripted-lab.session.error",
116
111
  message: args.sessionError,
@@ -119,7 +114,7 @@ function scriptedEvents(args) {
119
114
  else {
120
115
  events.push({
121
116
  id: "event-003-contract",
122
- at: args.createdAt,
117
+ at: args.run.createdAt,
123
118
  level: "info",
124
119
  type: "scripted-lab.contract.ready",
125
120
  message: `Dry-run contract bundle ready: scenario ${args.journey.scenarioId} @ ${args.scenarioSourceDigest} (${args.scenarioSource}, ${args.journey.steps.length} step${args.journey.steps.length === 1 ? "" : "s"}) parsed and digest-pinned; switch scenario.mode to live to actuate a real browser.`,
@@ -1,6 +1,6 @@
1
+ import type { LabDeps } from "../../lab/lab-deps.js";
1
2
  import type { RoutePlanResult, RouteRefusal, ScriptedPlan } from "../../lab/plan-types.js";
2
3
  import type { LabConfig } from "../../lab/types.js";
3
- import type { RunLabProvenance } from "../../run/status.js";
4
4
  /** The error a scripted lab returns before a run starts. */
5
5
  export interface ScriptedRefusal extends RouteRefusal<"scripted", "HUMANISH_LAB_ANALYSIS_INVALID" | "HUMANISH_LAB_TASKS_UNSUPPORTED" | "HUMANISH_SCRIPTED_LAB_ACTOR_UNSUPPORTED" | "HUMANISH_SCRIPTED_LAB_SCENARIO_INVALID" | "HUMANISH_SCRIPTED_LAB_SUBJECT_UNSAFE"> {
6
6
  /**
@@ -15,16 +15,14 @@ export interface ScriptedRefusal extends RouteRefusal<"scripted", "HUMANISH_LAB_
15
15
  export type ScriptedPlanResult = RoutePlanResult<ScriptedPlan, ScriptedRefusal>;
16
16
  /** The app URL a run's evidence names: a provisioned subject's getHost URL is never persisted. */
17
17
  export declare function evidenceAppUrlOf(subject: ScriptedPlan["subject"]): string;
18
+ /** Whether a test injected the browser, so a live run needs no host browser. */
19
+ export declare function injectedBrowser(deps: LabDeps | undefined): boolean;
18
20
  /**
19
21
  * Plan a scripted-browser lab. It is called for any config handed to the scripted runner, not only
20
22
  * one routeOf sends here, so a config for another route gets this route's refusal.
21
23
  */
22
24
  export declare function planScriptedLab(config: LabConfig, input: {
23
25
  readonly dryRun: boolean;
24
- readonly lab?: RunLabProvenance;
25
- /** An injected browser means a live run needs no host browser. */
26
- readonly hooks?: {
27
- readonly launchBrowser?: unknown;
28
- readonly browserCommand?: string;
29
- };
26
+ /** A test's injected browser means a live run needs no host browser. */
27
+ readonly injectedBrowser?: boolean;
30
28
  }): ScriptedPlanResult;
@@ -7,13 +7,17 @@ import { browserSurfaces } from "../../actors/scripted-browser/types.js";
7
7
  import { resolveAutomaticAnalysis } from "../../analysis/automatic-config.js";
8
8
  import { isNonEmpty, planBase, provisionedSubject } from "../../lab/plan-base.js";
9
9
  import { cloneTargetValidationReason, desktopMediaValidationReason, taskProtocolValidationReason, } from "../../lab/validation.js";
10
- // Default surface roster is 1 (desktop only): the defaults-table single-lane row governs;
10
+ // Default surface roster is 1 (desktop only): the defaults-table single-participant row governs;
11
11
  // `count: 2` is the declared override that adds the mobile surface.
12
12
  const DEFAULT_SURFACE_COUNT = 1;
13
13
  /** The app URL a run's evidence names: a provisioned subject's getHost URL is never persisted. */
14
14
  export function evidenceAppUrlOf(subject) {
15
15
  return subject.kind === "clone" ? "[provisioned-subject]" : subject.appUrl;
16
16
  }
17
+ /** Whether a test injected the browser, so a live run needs no host browser. */
18
+ export function injectedBrowser(deps) {
19
+ return Boolean(deps?.launchBrowser || deps?.browserCommand);
20
+ }
17
21
  /**
18
22
  * Plan a scripted-browser lab. It is called for any config handed to the scripted runner, not only
19
23
  * one routeOf sends here, so a config for another route gets this route's refusal.
@@ -62,7 +66,6 @@ export function planScriptedLab(config, input) {
62
66
  const scenarioRef = config.scenario?.ref;
63
67
  if (!scenarioRef?.trim())
64
68
  return refuse("HUMANISH_SCRIPTED_LAB_SCENARIO_INVALID", "scripted-browser labs require `scenario.ref` — the committed scenario's browser steps are what this actor executes.", { actor, appUrl: evidenceAppUrlOf(subject) });
65
- const hooks = input.hooks ?? {};
66
69
  const requirements = [];
67
70
  if (!input.dryRun && subject.kind === "clone") {
68
71
  requirements.push({ kind: "key", name: "E2B_API_KEY" });
@@ -70,7 +73,7 @@ export function planScriptedLab(config, input) {
70
73
  requirements.push({ kind: "subject-env", names: subject.env });
71
74
  }
72
75
  // The browser runs on this machine on both subjects; a clone's is pointed at its getHost URL.
73
- if (!input.dryRun && !hooks.launchBrowser && !hooks.browserCommand)
76
+ if (!input.dryRun && input.injectedBrowser !== true)
74
77
  requirements.push({ kind: "host-browser" });
75
78
  const persona = config.actors[0]?.persona;
76
79
  const timeoutMs = config.execution?.timeoutMs;
@@ -79,7 +82,6 @@ export function planScriptedLab(config, input) {
79
82
  plan: {
80
83
  ...planBase(config, {
81
84
  dryRun: input.dryRun,
82
- ...(input.lab === undefined ? {} : { lab: input.lab }),
83
85
  analysis,
84
86
  }),
85
87
  route: "scripted",
@@ -36,13 +36,16 @@ export interface ScriptedFinishInputs {
36
36
  }
37
37
  /**
38
38
  * The scripted run's execution failures: the session's own error, a live surface that never
39
- * returned, a surface that ended in a harness error, and an Observer that failed.
39
+ * returned, a surface that ended in a harness error, a subject sandbox whose release is
40
+ * unconfirmed, and an Observer that failed.
40
41
  */
41
42
  export declare function scriptedExecutionFailures(args: {
42
43
  dryRun: boolean;
44
+ runId: string;
43
45
  sessionError: string | undefined;
44
46
  expected: number;
45
47
  sessionResults: readonly Pick<ScriptedBrowserSessionResult, "completionReason" | "reason">[];
48
+ subject: Pick<ScriptedSubject, "sandboxId" | "killed" | "releaseWarning"> | undefined;
46
49
  observer: Pick<ObserverResult, "ok" | "error">;
47
50
  }): ExecutionFailure[];
48
51
  export declare function finishScriptedRun(inputs: ScriptedFinishInputs): Promise<ScriptedBrowserLabResult>;
@@ -1,4 +1,4 @@
1
- import { judgeExecution, judgeScripted, OUTCOME_POLICIES, resultOk, } from "../../run/judge.js";
1
+ import { judgeExecution, sandboxCleanupFailure, judgeScripted, OUTCOME_POLICIES, resultOk, } from "../../run/judge.js";
2
2
  import { validatePreparedRunArtifactPaths } from "../../run/paths.js";
3
3
  import { resolveSubjectState } from "../computer-use/subject-projection.js";
4
4
  import { buildScriptedLabBundle } from "./bundle.js";
@@ -16,7 +16,8 @@ function scriptedSurfaceFacts(result) {
16
16
  }
17
17
  /**
18
18
  * The scripted run's execution failures: the session's own error, a live surface that never
19
- * returned, a surface that ended in a harness error, and an Observer that failed.
19
+ * returned, a surface that ended in a harness error, a subject sandbox whose release is
20
+ * unconfirmed, and an Observer that failed.
20
21
  */
21
22
  export function scriptedExecutionFailures(args) {
22
23
  const { sessionError, sessionResults, observer } = args;
@@ -39,6 +40,9 @@ export function scriptedExecutionFailures(args) {
39
40
  },
40
41
  ]
41
42
  : []),
43
+ ...(args.subject?.sandboxId === undefined || args.subject.killed
44
+ ? []
45
+ : [sandboxCleanupFailure("subject", args.subject.releaseWarning, args.runId)]),
42
46
  ...(observer.ok
43
47
  ? []
44
48
  : [
@@ -54,7 +58,7 @@ export async function finishScriptedRun(inputs) {
54
58
  const { surfaces, sessionResults, sessionError, warnings, clone, redactRepoLabel } = inputs;
55
59
  const { subjectEnvNames, scriptedSubject } = inputs;
56
60
  const { actor, dryRun } = plan;
57
- const { runId, createdAt, paths: runPaths } = run;
61
+ const { runId, paths: runPaths } = run;
58
62
  const subjectCommit = scriptedSubject?.commit;
59
63
  const subjectSandboxId = scriptedSubject?.sandboxId;
60
64
  const subjectKilled = scriptedSubject?.killed ?? false;
@@ -86,16 +90,14 @@ export async function finishScriptedRun(inputs) {
86
90
  surfaces: sessionResults.map(scriptedSurfaceFacts),
87
91
  });
88
92
  const bundle = buildScriptedLabBundle({
89
- ...(plan.lab === undefined ? {} : { lab: plan.lab }),
93
+ run,
90
94
  actorId: actor,
91
95
  appUrl: evidenceAppUrl,
92
- createdAt,
93
96
  dryRun,
94
97
  journey,
95
98
  labId: plan.labId,
96
99
  ...(plan.title ? { labTitle: plan.title } : {}),
97
100
  persona,
98
- runId,
99
101
  scenarioSource: scenario.source,
100
102
  scenarioSourceDigest: scenario.sourceDigest,
101
103
  screenshotsBySurface,
@@ -122,9 +124,11 @@ export async function finishScriptedRun(inputs) {
122
124
  const policy = OUTCOME_POLICIES.scripted;
123
125
  const execution = judgeExecution(scriptedExecutionFailures({
124
126
  dryRun,
127
+ runId,
125
128
  sessionError,
126
129
  expected: surfaces.length,
127
130
  sessionResults,
131
+ subject: scriptedSubject,
128
132
  observer,
129
133
  }), policy);
130
134
  const ok = resultOk({ judgment, execution, scorerFailures: [], policy });
@@ -24,7 +24,7 @@ import { buildRunSource } from "../../run/bundle.js";
24
24
  import { prepareSelectedOutputDirectory } from "../../run/contained-output.js";
25
25
  import { runScope } from "../../run/run.js";
26
26
  import { renderScriptedReviewMarkdown } from "./bundle.js";
27
- import { planScriptedLab } from "./plan.js";
27
+ import { injectedBrowser, planScriptedLab } from "./plan.js";
28
28
  import { finishScriptedRun } from "./result.js";
29
29
  import { UnsafeScriptedSessionResultError } from "./session-result.js";
30
30
  import { prepareScriptedRun } from "./setup.js";
@@ -36,12 +36,11 @@ import { SCRIPTED_BROWSER_LAB_SCHEMA, } from "./types.js";
36
36
  * returned at that refusal's stage, and otherwise runs the plan.
37
37
  */
38
38
  export async function runScriptedBrowserLab(options) {
39
- const { config, dryRun, lab, ...input } = options;
39
+ const { config, dryRun, ...input } = options;
40
40
  // planScriptedLab makes every configuration refusal, in the order this route always has.
41
41
  const planned = planScriptedLab(config, {
42
42
  dryRun,
43
- ...(lab === undefined ? {} : { lab }),
44
- ...(input.hooks === undefined ? {} : { hooks: input.hooks }),
43
+ injectedBrowser: injectedBrowser(input.deps),
45
44
  });
46
45
  if (planned.ok)
47
46
  return runScriptedPlan(planned.plan, input);
@@ -86,7 +85,7 @@ export async function scriptedLabRefusal(options, refusal) {
86
85
  error: { code: refusal.code, message: refusal.message },
87
86
  };
88
87
  const analysis = resolveAutomaticAnalysis(config.review?.analysis);
89
- return completeAutomaticAnalysis(refused, undefined, analysis.ok ? analysis.config : undefined, options.automaticAnalysis, { trigger: config.review?.analysis === undefined ? "default" : "explicit" });
88
+ return completeAutomaticAnalysis(refused, undefined, analysis.ok ? analysis.config : undefined, options, { trigger: config.review?.analysis === undefined ? "default" : "explicit" });
90
89
  }
91
90
  /**
92
91
  * runLab's step for a scripted plan. It takes no scorer, and its local checks (keys, a browser)
@@ -97,7 +96,6 @@ export function admitScriptedPlan(plan, input) {
97
96
  ok: true,
98
97
  run: async () => ({
99
98
  route: "scripted",
100
- backend: "scripted",
101
99
  result: await runScriptedPlan(plan, input),
102
100
  }),
103
101
  };
@@ -112,7 +110,7 @@ export function admitScriptedPlan(plan, input) {
112
110
  */
113
111
  export async function runScriptedPlan(plan, input) {
114
112
  const { result, finished } = await runScope((scope) => runScriptedPlanInScope(plan, input, scope));
115
- return completeAutomaticAnalysis(result, finished, plan.analysis?.config, input.automaticAnalysis, {
113
+ return completeAutomaticAnalysis(result, finished, plan.analysis?.config, input, {
116
114
  ...(plan.analysis === undefined ? {} : { trigger: plan.analysis.trigger }),
117
115
  preferLargerOutput: plan.analysis?.preferLargerOutput === true,
118
116
  });
@@ -130,7 +128,7 @@ async function runScriptedPlanInScope(plan, input, scope) {
130
128
  mode: dryRun ? "dry-run" : "live",
131
129
  lab: plan.lab,
132
130
  renderReview: renderScriptedReviewMarkdown,
133
- observer: { open: input.open === true, render: setup.hooks.renderObserverFn },
131
+ observer: { open: input.open === true, render: setup.deps.renderObserver },
134
132
  });
135
133
  if (!started.ok) {
136
134
  return setup.failed(started.code, started.message);
@@ -148,7 +146,8 @@ async function runScriptedPlanInScope(plan, input, scope) {
148
146
  ? new ScriptedSubject({
149
147
  plan,
150
148
  clone: setup.clone,
151
- hooks: setup.hooks,
149
+ deps: setup.deps,
150
+ ...(input.prepareDesktop === undefined ? {} : { prepareDesktop: input.prepareDesktop }),
152
151
  env: setup.env,
153
152
  e2bApiKey: setup.e2bApiKey,
154
153
  runPaths,
@@ -156,7 +155,7 @@ async function runScriptedPlanInScope(plan, input, scope) {
156
155
  subjectEnvNames: setup.subjectEnvNames,
157
156
  hasGithubToken: setup.hasGithubToken,
158
157
  scrubKnownValues: setup.scrubKnownValues,
159
- now: setup.hooks.now ?? Date.now,
158
+ now: setup.deps.now ?? Date.now,
160
159
  warnings: setup.warnings,
161
160
  })
162
161
  : undefined;
@@ -175,7 +174,7 @@ async function runScriptedPlanInScope(plan, input, scope) {
175
174
  artifactRoot,
176
175
  }, {
177
176
  surfaces: setup.surfaces,
178
- hooks: setup.hooks,
177
+ deps: setup.deps,
179
178
  browserCommand: setup.browserCommand,
180
179
  runPaths,
181
180
  });
@@ -9,7 +9,7 @@ interface ResolvedScriptedScenario {
9
9
  }
10
10
  /**
11
11
  * Resolve and consume `scenario.ref`. Path-style refs (contain a separator or end .yaml/.yml)
12
- * resolve against cwd and are CLAMPED inside it — a ../../ escape is rejected, never recorded
12
+ * resolve against cwd and are clamped inside it: a ../../ escape is rejected, never recorded
13
13
  * as repo-relative provenance. Id-style refs must be public-safe tokens and resolve to
14
14
  * humanish/scenarios/<ref>.yaml (then .yml). Every failure mode is fail-closed. planScriptedLab
15
15
  * has already refused a missing or blank ref.
@@ -11,7 +11,7 @@ import { readContainedRegularFile, } from "../../run/contained-output.js";
11
11
  const SCENARIO_REF_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
12
12
  /**
13
13
  * Resolve and consume `scenario.ref`. Path-style refs (contain a separator or end .yaml/.yml)
14
- * resolve against cwd and are CLAMPED inside it — a ../../ escape is rejected, never recorded
14
+ * resolve against cwd and are clamped inside it: a ../../ escape is rejected, never recorded
15
15
  * as repo-relative provenance. Id-style refs must be public-safe tokens and resolve to
16
16
  * humanish/scenarios/<ref>.yaml (then .yml). Every failure mode is fail-closed. planScriptedLab
17
17
  * has already refused a missing or blank ref.
@@ -1,12 +1,13 @@
1
1
  import type { ActorPersonaRef } from "../../actors/contract.js";
2
2
  import type { BrowserPersonaJourney, ScriptedBrowserEvidenceUrlPolicy } from "../../actors/scripted-browser/types.js";
3
3
  import type { ScriptedPlan } from "../../lab/plan-types.js";
4
- import { type ScriptedBrowserLabHooks, type ScriptedBrowserLabResult, type ScriptedRunInput } from "./types.js";
4
+ import { type ScriptedBrowserLabResult, type ScriptedRunInput } from "./types.js";
5
+ import type { LabDeps } from "../../lab/lab-deps.js";
5
6
  /** What setup hands the run: the plan's subject and scenario, keys and the browser to launch. */
6
7
  export interface ScriptedRunSetup {
7
8
  cwd: string;
8
9
  physicalCwd: string;
9
- hooks: ScriptedBrowserLabHooks;
10
+ deps: LabDeps;
10
11
  warnings: string[];
11
12
  failed: (code: NonNullable<ScriptedBrowserLabResult["error"]>["code"], message: string) => ScriptedBrowserLabResult;
12
13
  clone: Extract<ScriptedPlan["subject"], {
@@ -2,6 +2,7 @@
2
2
  // the E2B key and subject env of a live clone, a browser to launch) and the values the run reads
3
3
  // (the evidence URL policy, the scrubber for clone values, the persona and the session budget).
4
4
  import { realpath } from "node:fs/promises";
5
+ import { missingKeys, missingSubjectEnv } from "../../lab/requirements.js";
5
6
  import path from "node:path";
6
7
  import { resolveBrowserCommand } from "../../actors/scripted-browser/browser-command.js";
7
8
  import { describeMissingKeys } from "../../keys/key-resolution.js";
@@ -21,7 +22,7 @@ export async function prepareScriptedRun(plan, input) {
21
22
  const cwd = path.resolve(input.cwd);
22
23
  const physicalCwd = await realpath(cwd);
23
24
  const projectRoot = await prepareSelectedOutputDirectory(path.dirname(physicalCwd), physicalCwd);
24
- const hooks = input.hooks ?? {};
25
+ const deps = input.deps ?? {};
25
26
  const warnings = [];
26
27
  const clone = plan.subject.kind === "clone" ? plan.subject : undefined;
27
28
  const evidenceAppUrl = evidenceAppUrlOf(plan.subject);
@@ -42,7 +43,7 @@ export async function prepareScriptedRun(plan, input) {
42
43
  ? { kind: "provisioned-subject", evidenceOrigin: evidenceAppUrl }
43
44
  : { kind: "loopback" };
44
45
  const subjectEnvNames = [...(clone?.env ?? [])];
45
- const env = hooks.env ?? process.env;
46
+ const env = input.env ?? process.env;
46
47
  const e2bApiKey = env.E2B_API_KEY?.trim() ?? "";
47
48
  const hasGithubToken = subjectEnvNames.includes("GITHUB_TOKEN");
48
49
  const redactRepoLabel = plan.residual.policies?.redactRepos ?? hasGithubToken;
@@ -61,33 +62,33 @@ export async function prepareScriptedRun(plan, input) {
61
62
  };
62
63
  }
63
64
  const journey = scenario.journey;
64
- if (!dryRun && clone) {
65
- if (!e2bApiKey) {
66
- return {
67
- ok: false,
68
- result: failed("HUMANISH_SCRIPTED_LAB_KEYS_MISSING", `Live clone scripted-browser labs require E2B_API_KEY (dry-run remains $0 and does not provision a subject). ${describeMissingKeys(["E2B_API_KEY"], env)}`),
69
- };
70
- }
71
- const missingSubjectEnv = subjectEnvNames.filter((name) => !env[name]?.trim());
72
- if (missingSubjectEnv.length > 0) {
73
- return {
74
- ok: false,
75
- result: failed("HUMANISH_SCRIPTED_LAB_SUBJECT_ENV_MISSING", `Subject env values missing for live clone scripted-browser lab: ${missingSubjectEnv.join(", ")}.`),
76
- };
77
- }
65
+ // The plan lists E2B_API_KEY and the subject env only for a live clone.
66
+ const missing = missingKeys(plan.requirements, env);
67
+ if (missing.length > 0) {
68
+ return {
69
+ ok: false,
70
+ result: failed("HUMANISH_SCRIPTED_LAB_KEYS_MISSING", `Live clone scripted-browser labs require ${missing.join(" and ")} (dry-run remains $0 and does not provision a subject). ${describeMissingKeys(missing, env)}`),
71
+ };
72
+ }
73
+ const unsetSubjectEnv = missingSubjectEnv(plan.requirements, env);
74
+ if (unsetSubjectEnv.length > 0) {
75
+ return {
76
+ ok: false,
77
+ result: failed("HUMANISH_SCRIPTED_LAB_SUBJECT_ENV_MISSING", `Subject env values missing for live clone scripted-browser lab: ${unsetSubjectEnv.join(", ")}.`),
78
+ };
78
79
  }
79
80
  const surfaces = plan.surfaces;
80
81
  const timeoutMs = plan.sessionTimeoutMs ?? DEFAULT_SESSION_TIMEOUT_MS;
81
82
  const persona = {
82
83
  id: plan.personaId ?? "scripted-journey",
83
84
  traitsApplied: [],
84
- // The step manifest IS the "prompt" on this lane; the digest binds the trace to the
85
+ // The step manifest is the "prompt" on this route; the digest binds the trace to the
85
86
  // committed scenario text.
86
87
  promptDigest: journey.sourceDigest.slice(0, 16),
87
88
  };
88
- // Live runs need a browser BEFORE any actuation (unless one is injected).
89
- let browserCommand = hooks.browserCommand;
90
- if (!dryRun && !hooks.launchBrowser && !browserCommand) {
89
+ // Live runs need a browser before any actuation (unless one is injected).
90
+ let browserCommand = deps.browserCommand;
91
+ if (!dryRun && !deps.launchBrowser && !browserCommand) {
91
92
  const resolved = await resolveBrowserCommand();
92
93
  if (!resolved) {
93
94
  return {
@@ -102,7 +103,7 @@ export async function prepareScriptedRun(plan, input) {
102
103
  setup: {
103
104
  cwd,
104
105
  physicalCwd,
105
- hooks,
106
+ deps,
106
107
  warnings,
107
108
  failed,
108
109
  clone,
@@ -2,7 +2,8 @@ import type { ScriptedPlan } from "../../lab/plan-types.js";
2
2
  import { type PreparedRunArtifactPaths } from "../../run/paths.js";
3
3
  import type { RunSubjectStateStepRecord } from "../../run/bundle.js";
4
4
  import { type DesktopResourceObservation } from "../../substrates/e2b/desktop-resources.js";
5
- import type { ScriptedBrowserLabHooks } from "./types.js";
5
+ import type { LabDeps } from "../../lab/lab-deps.js";
6
+ import type { RunLabHomes } from "../../lab/run-lab-homes.js";
6
7
  type ScriptedCloneSubject = Extract<ScriptedPlan["subject"], {
7
8
  readonly kind: "clone";
8
9
  }>;
@@ -10,8 +11,10 @@ type ScriptedCloneSubject = Extract<ScriptedPlan["subject"], {
10
11
  export interface ScriptedSubjectInputs {
11
12
  plan: ScriptedPlan;
12
13
  clone: ScriptedCloneSubject;
13
- hooks: ScriptedBrowserLabHooks;
14
- env: Record<string, string | undefined>;
14
+ deps: LabDeps;
15
+ /** Runs after the subject sandbox exists and before provisioning. */
16
+ prepareDesktop?: NonNullable<RunLabHomes["prepareDesktop"]>;
17
+ env: Readonly<Record<string, string | undefined>>;
15
18
  e2bApiKey: string;
16
19
  runPaths: PreparedRunArtifactPaths;
17
20
  timeoutMs: number;
@@ -26,6 +29,8 @@ export interface ScriptedSubjectInputs {
26
29
  export declare class ScriptedSubject {
27
30
  sandboxId: string | undefined;
28
31
  killed: boolean;
32
+ /** The scrubbed release warning when the subject's release is unconfirmed. */
33
+ releaseWarning: string | undefined;
29
34
  commit: string | undefined;
30
35
  hostDigest: string | undefined;
31
36
  readonly stateStepRecords: RunSubjectStateStepRecord[];
@@ -37,6 +37,8 @@ function hostOriginDigest(url) {
37
37
  export class ScriptedSubject {
38
38
  sandboxId;
39
39
  killed = false;
40
+ /** The scrubbed release warning when the subject's release is unconfirmed. */
41
+ releaseWarning;
40
42
  commit;
41
43
  hostDigest;
42
44
  stateStepRecords = [];
@@ -50,15 +52,15 @@ export class ScriptedSubject {
50
52
  }
51
53
  /** Acquires, provisions and serves the subject. Returns the tokenless getHost URL to drive. */
52
54
  async provision() {
53
- const { plan, clone, hooks, env, e2bApiKey, runPaths, timeoutMs } = this.inputs;
55
+ const { plan, clone, deps, prepareDesktop, env, e2bApiKey, runPaths, timeoutMs } = this.inputs;
54
56
  const { subjectEnvNames, hasGithubToken, scrubKnownValues, now } = this.inputs;
55
57
  const requestTimeoutMs = e2bRequestTimeoutMs(env);
56
- const timers = hooks.detachedTimers ?? {};
58
+ const timers = deps.detachedTimers ?? {};
57
59
  const subjectSandboxTimeoutMs = timeoutMs +
58
60
  SUBJECT_PROVISION_BUDGET_MS +
59
61
  (clone.state?.seed ?? []).reduce((sum, step) => sum + (step.timeoutMs ?? DEFAULT_STATE_STEP_TIMEOUT_MS), 0) +
60
62
  SANDBOX_TIMEOUT_BUFFER_MS;
61
- const subjectModule = await (hooks.loadDesktopModule ?? loadE2BDesktopModule)();
63
+ const subjectModule = await (deps.desktopModule ?? loadE2BDesktopModule)();
62
64
  await validatePreparedRunArtifactPaths(runPaths);
63
65
  // The receipt is on disk before any work on the sandbox, so `humanish reclaim` can kill
64
66
  // it by exact id when this process dies mid-run; the finally block below only runs while
@@ -92,8 +94,8 @@ export class ScriptedSubject {
92
94
  this.sandboxId = subject.allocation.resourceId;
93
95
  this.createdAtMs = now();
94
96
  this.resources = await observeDesktopResources(subjectDesktop);
95
- if (hooks.prepareDesktop) {
96
- await hooks.prepareDesktop(subjectDesktop);
97
+ if (prepareDesktop) {
98
+ await prepareDesktop(subjectDesktop, { kind: "subject" });
97
99
  await validatePreparedRunArtifactPaths(runPaths);
98
100
  }
99
101
  this.commit = await provisionCloneSubject(e2bShell(subjectDesktop), {
@@ -137,6 +139,8 @@ export class ScriptedSubject {
137
139
  this.killed = reading.released;
138
140
  if (reading.warning)
139
141
  warnings.push(reading.warning);
142
+ if (!reading.released)
143
+ this.releaseWarning = reading.warning ?? "Subject sandbox release is unconfirmed.";
140
144
  // Without a kill method, or in E2B debug mode, no kill reached E2B, so there is no teardown
141
145
  // time to record.
142
146
  if (released.status !== "unconfirmed" || released.reason !== "release_unavailable")
@@ -44,7 +44,7 @@ export function scriptedSurfaceRecords(context, surface, index, result, screensh
44
44
  embed: lastScreenshot
45
45
  ? { kind: "screenshot", url: `../${lastScreenshot}`, title: `${surface.label} (raw)` }
46
46
  : { kind: "placeholder", title: surface.label },
47
- // REAL emulated viewport: isMobile/deviceScaleFactor genuinely render on this route
47
+ // Real emulated viewport: isMobile/deviceScaleFactor genuinely render on this route
48
48
  // (playwright emulation), unlike the e2b-desktop route's prompt-signal-only fidelity.
49
49
  viewport: surface.viewport,
50
50
  ui: {
@@ -1,11 +1,11 @@
1
1
  import { type ScriptedBrowserSessionOptions, type ScriptedBrowserSessionResult } from "../../actors/scripted-browser/actor.js";
2
2
  import type { ScriptedPlan } from "../../lab/plan-types.js";
3
3
  import { type PreparedRunArtifactPaths } from "../../run/paths.js";
4
- import type { ScriptedBrowserLabHooks } from "./types.js";
4
+ import type { LabDeps } from "../../lab/lab-deps.js";
5
5
  /** One session per surface, in parallel. */
6
6
  export declare function runScriptedSessions(session: Required<Pick<ScriptedBrowserSessionOptions, "appUrl" | "evidenceAppUrl" | "urlPolicy" | "journey" | "persona" | "timeoutMs" | "artifactRoot">>, run: {
7
7
  surfaces: ScriptedPlan["surfaces"];
8
- hooks: ScriptedBrowserLabHooks;
8
+ deps: LabDeps;
9
9
  browserCommand: string | undefined;
10
10
  runPaths: PreparedRunArtifactPaths;
11
11
  }): Promise<ScriptedBrowserSessionResult[]>;
@@ -7,8 +7,8 @@ import { validateScriptedSessionResult } from "./session-result.js";
7
7
  /** One session per surface, in parallel. */
8
8
  export function runScriptedSessions(session, run) {
9
9
  const { appUrl, evidenceAppUrl, urlPolicy, journey, persona, timeoutMs, artifactRoot } = session;
10
- const { surfaces, hooks, browserCommand, runPaths } = run;
11
- const runSession = hooks.runSession;
10
+ const { surfaces, deps, browserCommand, runPaths } = run;
11
+ const runSession = deps.runScriptedSession;
12
12
  return Promise.all(surfaces.map((surface) => {
13
13
  const sessionOptions = {
14
14
  appUrl,
@@ -20,8 +20,8 @@ export function runScriptedSessions(session, run) {
20
20
  timeoutMs,
21
21
  artifactRoot,
22
22
  ...(browserCommand === undefined ? {} : { browserCommand }),
23
- ...(hooks.launchBrowser === undefined ? {} : { launchBrowser: hooks.launchBrowser }),
24
- ...(hooks.now === undefined ? {} : { now: hooks.now }),
23
+ ...(deps.launchBrowser === undefined ? {} : { launchBrowser: deps.launchBrowser }),
24
+ ...(deps.now === undefined ? {} : { now: deps.now }),
25
25
  };
26
26
  return runSession
27
27
  ? runSession(sessionOptions).then(async (result) => {