humanish 0.106.1 → 0.108.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 (668) hide show
  1. package/ARCHITECTURE.md +38 -32
  2. package/CHANGELOG.md +28 -0
  3. package/CONTEXT.md +51 -41
  4. package/README.md +152 -174
  5. package/SECURITY.md +16 -26
  6. package/TELEMETRY.md +8 -6
  7. package/dist/actors/affordance.d.ts +4 -4
  8. package/dist/actors/affordance.js +12 -12
  9. package/dist/actors/agent-session.d.ts +2 -2
  10. package/dist/actors/agent-session.js +7 -7
  11. package/dist/actors/codex/app-server-actor-trace.d.ts +1 -1
  12. package/dist/actors/codex/app-server-actor-trace.js +1 -1
  13. package/dist/actors/codex/app-server-client.js +2 -1
  14. package/dist/actors/codex/app-server-trace.d.ts +0 -1
  15. package/dist/actors/codex/app-server-trace.js +1 -3
  16. package/dist/actors/codex/app-server-ui.js +1 -1
  17. package/dist/actors/codex/app-server.js +2 -1
  18. package/dist/actors/codex/codex-admission.d.ts +91 -0
  19. package/dist/actors/codex/codex-admission.js +150 -0
  20. package/dist/actors/codex/protocol-compat.d.ts +27 -0
  21. package/dist/actors/codex/protocol-compat.js +357 -0
  22. package/dist/actors/codex/protocol-contract.d.ts +61 -0
  23. package/dist/actors/codex/protocol-contract.js +471 -0
  24. package/dist/actors/codex/restricted-executable.d.ts +28 -4
  25. package/dist/actors/codex/restricted-executable.js +104 -29
  26. package/dist/actors/codex/restricted-launch.d.ts +9 -2
  27. package/dist/actors/codex/restricted-launch.js +43 -4
  28. package/dist/actors/codex/restricted-notifications.d.ts +101 -0
  29. package/dist/actors/codex/restricted-notifications.js +277 -0
  30. package/dist/actors/codex/restricted-participant.d.ts +30 -0
  31. package/dist/actors/codex/restricted-participant.js +66 -6
  32. package/dist/actors/codex/restricted-policy.d.ts +11 -3
  33. package/dist/actors/codex/restricted-policy.js +2 -2
  34. package/dist/actors/codex/restricted-session.d.ts +16 -3
  35. package/dist/actors/codex/restricted-session.js +60 -22
  36. package/dist/actors/codex/restricted-transport.d.ts +29 -0
  37. package/dist/actors/codex/restricted-transport.js +139 -27
  38. package/dist/actors/codex/restricted-turn.d.ts +19 -4
  39. package/dist/actors/codex/restricted-turn.js +43 -30
  40. package/dist/actors/computer-use/actor.d.ts +17 -17
  41. package/dist/actors/computer-use/actor.js +6 -6
  42. package/dist/actors/computer-use/admission-limit.d.ts +1 -1
  43. package/dist/actors/computer-use/admission-limit.js +1 -1
  44. package/dist/actors/computer-use/loop/actions.d.ts +3 -3
  45. package/dist/actors/computer-use/loop/actions.js +10 -10
  46. package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
  47. package/dist/actors/computer-use/loop/backstop.js +15 -13
  48. package/dist/actors/computer-use/loop/ending.d.ts +7 -7
  49. package/dist/actors/computer-use/loop/ending.js +9 -9
  50. package/dist/actors/computer-use/loop/observation.d.ts +2 -2
  51. package/dist/actors/computer-use/loop/observation.js +9 -9
  52. package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
  53. package/dist/actors/computer-use/loop/provider-call.js +1 -1
  54. package/dist/actors/computer-use/loop/session.js +3 -3
  55. package/dist/actors/computer-use/loop/spend.d.ts +2 -2
  56. package/dist/actors/computer-use/loop/spend.js +4 -4
  57. package/dist/actors/computer-use/loop/trace.js +11 -10
  58. package/dist/actors/computer-use/loop/types.d.ts +37 -26
  59. package/dist/actors/computer-use/loop/usage.js +2 -2
  60. package/dist/actors/computer-use/loop.js +4 -4
  61. package/dist/actors/computer-use/openai-context.d.ts +37 -0
  62. package/dist/actors/computer-use/openai-context.js +214 -0
  63. package/dist/actors/computer-use/openai-provider.d.ts +12 -9
  64. package/dist/actors/computer-use/openai-provider.js +47 -36
  65. package/dist/actors/computer-use/openai-requests.d.ts +36 -10
  66. package/dist/actors/computer-use/openai-requests.js +82 -15
  67. package/dist/actors/computer-use/openai-wire.d.ts +19 -7
  68. package/dist/actors/computer-use/openai-wire.js +36 -34
  69. package/dist/actors/contract.d.ts +86 -49
  70. package/dist/actors/contract.js +29 -23
  71. package/dist/actors/local-agent/claude-session.d.ts +1 -1
  72. package/dist/actors/local-agent/claude-session.js +10 -9
  73. package/dist/actors/local-agent/cli.d.ts +8 -6
  74. package/dist/actors/local-agent/cli.js +24 -28
  75. package/dist/actors/local-agent/readiness.d.ts +2 -2
  76. package/dist/actors/local-agent/readiness.js +4 -4
  77. package/dist/actors/reasoning-effort.js +6 -6
  78. package/dist/actors/registry.d.ts +10 -10
  79. package/dist/actors/registry.js +18 -17
  80. package/dist/actors/scripted-browser/actor.d.ts +8 -8
  81. package/dist/actors/scripted-browser/actor.js +16 -16
  82. package/dist/actors/scripted-browser/browser-command.js +1 -1
  83. package/dist/actors/scripted-browser/journey.js +15 -4
  84. package/dist/actors/scripted-browser/steps.js +19 -1
  85. package/dist/actors/scripted-browser/types.d.ts +12 -2
  86. package/dist/actors/stop-conditions.d.ts +1 -1
  87. package/dist/actors/stop-conditions.js +1 -3
  88. package/dist/analysis/automatic-completion.d.ts +13 -8
  89. package/dist/analysis/automatic-completion.js +14 -8
  90. package/dist/analysis/automatic-config.d.ts +1 -1
  91. package/dist/analysis/automatic-config.js +2 -2
  92. package/dist/analysis/automatic.d.ts +10 -4
  93. package/dist/analysis/automatic.js +17 -13
  94. package/dist/analysis/codex-config.d.ts +6 -2
  95. package/dist/analysis/codex-config.js +22 -14
  96. package/dist/analysis/diagnostics.d.ts +23 -0
  97. package/dist/analysis/diagnostics.js +112 -0
  98. package/dist/analysis/evidence-sources.js +2 -2
  99. package/dist/analysis/evidence.js +6 -6
  100. package/dist/analysis/execute.d.ts +7 -1
  101. package/dist/analysis/execute.js +39 -12
  102. package/dist/analysis/job.d.ts +8 -5
  103. package/dist/analysis/job.js +15 -14
  104. package/dist/analysis/load.d.ts +1 -1
  105. package/dist/analysis/load.js +5 -5
  106. package/dist/analysis/provider.d.ts +9 -1
  107. package/dist/analysis/restricted-codex.d.ts +2 -0
  108. package/dist/analysis/restricted-codex.js +10 -1
  109. package/dist/analysis/service.d.ts +2 -0
  110. package/dist/analysis/service.js +35 -16
  111. package/dist/analysis/sharing.d.ts +2 -2
  112. package/dist/analysis/sharing.js +5 -5
  113. package/dist/analysis/store-executions.d.ts +5 -5
  114. package/dist/analysis/store-executions.js +12 -12
  115. package/dist/analysis/store.d.ts +4 -4
  116. package/dist/analysis/store.js +13 -13
  117. package/dist/cli/commands/analysis-signals.d.ts +2 -1
  118. package/dist/cli/commands/analysis-signals.js +4 -1
  119. package/dist/cli/commands/analyze.js +23 -18
  120. package/dist/cli/commands/codex.js +9 -9
  121. package/dist/cli/commands/comms.js +62 -34
  122. package/dist/cli/commands/feedback.js +20 -21
  123. package/dist/cli/commands/lab-format.d.ts +5 -4
  124. package/dist/cli/commands/lab-format.js +35 -23
  125. package/dist/cli/commands/lab-route-computer-use.d.ts +0 -2
  126. package/dist/cli/commands/lab-route-computer-use.js +32 -21
  127. package/dist/cli/commands/lab-route-preview.d.ts +1 -3
  128. package/dist/cli/commands/lab-route-preview.js +7 -7
  129. package/dist/cli/commands/lab-route-run.d.ts +6 -4
  130. package/dist/cli/commands/lab-route-run.js +6 -2
  131. package/dist/cli/commands/lab-route-scripted.d.ts +0 -2
  132. package/dist/cli/commands/lab-route-scripted.js +0 -1
  133. package/dist/cli/commands/lab-route-shared-world.d.ts +0 -2
  134. package/dist/cli/commands/lab-route-shared-world.js +3 -4
  135. package/dist/cli/commands/lab-route-terminal.d.ts +0 -2
  136. package/dist/cli/commands/lab-route-terminal.js +0 -1
  137. package/dist/cli/commands/lab-run.js +84 -54
  138. package/dist/cli/commands/lab-scorer.d.ts +2 -4
  139. package/dist/cli/commands/lab-scorer.js +1 -1
  140. package/dist/cli/commands/migrate.d.ts +4 -0
  141. package/dist/cli/commands/migrate.js +65 -0
  142. package/dist/cli/commands/observe.js +168 -107
  143. package/dist/cli/commands/run-command.d.ts +10 -0
  144. package/dist/cli/commands/run-command.js +85 -0
  145. package/dist/cli/commands/run-signals.d.ts +30 -0
  146. package/dist/cli/commands/run-signals.js +146 -0
  147. package/dist/cli/commands/runs.js +137 -136
  148. package/dist/cli/commands/setup.d.ts +2 -2
  149. package/dist/cli/commands/setup.js +26 -21
  150. package/dist/cli/commands/study.d.ts +3 -0
  151. package/dist/cli/commands/study.js +182 -0
  152. package/dist/cli/commands/tui.d.ts +4 -4
  153. package/dist/cli/commands/tui.js +21 -21
  154. package/dist/cli/commands/watch.js +64 -77
  155. package/dist/cli/deprecations.d.ts +18 -0
  156. package/dist/cli/deprecations.js +48 -0
  157. package/dist/cli/doctor.d.ts +18 -5
  158. package/dist/cli/doctor.js +111 -48
  159. package/dist/cli/first-run-path.d.ts +12 -10
  160. package/dist/cli/first-run-path.js +30 -28
  161. package/dist/cli/io.d.ts +46 -10
  162. package/dist/cli/io.js +109 -30
  163. package/dist/cli/observer-follow.d.ts +2 -2
  164. package/dist/cli/observer-follow.js +5 -6
  165. package/dist/cli/orientation.d.ts +6 -3
  166. package/dist/cli/orientation.js +43 -39
  167. package/dist/cli/product-sentence.d.ts +6 -0
  168. package/dist/cli/product-sentence.js +6 -0
  169. package/dist/cli/program.d.ts +6 -1
  170. package/dist/cli/program.js +112 -43
  171. package/dist/cli/telemetry.d.ts +17 -17
  172. package/dist/cli/telemetry.js +49 -41
  173. package/dist/cli.js +1 -1
  174. package/dist/comms/capture-surface.d.ts +14 -13
  175. package/dist/comms/capture-surface.js +23 -22
  176. package/dist/comms/catch-host.d.ts +8 -8
  177. package/dist/comms/catch-host.js +14 -14
  178. package/dist/comms/connections.js +4 -4
  179. package/dist/comms/email-catch.d.ts +3 -3
  180. package/dist/comms/email-catch.js +8 -8
  181. package/dist/comms/external-evidence.d.ts +27 -0
  182. package/dist/comms/external-evidence.js +93 -0
  183. package/dist/comms/extract.js +2 -2
  184. package/dist/comms/fake-inbox.d.ts +2 -2
  185. package/dist/comms/fake-inbox.js +2 -2
  186. package/dist/comms/lease-store.js +7 -7
  187. package/dist/comms/receiving-render.d.ts +1 -1
  188. package/dist/comms/receiving-render.js +2 -2
  189. package/dist/comms/sandbox-catch-script.d.ts +6 -6
  190. package/dist/comms/sandbox-catch-script.js +6 -6
  191. package/dist/comms/sandbox-catch.d.ts +36 -37
  192. package/dist/comms/sandbox-catch.js +34 -35
  193. package/dist/comms/setup.js +42 -8
  194. package/dist/comms/thread-evidence.d.ts +1 -1
  195. package/dist/comms/thread-evidence.js +6 -6
  196. package/dist/comms/types.d.ts +6 -6
  197. package/dist/comms/types.js +4 -4
  198. package/dist/evidence/browser-hygiene.d.ts +1 -1
  199. package/dist/evidence/browser-hygiene.js +1 -1
  200. package/dist/evidence/frame-signature.d.ts +1 -1
  201. package/dist/evidence/frame-signature.js +4 -4
  202. package/dist/evidence/redaction.d.ts +3 -3
  203. package/dist/evidence/redaction.js +5 -5
  204. package/dist/evidence/secret-scrub.d.ts +9 -0
  205. package/dist/evidence/secret-scrub.js +96 -0
  206. package/dist/feedback/draft.js +41 -85
  207. package/dist/feedback/export-bundle.js +5 -5
  208. package/dist/feedback/export.d.ts +5 -1
  209. package/dist/feedback/export.js +16 -17
  210. package/dist/feedback/feedback.d.ts +3 -3
  211. package/dist/feedback/feedback.js +21 -3
  212. package/dist/guest/chromium-text.js +2 -2
  213. package/dist/guest/desktop-native.d.ts +1 -1
  214. package/dist/guest/runtime.js +1 -1
  215. package/dist/index.d.ts +14 -15
  216. package/dist/index.js +10 -11
  217. package/dist/keys/key-resolution.d.ts +7 -5
  218. package/dist/keys/key-resolution.js +40 -38
  219. package/dist/lab/adapter-extension.d.ts +35 -13
  220. package/dist/lab/adapter-extension.js +50 -134
  221. package/dist/lab/adapter-scorer-loader.d.ts +32 -12
  222. package/dist/lab/adapter-scorer-loader.js +56 -32
  223. package/dist/lab/composition-rules.js +58 -58
  224. package/dist/lab/config.js +85 -43
  225. package/dist/lab/deprecated-fields.d.ts +10 -0
  226. package/dist/lab/deprecated-fields.js +24 -0
  227. package/dist/lab/device-presets.d.ts +10 -10
  228. package/dist/lab/device-presets.js +11 -11
  229. package/dist/lab/discover.d.ts +13 -9
  230. package/dist/lab/discover.js +118 -60
  231. package/dist/lab/doctor.d.ts +53 -11
  232. package/dist/lab/doctor.js +193 -47
  233. package/dist/lab/init-plan.js +1 -3
  234. package/dist/lab/init-templates.js +147 -147
  235. package/dist/lab/init.d.ts +1 -1
  236. package/dist/lab/init.js +41 -9
  237. package/dist/lab/keys.d.ts +2 -0
  238. package/dist/lab/keys.js +43 -9
  239. package/dist/lab/lab-deps.d.ts +80 -0
  240. package/dist/lab/lab-deps.js +4 -0
  241. package/dist/lab/parse/actors.js +17 -16
  242. package/dist/lab/parse/comms.js +8 -7
  243. package/dist/lab/parse/execution.js +15 -14
  244. package/dist/lab/parse/study-v3.d.ts +23 -0
  245. package/dist/lab/parse/study-v3.js +259 -0
  246. package/dist/lab/parse/subject-state.d.ts +7 -7
  247. package/dist/lab/parse/subject-state.js +18 -17
  248. package/dist/lab/parse/subject.js +30 -29
  249. package/dist/lab/parse/values.d.ts +1 -2
  250. package/dist/lab/parse/values.js +3 -6
  251. package/dist/lab/persona-resolve.d.ts +7 -7
  252. package/dist/lab/persona-resolve.js +8 -8
  253. package/dist/lab/persona.js +1 -3
  254. package/dist/lab/plan-base.d.ts +0 -2
  255. package/dist/lab/plan-base.js +6 -4
  256. package/dist/lab/plan-participants.d.ts +7 -7
  257. package/dist/lab/plan-participants.js +2 -2
  258. package/dist/lab/plan-types.d.ts +26 -8
  259. package/dist/lab/plan.d.ts +4 -18
  260. package/dist/lab/plan.js +24 -79
  261. package/dist/lab/preflight-probes.js +11 -11
  262. package/dist/lab/preflight-result.d.ts +2 -1
  263. package/dist/lab/preflight-result.js +5 -6
  264. package/dist/lab/preflight.d.ts +7 -8
  265. package/dist/lab/preflight.js +6 -6
  266. package/dist/lab/requirements.d.ts +20 -0
  267. package/dist/lab/requirements.js +54 -0
  268. package/dist/lab/route-inputs.d.ts +23 -12
  269. package/dist/lab/route-inputs.js +48 -51
  270. package/dist/lab/routing.d.ts +42 -41
  271. package/dist/lab/routing.js +66 -68
  272. package/dist/lab/run-lab-events.d.ts +3 -11
  273. package/dist/lab/run-lab-events.js +2 -16
  274. package/dist/lab/run-lab-homes.d.ts +76 -0
  275. package/dist/lab/run-lab-homes.js +7 -0
  276. package/dist/lab/run-lab-options.d.ts +12 -66
  277. package/dist/lab/run-lab-options.js +58 -285
  278. package/dist/lab/summary.d.ts +15 -9
  279. package/dist/lab/summary.js +24 -17
  280. package/dist/lab/tasks.d.ts +15 -15
  281. package/dist/lab/tasks.js +14 -14
  282. package/dist/lab/types.d.ts +201 -195
  283. package/dist/lab/types.js +2 -0
  284. package/dist/lab/validation.d.ts +21 -21
  285. package/dist/lab/validation.js +61 -59
  286. package/dist/lab/warnings.d.ts +10 -0
  287. package/dist/lab/warnings.js +70 -41
  288. package/dist/library-aliases.d.ts +56 -0
  289. package/dist/library-aliases.js +22 -0
  290. package/dist/observer/artifact.d.ts +2 -2
  291. package/dist/observer/artifact.js +9 -9
  292. package/dist/observer/data.d.ts +6 -6
  293. package/dist/observer/data.js +7 -6
  294. package/dist/observer/exposure.d.ts +1 -1
  295. package/dist/observer/exposure.js +11 -11
  296. package/dist/observer/http.js +1 -1
  297. package/dist/observer/library.d.ts +1 -1
  298. package/dist/observer/library.js +4 -2
  299. package/dist/observer/listen.js +5 -4
  300. package/dist/observer/render.d.ts +1 -1
  301. package/dist/observer/render.js +12 -7
  302. package/dist/observer/run-routes.d.ts +4 -4
  303. package/dist/observer/run-routes.js +6 -6
  304. package/dist/observer/serve.d.ts +17 -0
  305. package/dist/observer/serve.js +41 -6
  306. package/dist/observer/tunnel.js +1 -1
  307. package/dist/observer-app.html +4 -4
  308. package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
  309. package/dist/routes/computer-use/bundle-parts.js +24 -17
  310. package/dist/routes/computer-use/bundle.d.ts +4 -11
  311. package/dist/routes/computer-use/bundle.js +12 -18
  312. package/dist/routes/computer-use/diagnostics.d.ts +1 -1
  313. package/dist/routes/computer-use/diagnostics.js +1 -1
  314. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +11 -11
  315. package/dist/routes/computer-use/e2b-desktop/comms.js +24 -27
  316. package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +2 -2
  317. package/dist/routes/computer-use/e2b-desktop/desktop.js +8 -11
  318. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +16 -15
  319. package/dist/routes/computer-use/e2b-desktop/fidelity.js +20 -19
  320. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +3 -3
  321. package/dist/routes/computer-use/e2b-desktop/prepare.js +40 -43
  322. package/dist/routes/computer-use/e2b-desktop/start.d.ts +1 -1
  323. package/dist/routes/computer-use/e2b-desktop/start.js +32 -30
  324. package/dist/routes/computer-use/e2b-desktop/state.d.ts +5 -4
  325. package/dist/routes/computer-use/e2b-desktop/state.js +5 -3
  326. package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +1 -1
  327. package/dist/routes/computer-use/e2b-desktop/teardown.js +33 -20
  328. package/dist/routes/computer-use/external-comms.d.ts +4 -4
  329. package/dist/routes/computer-use/external-comms.js +19 -43
  330. package/dist/routes/computer-use/fanout-bundle.d.ts +3 -3
  331. package/dist/routes/computer-use/fanout-bundle.js +38 -42
  332. package/dist/routes/computer-use/{fanout-lanes.js → fanout-records.js} +33 -28
  333. package/dist/routes/computer-use/in-process-desktop.d.ts +3 -10
  334. package/dist/routes/computer-use/in-process-desktop.js +3 -9
  335. package/dist/routes/computer-use/live-flush.d.ts +7 -5
  336. package/dist/routes/computer-use/live-flush.js +20 -28
  337. package/dist/routes/computer-use/{run-lanes.d.ts → live-phase.d.ts} +4 -2
  338. package/dist/routes/computer-use/{run-lanes.js → live-phase.js} +17 -16
  339. package/dist/routes/computer-use/local-tree-pack.d.ts +3 -3
  340. package/dist/routes/computer-use/local-tree-pack.js +4 -5
  341. package/dist/routes/computer-use/local-vm.d.ts +11 -8
  342. package/dist/routes/computer-use/local-vm.js +40 -67
  343. package/dist/routes/computer-use/participant-desktop.d.ts +8 -23
  344. package/dist/routes/computer-use/participant-desktop.js +5 -25
  345. package/dist/routes/computer-use/{lanes.d.ts → participant-execution.d.ts} +11 -11
  346. package/dist/routes/computer-use/{lanes.js → participant-execution.js} +39 -26
  347. package/dist/routes/computer-use/participant-facts.d.ts +7 -1
  348. package/dist/routes/computer-use/participant-facts.js +12 -1
  349. package/dist/routes/computer-use/participant-model.d.ts +25 -11
  350. package/dist/routes/computer-use/participant-model.js +76 -34
  351. package/dist/routes/computer-use/participant-prompt.d.ts +13 -13
  352. package/dist/routes/computer-use/participant-prompt.js +8 -8
  353. package/dist/routes/computer-use/participant-runs.d.ts +11 -11
  354. package/dist/routes/computer-use/participant-runs.js +18 -18
  355. package/dist/routes/computer-use/plan.d.ts +21 -29
  356. package/dist/routes/computer-use/plan.js +70 -78
  357. package/dist/routes/computer-use/preflight.d.ts +3 -5
  358. package/dist/routes/computer-use/preflight.js +40 -36
  359. package/dist/routes/computer-use/rerun-selection.js +11 -7
  360. package/dist/routes/computer-use/result.d.ts +1 -1
  361. package/dist/routes/computer-use/result.js +48 -38
  362. package/dist/routes/computer-use/route.d.ts +5 -5
  363. package/dist/routes/computer-use/route.js +36 -33
  364. package/dist/routes/computer-use/self-report.d.ts +8 -8
  365. package/dist/routes/computer-use/self-report.js +33 -33
  366. package/dist/routes/computer-use/setup.d.ts +9 -15
  367. package/dist/routes/computer-use/setup.js +106 -83
  368. package/dist/routes/computer-use/single-bundle.d.ts +13 -16
  369. package/dist/routes/computer-use/single-bundle.js +46 -53
  370. package/dist/routes/computer-use/subject-projection.d.ts +6 -8
  371. package/dist/routes/computer-use/subject-projection.js +24 -23
  372. package/dist/routes/computer-use/types.d.ts +195 -238
  373. package/dist/routes/computer-use/types.js +21 -13
  374. package/dist/routes/preview.d.ts +8 -2
  375. package/dist/routes/preview.js +8 -5
  376. package/dist/routes/scripted/bundle.d.ts +5 -8
  377. package/dist/routes/scripted/bundle.js +23 -27
  378. package/dist/routes/scripted/plan.d.ts +6 -8
  379. package/dist/routes/scripted/plan.js +15 -13
  380. package/dist/routes/scripted/result.d.ts +4 -1
  381. package/dist/routes/scripted/result.js +15 -11
  382. package/dist/routes/scripted/route.js +15 -17
  383. package/dist/routes/scripted/scenario.d.ts +1 -1
  384. package/dist/routes/scripted/scenario.js +3 -3
  385. package/dist/routes/scripted/setup.d.ts +3 -2
  386. package/dist/routes/scripted/setup.js +27 -26
  387. package/dist/routes/scripted/subject.d.ts +8 -3
  388. package/dist/routes/scripted/subject.js +10 -6
  389. package/dist/routes/scripted/surface-records.js +4 -4
  390. package/dist/routes/scripted/surface-sessions.d.ts +2 -2
  391. package/dist/routes/scripted/surface-sessions.js +4 -4
  392. package/dist/routes/scripted/types.d.ts +21 -40
  393. package/dist/routes/scripted/types.js +2 -3
  394. package/dist/routes/shared-world/{seat-records.js → bundle-records.js} +17 -16
  395. package/dist/routes/shared-world/bundle.d.ts +7 -7
  396. package/dist/routes/shared-world/bundle.js +60 -62
  397. package/dist/routes/shared-world/checkpoints.d.ts +5 -5
  398. package/dist/routes/shared-world/checkpoints.js +5 -5
  399. package/dist/routes/shared-world/comms.d.ts +8 -7
  400. package/dist/routes/shared-world/comms.js +38 -51
  401. package/dist/routes/shared-world/external-public.d.ts +6 -5
  402. package/dist/routes/shared-world/external-public.js +28 -25
  403. package/dist/routes/shared-world/handoff.d.ts +10 -9
  404. package/dist/routes/shared-world/handoff.js +89 -81
  405. package/dist/routes/shared-world/lobby-code.d.ts +7 -7
  406. package/dist/routes/shared-world/lobby-code.js +22 -22
  407. package/dist/routes/shared-world/{seats.d.ts → participant-specs.d.ts} +15 -12
  408. package/dist/routes/shared-world/{seats.js → participant-specs.js} +65 -63
  409. package/dist/routes/shared-world/plan.d.ts +2 -6
  410. package/dist/routes/shared-world/plan.js +8 -9
  411. package/dist/routes/shared-world/provenance.d.ts +4 -4
  412. package/dist/routes/shared-world/provenance.js +4 -4
  413. package/dist/routes/shared-world/provisioned.d.ts +3 -2
  414. package/dist/routes/shared-world/provisioned.js +55 -48
  415. package/dist/routes/shared-world/result.js +47 -36
  416. package/dist/routes/shared-world/route.js +54 -57
  417. package/dist/routes/shared-world/setup.d.ts +6 -5
  418. package/dist/routes/shared-world/setup.js +16 -18
  419. package/dist/routes/shared-world/types.d.ts +70 -141
  420. package/dist/routes/shared-world/types.js +5 -5
  421. package/dist/routes/terminal/adapter.d.ts +10 -10
  422. package/dist/routes/terminal/adapter.js +32 -129
  423. package/dist/routes/terminal/bundle.d.ts +10 -15
  424. package/dist/routes/terminal/bundle.js +43 -52
  425. package/dist/routes/terminal/credentials.d.ts +4 -4
  426. package/dist/routes/terminal/credentials.js +20 -20
  427. package/dist/routes/terminal/dry-run.d.ts +1 -1
  428. package/dist/routes/terminal/dry-run.js +13 -15
  429. package/dist/routes/terminal/encoding.d.ts +1 -1
  430. package/dist/routes/terminal/encoding.js +4 -4
  431. package/dist/routes/terminal/ledger.d.ts +8 -8
  432. package/dist/routes/terminal/ledger.js +22 -22
  433. package/dist/routes/terminal/live-finish.d.ts +1 -2
  434. package/dist/routes/terminal/live-finish.js +24 -23
  435. package/dist/routes/terminal/live-sandbox.d.ts +3 -2
  436. package/dist/routes/terminal/live-sandbox.js +31 -32
  437. package/dist/routes/terminal/participant-text.d.ts +23 -0
  438. package/dist/routes/terminal/participant-text.js +165 -0
  439. package/dist/routes/terminal/persona.js +1 -1
  440. package/dist/routes/terminal/plan.d.ts +2 -6
  441. package/dist/routes/terminal/plan.js +23 -19
  442. package/dist/routes/terminal/recorder.d.ts +6 -1
  443. package/dist/routes/terminal/recorder.js +12 -4
  444. package/dist/routes/terminal/result.js +12 -12
  445. package/dist/routes/terminal/route.js +30 -31
  446. package/dist/routes/terminal/runtime.d.ts +3 -2
  447. package/dist/routes/terminal/runtime.js +3 -3
  448. package/dist/routes/terminal/sandbox.d.ts +4 -4
  449. package/dist/routes/terminal/sandbox.js +10 -10
  450. package/dist/routes/terminal/session.js +22 -19
  451. package/dist/routes/terminal/token-usage.d.ts +1 -1
  452. package/dist/routes/terminal/token-usage.js +10 -11
  453. package/dist/routes/terminal/trace.d.ts +7 -10
  454. package/dist/routes/terminal/trace.js +11 -66
  455. package/dist/routes/terminal/types.d.ts +104 -114
  456. package/dist/routes/terminal/types.js +12 -7
  457. package/dist/run/active-runs.d.ts +13 -0
  458. package/dist/run/active-runs.js +12 -0
  459. package/dist/run/bundle-shape.d.ts +2 -1
  460. package/dist/run/bundle-shape.js +7 -7
  461. package/dist/run/bundle.d.ts +99 -92
  462. package/dist/run/bundle.js +10 -8
  463. package/dist/run/cost-summary.js +6 -5
  464. package/dist/run/costs.d.ts +6 -6
  465. package/dist/run/costs.js +17 -11
  466. package/dist/run/detail.d.ts +9 -9
  467. package/dist/run/detail.js +10 -10
  468. package/dist/run/dry-run-inputs.js +1 -1
  469. package/dist/run/dry-run.js +23 -30
  470. package/dist/run/{study-files.d.ts → evidence-files.d.ts} +4 -4
  471. package/dist/run/{study-files.js → evidence-files.js} +5 -5
  472. package/dist/run/feedback-shape.js +1 -1
  473. package/dist/run/judge.d.ts +34 -16
  474. package/dist/run/judge.js +41 -14
  475. package/dist/run/locate.d.ts +2 -0
  476. package/dist/run/locate.js +3 -1
  477. package/dist/run/outcomes.d.ts +3 -3
  478. package/dist/run/outcomes.js +3 -3
  479. package/dist/run/participant-records.d.ts +2 -2
  480. package/dist/run/participant-records.js +2 -2
  481. package/dist/run/paths.d.ts +1 -1
  482. package/dist/run/paths.js +2 -2
  483. package/dist/run/pricing.d.ts +30 -15
  484. package/dist/run/pricing.js +49 -30
  485. package/dist/run/projection.d.ts +27 -27
  486. package/dist/run/projection.js +23 -23
  487. package/dist/run/reclaim.d.ts +6 -0
  488. package/dist/run/reclaim.js +15 -5
  489. package/dist/run/results.d.ts +5 -5
  490. package/dist/run/run-index.d.ts +9 -7
  491. package/dist/run/run-index.js +24 -25
  492. package/dist/run/run-not-found.d.ts +5 -0
  493. package/dist/run/run-not-found.js +15 -0
  494. package/dist/run/run.d.ts +7 -4
  495. package/dist/run/run.js +10 -6
  496. package/dist/run/sandbox-receipts.d.ts +5 -5
  497. package/dist/run/sandbox-receipts.js +6 -6
  498. package/dist/run/shared-world-evidence.d.ts +67 -66
  499. package/dist/run/shared-world-evidence.js +4 -4
  500. package/dist/run/shared-world-shape.d.ts +3 -3
  501. package/dist/run/shared-world-shape.js +16 -16
  502. package/dist/run/stats.d.ts +17 -11
  503. package/dist/run/stats.js +124 -66
  504. package/dist/run/status.d.ts +21 -32
  505. package/dist/run/status.js +34 -33
  506. package/dist/run/stored-runs.js +2 -1
  507. package/dist/run/stream-shape.js +1 -1
  508. package/dist/run/streams.d.ts +29 -22
  509. package/dist/run/study-provenance.d.ts +47 -0
  510. package/dist/run/study-provenance.js +63 -0
  511. package/dist/run/study-result.d.ts +16 -0
  512. package/dist/run/study-result.js +9 -0
  513. package/dist/run/terminal-contract.d.ts +5 -5
  514. package/dist/run/terminal-contract.js +4 -4
  515. package/dist/run/text.d.ts +2 -0
  516. package/dist/run/text.js +4 -0
  517. package/dist/run/transient-comms-secrets.d.ts +5 -0
  518. package/dist/run/transient-comms-secrets.js +12 -0
  519. package/dist/run-lab.d.ts +40 -38
  520. package/dist/run-lab.js +42 -40
  521. package/dist/study/convert.d.ts +33 -0
  522. package/dist/study/convert.js +432 -0
  523. package/dist/study/field-paths.d.ts +12 -0
  524. package/dist/study/field-paths.js +126 -0
  525. package/dist/study/files.d.ts +26 -0
  526. package/dist/study/files.js +43 -0
  527. package/dist/study/migrate.d.ts +48 -0
  528. package/dist/study/migrate.js +408 -0
  529. package/dist/study/owned-files.d.ts +38 -0
  530. package/dist/study/owned-files.js +182 -0
  531. package/dist/subject/clone.d.ts +1 -1
  532. package/dist/subject/desktop-cli.d.ts +2 -2
  533. package/dist/subject/desktop-cli.js +3 -3
  534. package/dist/subject/local-tree-archive.d.ts +1 -1
  535. package/dist/subject/local-tree-archive.js +5 -5
  536. package/dist/subject/local-tree.d.ts +3 -3
  537. package/dist/subject/local-tree.js +1 -1
  538. package/dist/subject/node-bootstrap.d.ts +1 -1
  539. package/dist/subject/node-bootstrap.js +4 -4
  540. package/dist/subject/runtime.js +10 -11
  541. package/dist/subject/serve.d.ts +1 -1
  542. package/dist/subject/serve.js +4 -4
  543. package/dist/subject/state.d.ts +1 -1
  544. package/dist/subject/steps.d.ts +8 -8
  545. package/dist/subject/steps.js +7 -7
  546. package/dist/substrates/command-failure.d.ts +3 -3
  547. package/dist/substrates/command-failure.js +3 -3
  548. package/dist/substrates/detached.d.ts +6 -6
  549. package/dist/substrates/detached.js +7 -7
  550. package/dist/substrates/e2b/cdp-probe.d.ts +11 -11
  551. package/dist/substrates/e2b/cdp-probe.js +15 -18
  552. package/dist/substrates/e2b/desktop-browser.d.ts +5 -5
  553. package/dist/substrates/e2b/desktop-browser.js +12 -12
  554. package/dist/substrates/e2b/desktop-cdp.d.ts +15 -15
  555. package/dist/substrates/e2b/desktop-cdp.js +11 -11
  556. package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
  557. package/dist/substrates/e2b/desktop-executor.js +1 -1
  558. package/dist/substrates/e2b/desktop-geometry.d.ts +6 -6
  559. package/dist/substrates/e2b/desktop-geometry.js +9 -9
  560. package/dist/substrates/e2b/desktop-media.d.ts +1 -1
  561. package/dist/substrates/e2b/desktop-media.js +3 -3
  562. package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
  563. package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
  564. package/dist/substrates/e2b/sandbox.d.ts +1 -1
  565. package/dist/substrates/e2b/sandbox.js +2 -2
  566. package/dist/substrates/e2b/sdk.d.ts +11 -11
  567. package/dist/substrates/e2b/sdk.js +8 -8
  568. package/dist/substrates/local/runtime-host.d.ts +2 -0
  569. package/dist/substrates/local/runtime-host.js +6 -0
  570. package/dist/tui/actions.d.ts +8 -6
  571. package/dist/tui/actions.js +31 -22
  572. package/dist/tui/contract.d.ts +16 -16
  573. package/dist/tui/contract.js +10 -10
  574. package/dist/tui/launch.d.ts +4 -4
  575. package/dist/tui/launch.js +18 -19
  576. package/dist/tui/project.js +5 -5
  577. package/dist/tui-app.js +83 -83
  578. package/dist/verify/actor.d.ts +14 -14
  579. package/dist/verify/actor.js +45 -45
  580. package/dist/verify/artifacts.d.ts +3 -3
  581. package/dist/verify/artifacts.js +6 -6
  582. package/dist/verify/context-growth.d.ts +9 -0
  583. package/dist/verify/context-growth.js +62 -0
  584. package/dist/verify/costs.d.ts +7 -7
  585. package/dist/verify/costs.js +9 -9
  586. package/dist/verify/liveness.d.ts +1 -1
  587. package/dist/verify/liveness.js +4 -1
  588. package/dist/verify/rerun.d.ts +1 -1
  589. package/dist/verify/rerun.js +1 -1
  590. package/dist/verify/shared-world-concurrent.d.ts +2 -2
  591. package/dist/verify/shared-world-concurrent.js +79 -76
  592. package/dist/verify/shared-world.d.ts +2 -2
  593. package/dist/verify/shared-world.js +18 -18
  594. package/dist/verify/subject.d.ts +4 -4
  595. package/dist/verify/subject.js +18 -18
  596. package/dist/verify/verify.js +98 -49
  597. package/docs/README.md +26 -33
  598. package/docs/architecture/actor-contract.md +105 -98
  599. package/docs/architecture/desktop-sessions.md +14 -14
  600. package/docs/architecture/external-public-shared-world.md +66 -59
  601. package/docs/architecture/github-feedback-loop.md +1 -4
  602. package/docs/architecture/guest-desktop.md +2 -2
  603. package/docs/architecture/observer.md +37 -37
  604. package/docs/architecture/restricted-codex-analysis.md +70 -30
  605. package/docs/architecture/serve.md +34 -37
  606. package/docs/architecture/state-driven-executor.md +55 -59
  607. package/docs/architecture/task-protocol-support.md +7 -9
  608. package/docs/architecture/{terminal-product-lane.md → terminal-product-route.md} +83 -115
  609. package/docs/contracts/README.md +24 -0
  610. package/docs/contracts/adapter-admission.md +3 -3
  611. package/docs/contracts/adapter-fixtures.md +2 -5
  612. package/docs/contracts/core.md +1 -3
  613. package/docs/contracts/errors.md +62 -0
  614. package/docs/contracts/feedback.md +8 -9
  615. package/docs/contracts/policy.md +7 -12
  616. package/docs/contracts/run-bundle.md +54 -51
  617. package/docs/contracts/schemas.md +505 -390
  618. package/docs/contracts/study-analysis.md +26 -2
  619. package/docs/contracts/study-costs.md +11 -7
  620. package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
  621. package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
  622. package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
  623. package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +2 -1
  624. package/docs/principles/actor-fidelity.md +4 -4
  625. package/docs/principles/engineering.md +3 -3
  626. package/docs/principles/invariants-and-defaults.md +38 -38
  627. package/docs/principles/self-driving-harness.md +1 -5
  628. package/docs/principles/three-roles.md +1 -1
  629. package/docs/product/automatic-analysis.md +8 -7
  630. package/examples/participant/README.md +5 -5
  631. package/examples/participant/run.mjs +11 -10
  632. package/examples/scorer/README.md +3 -3
  633. package/examples/scorer/run.mjs +11 -12
  634. package/package.json +16 -17
  635. package/skills/humanish/SKILL.md +63 -60
  636. package/skills/humanish/agents/openai.yaml +1 -1
  637. package/AGENTS.md +0 -99
  638. package/CONTRIBUTING.md +0 -148
  639. package/dist/actors/codex/qualified-versions.d.ts +0 -45
  640. package/dist/actors/codex/qualified-versions.js +0 -87
  641. package/dist/cli/commands/lab.d.ts +0 -3
  642. package/dist/cli/commands/lab.js +0 -193
  643. package/dist/deprecated.d.ts +0 -90
  644. package/dist/deprecated.js +0 -106
  645. package/dist/lab/bag-overrides.d.ts +0 -18
  646. package/dist/lab/bag-overrides.js +0 -121
  647. package/dist/observer/static.d.ts +0 -39
  648. package/dist/observer/static.js +0 -369
  649. package/dist/routes/computer-use/legacy-lane-spec.d.ts +0 -62
  650. package/dist/routes/computer-use/legacy-lane-spec.js +0 -39
  651. package/docs/architecture/comms-inbox.md +0 -122
  652. package/docs/architecture/desktop-recording.md +0 -80
  653. package/docs/architecture/local-browser-runtime.md +0 -178
  654. package/docs/architecture/observer-review.md +0 -144
  655. package/docs/architecture/participant-media.md +0 -90
  656. package/docs/architecture/project-layout.md +0 -62
  657. package/docs/architecture/real-email-receiving.md +0 -136
  658. package/docs/assets/humanish-drawdb-hero.png +0 -0
  659. package/docs/assets/humanish-observer-hero.png +0 -0
  660. package/docs/goals/current.md +0 -207
  661. package/docs/product/lobby-trivia-3player-external-public.md +0 -77
  662. package/docs/product/open-source-install-experience.md +0 -240
  663. package/docs/ramp/README.md +0 -294
  664. package/docs/release/open-source-readiness.md +0 -222
  665. package/docs/release/public-readiness-standard.md +0 -210
  666. package/docs/roadmap/world-class-open-source-v0.md +0 -311
  667. /package/dist/routes/computer-use/{fanout-lanes.d.ts → fanout-records.d.ts} +0 -0
  668. /package/dist/routes/shared-world/{seat-records.d.ts → bundle-records.d.ts} +0 -0
@@ -3,19 +3,21 @@ import { openTarget, renderObserver, serveObserver } from "../../observer/render
3
3
  import { SERVE_SCHEMA, serveObserverLibrary } from "../../observer/serve.js";
4
4
  import { startExposedObserver, validateExposure } from "../../observer/exposure.js";
5
5
  import { ServeTunnelError } from "../../observer/tunnel.js";
6
- import { collectRepeated, formatRunHuman, JSON_OPTION_DESCRIPTION, parseObserverPort, wantsJson, writeResult, } from "../io.js";
6
+ import { deprecationMessage, warnAndQueue } from "../deprecations.js";
7
+ import { collectRepeated, CWD_OPTION_DESCRIPTION, formatRunHuman, freePortOption, JSON_OPTION_DESCRIPTION, parseObserverPort, RUN_OPTION_DESCRIPTION, wantsJson, writeResult, } from "../io.js";
7
8
  import { exitCodeForSignal, formatObserverHuman, } from "../observer-follow.js";
8
9
  export function registerObserveCommand(parent, io) {
9
- parent
10
+ addLibraryOptions(parent
10
11
  .command("observe")
11
- .description("Follow a run's saved evidence in Observer over loopback http://127.0.0.1.")
12
- .summary("Follow a run's saved evidence over loopback http.")
13
- .option("--run <id>", "Run id or latest pointer.", "latest")
14
- .option("--port <port>", "Loopback port to bind on 127.0.0.1. Defaults to an ephemeral port.", "0")
15
- .option("--cwd <path>", "Target project directory.", ".")
16
- .option("--open", "Open the observer in the default browser.")
12
+ .description("Open a saved run in the Observer, served on http://127.0.0.1; without --run, the latest. With --all, serve the run library, opening on --run when given.")
13
+ .summary("Open a saved run in the Observer.")
14
+ .option("--run <id>", RUN_OPTION_DESCRIPTION)
15
+ .option("--all", "Serve the whole run library, with optional tunnel-edge exposure.")
16
+ .addOption(freePortOption())
17
+ .option("--cwd <path>", CWD_OPTION_DESCRIPTION, ".")
18
+ .option("--open", "Open the Observer in the default browser.")
17
19
  .option("--no-open", "Serve without opening a browser.")
18
- .option("--json", JSON_OPTION_DESCRIPTION)
20
+ .option("--json", JSON_OPTION_DESCRIPTION))
19
21
  .addHelpText("after", [
20
22
  "",
21
23
  "Examples:",
@@ -23,62 +25,128 @@ export function registerObserveCommand(parent, io) {
23
25
  " humanish observe --run latest",
24
26
  " humanish observe --run <runId> --port 8732",
25
27
  " humanish observe --no-open --json",
28
+ " humanish observe --all",
29
+ " humanish observe --all --expose --tunnel ngrok --oauth google --allow-email you@example.com",
30
+ " humanish observe --all --safe --expose --tunnel ngrok",
31
+ " humanish observe --all --expose --public-url https://observer.example.com",
26
32
  "",
27
- "The server binds 127.0.0.1 only and exposes just the run's bundle directory.",
28
- "It stays attached until Ctrl-C; file:// security policy and live refresh are why",
29
- "loopback http is preferred over opening the index.html path directly.",
33
+ "The server binds 127.0.0.1 only. One run exposes just that run's bundle directory; --all",
34
+ "serves the run library. It stays attached until Ctrl-C; file:// security policy and live",
35
+ "refresh are why loopback http is preferred over opening the index.html path directly.",
36
+ "",
37
+ "--safe, --expose, --tunnel, --tunnel-domain, --oauth, --allow-email, --allow-domain and",
38
+ "--public-url need --all. Exposure only ever happens through an authenticated edge (ngrok",
39
+ "--oauth google, or an operator --public-url you secure) forwarding to the loopback port;",
40
+ "the server carries no in-process auth. Live desktop stream URLs are never served; remote",
41
+ "viewers see persisted evidence only. --safe composes with any exposure.",
30
42
  ].join("\n"))
31
- .action(async (options, command) => {
32
- const port = parseObserverPort(options.port);
33
- if (port === null) {
34
- const result = {
35
- schema: "humanish.run-result.v1",
36
- ok: false,
37
- cwd: options.cwd,
38
- warnings: [],
39
- error: {
40
- code: "HUMANISH_INVALID_PORT",
41
- message: "--port must be an integer between 0 and 65535.",
42
- },
43
- };
44
- writeResult(command, io, result, formatRunHuman);
45
- io.setExitCode(2);
46
- return;
47
- }
48
- const rendered = await renderObserver(options.cwd, options.run, { open: false });
49
- if (!rendered.ok || !rendered.observerPath) {
50
- writeResult(command, io, rendered, formatObserverHuman);
51
- io.setExitCode(2);
52
- return;
53
- }
54
- // Reuse the contained current-data projection, scoped to this run. A raw static
55
- // server would miss runtime status and could replay stored iframe grants.
56
- const wantsMachine = wantsJson(command);
57
- const shouldOpen = options.open === false
58
- ? false
59
- : options.open === true
60
- ? true
61
- : !wantsMachine && process.stdout.isTTY === true;
62
- const server = await serveObserver(rendered, { open: false, port, scope: "run" });
63
- const openResult = shouldOpen
64
- ? openTarget(server.url)
65
- : { opened: false };
43
+ .action((options, command) => handleObserve(io, options, command));
44
+ }
45
+ /** The run library's flags, on `observe --all` and the hidden `serve` alias. */
46
+ function addLibraryOptions(command) {
47
+ return command
48
+ .option("--safe", "Serve only runs whose verify shareSafety is share_ready; other runs are not served at all.")
49
+ .option("--expose", "Share the library beyond this machine. Requires --oauth or --public-url, or --safe.")
50
+ .addOption(new Option("--tunnel <provider>", "Spawn the external tunnel binary against the loopback port.").choices(["ngrok"]))
51
+ .option("--tunnel-domain <domain>", "Reserved domain passed to ngrok as --url (e.g. observer.example.com). Requires --tunnel.")
52
+ .addOption(new Option("--oauth <provider>", "Turn on ngrok edge OAuth. Requires --tunnel.").choices([
53
+ "google",
54
+ ]))
55
+ .option("--allow-email <addr>", "Edge OAuth allow rule: permit this email. Repeatable. Requires --oauth.", collectRepeated)
56
+ .option("--allow-domain <domain>", "Edge OAuth allow rule: permit this domain. Repeatable. Requires --oauth.", collectRepeated)
57
+ .option("--public-url <origin>", "Bring-your-own authed edge (e.g. https://observer.example.com). Requires --expose; never affects binding.");
58
+ }
59
+ /** The library flags set on a one-run observe, as typed on the command line. */
60
+ function libraryOnlyFlags(options) {
61
+ return [
62
+ options.safe === true ? ["--safe"] : [],
63
+ options.expose === true ? ["--expose"] : [],
64
+ options.tunnel === undefined ? [] : ["--tunnel"],
65
+ options.tunnelDomain === undefined ? [] : ["--tunnel-domain"],
66
+ options.oauth === undefined ? [] : ["--oauth"],
67
+ (options.allowEmail?.length ?? 0) === 0 ? [] : ["--allow-email"],
68
+ (options.allowDomain?.length ?? 0) === 0 ? [] : ["--allow-domain"],
69
+ options.publicUrl === undefined ? [] : ["--public-url"],
70
+ ].flat();
71
+ }
72
+ function refuseObserve(command, io, cwd, error) {
73
+ const result = {
74
+ schema: "humanish.run-result.v1",
75
+ ok: false,
76
+ cwd,
77
+ warnings: [],
78
+ ...(error === undefined ? {} : { error }),
79
+ };
80
+ writeResult(command, io, result, formatRunHuman);
81
+ io.setExitCode(2);
82
+ }
83
+ /** `observe` shows one run (default latest); `observe --all` serves the run library. */
84
+ async function handleObserve(io, options, command) {
85
+ if (options.all === true) {
86
+ await handleServe(io, options, command);
87
+ return;
88
+ }
89
+ const libraryOnly = libraryOnlyFlags(options);
90
+ if (libraryOnly.length > 0) {
91
+ refuseObserve(command, io, options.cwd, {
92
+ code: "HUMANISH_OBSERVE_OPTION_CONFLICT",
93
+ message: `${libraryOnly.join(", ")} ${libraryOnly.length === 1 ? "needs" : "need"} --all: humanish observe --all ${libraryOnly.join(" ")}.`,
94
+ });
95
+ return;
96
+ }
97
+ await observeRun(io, { ...options, run: options.run ?? "latest" }, command);
98
+ }
99
+ /** One run's Observer over loopback, until a signal stops it. */
100
+ async function observeRun(io, options, command) {
101
+ const port = parseObserverPort(options.port);
102
+ if (port === null) {
66
103
  const result = {
67
- ...rendered,
68
- observerUrl: server.url,
69
- serverUrl: server.url,
70
- opened: openResult.opened,
71
- ...(openResult.command ? { openCommand: openResult.command } : {}),
72
- warnings: [
73
- ...rendered.warnings,
74
- "Observer is served read-only over loopback http on 127.0.0.1; only this run's bundle directory is exposed.",
75
- ...(openResult.warning ? [openResult.warning] : []),
76
- ],
104
+ schema: "humanish.run-result.v1",
105
+ ok: false,
106
+ cwd: options.cwd,
107
+ warnings: [],
108
+ error: {
109
+ code: "HUMANISH_INVALID_PORT",
110
+ message: "--port must be an integer between 0 and 65535.",
111
+ },
77
112
  };
78
- writeResult(command, io, result, formatObserverHuman);
79
- io.setExitCode(0);
80
- await serveObserveUntilSignal(io, server, { json: wantsMachine });
81
- });
113
+ writeResult(command, io, result, formatRunHuman);
114
+ io.setExitCode(2);
115
+ return;
116
+ }
117
+ const rendered = await renderObserver(options.cwd, options.run, { open: false });
118
+ if (!rendered.ok || !rendered.observerPath) {
119
+ writeResult(command, io, rendered, formatObserverHuman);
120
+ io.setExitCode(2);
121
+ return;
122
+ }
123
+ // Reuse the contained current-data projection, scoped to this run. A raw static
124
+ // server would miss runtime status and could replay stored iframe grants.
125
+ const wantsMachine = wantsJson(command);
126
+ const shouldOpen = options.open === false
127
+ ? false
128
+ : options.open === true
129
+ ? true
130
+ : !wantsMachine && process.stdout.isTTY === true;
131
+ const server = await serveObserver(rendered, { open: false, port, scope: "run" });
132
+ const openResult = shouldOpen
133
+ ? openTarget(server.url)
134
+ : { opened: false };
135
+ const result = {
136
+ ...rendered,
137
+ observerUrl: server.url,
138
+ serverUrl: server.url,
139
+ opened: openResult.opened,
140
+ ...(openResult.command ? { openCommand: openResult.command } : {}),
141
+ warnings: [
142
+ ...rendered.warnings,
143
+ "Observer is served read-only over loopback http on 127.0.0.1; only this run's bundle directory is exposed.",
144
+ ...(openResult.warning ? [openResult.warning] : []),
145
+ ],
146
+ };
147
+ writeResult(command, io, result, formatObserverHuman);
148
+ io.setExitCode(0);
149
+ await serveObserveUntilSignal(io, server, { json: wantsMachine });
82
150
  }
83
151
  async function serveObserveUntilSignal(io, server, options) {
84
152
  // Keep the JSON envelope on stdout clean: route attach/stop chatter to stderr
@@ -117,45 +185,19 @@ async function serveObserveUntilSignal(io, server, options) {
117
185
  }
118
186
  });
119
187
  }
188
+ // Removed in 0.109.0: `serve` stays one minor as a hidden alias of `observe --all`.
120
189
  export function registerServeCommand(parent, io) {
121
- parent
122
- .command("serve")
123
- .description("Serve the local run library over loopback http, with optional tunnel-edge authenticated exposure.")
124
- .summary("Serve the run library; optional tunnel-edge exposure.")
125
- .option("--cwd <path>", "Target project directory.", ".")
126
- .option("--port <port>", "Loopback port to bind on 127.0.0.1. Defaults to an ephemeral port.", "0")
127
- .option("--run <id>", "Land on this run id (or latest) instead of the library index.")
128
- .option("--safe", "Serve only runs whose verify shareSafety is share_ready; everything else is absent (fail-closed).")
129
- .option("--expose", "Declare exposure intent. Requires edge auth (--oauth or --public-url) OR --safe.")
130
- .addOption(new Option("--tunnel <provider>", "Spawn the external tunnel binary against the loopback port.").choices(["ngrok"]))
131
- .option("--tunnel-domain <domain>", "Reserved domain passed to ngrok as --url (e.g. observer.example.com). Requires --tunnel.")
132
- .addOption(new Option("--oauth <provider>", "Turn on ngrok edge OAuth. Requires --tunnel.").choices([
133
- "google",
134
- ]))
135
- .option("--allow-email <addr>", "Edge OAuth allow rule: permit this email. Repeatable. Requires --oauth.", collectRepeated, [])
136
- .option("--allow-domain <domain>", "Edge OAuth allow rule: permit this domain. Repeatable. Requires --oauth.", collectRepeated, [])
137
- .option("--public-url <origin>", "Bring-your-own authed edge (e.g. https://observer.example.com). Requires --expose; never affects binding.")
190
+ addLibraryOptions(parent
191
+ .command("serve", { hidden: true })
192
+ .option("--cwd <path>", CWD_OPTION_DESCRIPTION, ".")
193
+ .addOption(freePortOption())
194
+ .option("--run <id>", RUN_OPTION_DESCRIPTION)
138
195
  .option("--open", "Open the library in the default browser.")
139
196
  .option("--no-open", "Serve without opening a browser.")
140
- .option("--json", JSON_OPTION_DESCRIPTION)
141
- .addHelpText("after", [
142
- "",
143
- "Happy path:",
144
- " humanish serve",
145
- " humanish serve --expose --tunnel ngrok --oauth google --allow-email you@example.com",
146
- " humanish serve --safe --expose --tunnel ngrok",
147
- " humanish serve --expose --public-url https://observer.example.com",
148
- "",
149
- "Agent/CI path:",
150
- " humanish serve --json --no-open",
151
- "",
152
- "The server always binds 127.0.0.1; exposure only ever happens through an authenticated",
153
- "edge (ngrok --oauth google, or an operator --public-url you secure) forwarding to the",
154
- "loopback port. The server carries no in-process auth; the gate lives at the edge. Live",
155
- "desktop stream URLs are never served here; remote viewers see persisted evidence only.",
156
- "--safe composes with any exposure for defense in depth.",
157
- ].join("\n"))
158
- .action((options, command) => handleServe(io, options, command));
197
+ .option("--json", JSON_OPTION_DESCRIPTION)).action((options, command) => {
198
+ warnAndQueue(command, io, deprecationMessage("humanish serve", "humanish observe --all"));
199
+ return handleServe(io, options, command);
200
+ });
159
201
  }
160
202
  async function handleServe(io, options, command) {
161
203
  const fail = (code, message) => refuseServe(command, io, options, code, message);
@@ -171,8 +213,8 @@ async function handleServe(io, options, command) {
171
213
  ...(options.tunnel === undefined ? {} : { tunnel: options.tunnel }),
172
214
  ...(options.tunnelDomain === undefined ? {} : { tunnelDomain: options.tunnelDomain }),
173
215
  ...(options.oauth === undefined ? {} : { oauth: options.oauth }),
174
- allowEmails: options.allowEmail,
175
- allowDomains: options.allowDomain,
216
+ allowEmails: options.allowEmail ?? [],
217
+ allowDomains: options.allowDomain ?? [],
176
218
  ...(options.publicUrl === undefined ? {} : { publicUrl: options.publicUrl }),
177
219
  safe: options.safe === true,
178
220
  });
@@ -257,7 +299,7 @@ async function reportServe(io, command, options, server, plan, edge) {
257
299
  ...serveExposureWarnings(server, options.safe === true, publicUrl),
258
300
  ];
259
301
  // Auto-open is suppressed under --expose so the public URL is not shoved into a local opener's
260
- // argv unasked — the exposure target is a remote device anyway. Explicit --open still honors
302
+ // argv unasked; the exposure target is a remote device anyway. Explicit --open still honors
261
303
  // intent and opens the loopback library.
262
304
  const shouldOpen = options.open === false
263
305
  ? false
@@ -292,6 +334,7 @@ async function reportServe(io, command, options, server, plan, edge) {
292
334
  : {}),
293
335
  runsListed: server.runsListed,
294
336
  ...(server.shareReadyCount !== undefined ? { shareReadyCount: server.shareReadyCount } : {}),
337
+ ...(server.hiddenRuns !== undefined ? { hiddenRuns: server.hiddenRuns } : {}),
295
338
  ...(server.entryRunId ? { entryRunId: server.entryRunId } : {}),
296
339
  opened: openResult.opened,
297
340
  ...(openResult.command ? { openCommand: openResult.command } : {}),
@@ -309,20 +352,38 @@ async function reportServe(io, command, options, server, plan, edge) {
309
352
  },
310
353
  }, { json: wantsMachine });
311
354
  }
355
+ /**
356
+ * The runs --safe left out, grouped by grade and reasons, and how to share one. A run held back
357
+ * only for raw screenshots can be exported as a copy with blurred screenshots; the read-results
358
+ * docs name that step.
359
+ */
360
+ function hiddenRunLines(groups) {
361
+ const total = groups.reduce((sum, group) => sum + group.runs, 0);
362
+ if (total === 0)
363
+ return [];
364
+ const runs = (count) => `${count} run${count === 1 ? "" : "s"}`;
365
+ const lines = [`hidden: ${runs(total)} not share_ready`];
366
+ for (const group of groups) {
367
+ const reasons = group.reasons.length > 0 ? ` (${group.reasons.join(", ")})` : "";
368
+ lines.push(` ${runs(group.runs)} ${group.status}${reasons}`);
369
+ }
370
+ if (groups.some((group) => group.reasons.join(",") === "RAW_SCREENSHOTS"))
371
+ lines.push("share: a run held back only for RAW_SCREENSHOTS can be copied with blurred screenshots: `humanish export --run <id> --format bundle --redact-screenshots --out <dir>`, then `humanish observe --all --safe --cwd <dir>`");
372
+ lines.push("why: `humanish verify --run <id>` explains each reason");
373
+ return lines;
374
+ }
312
375
  function formatServeHuman(result) {
313
376
  if (!result.ok) {
314
- return ([
315
- "humanish serve failed",
316
- ...(result.error ? [`error: ${result.error.code} ${result.error.message}`] : []),
317
- ...result.warnings.map((warning) => `warning: ${warning}`),
318
- ].join("\n") + "\n");
377
+ const warnings = result.warnings.map((warning) => `warning: ${warning}\n`).join("");
378
+ return { ...(warnings ? { stdout: warnings } : {}), error: result.error };
319
379
  }
320
380
  const modeSuffix = result.safe ? " (share_ready only)" : "";
321
381
  const lines = [
322
- "humanish serve",
382
+ "humanish observe --all",
323
383
  `mode: ${result.mode}${modeSuffix}`,
324
384
  `library: ${result.url ?? ""}`,
325
385
  `runs: ${result.runsListed}`,
386
+ ...hiddenRunLines(result.hiddenRuns ?? []),
326
387
  ];
327
388
  if (result.publicUrl) {
328
389
  lines.push(`public: ${result.publicUrl}`);
@@ -332,7 +393,7 @@ function formatServeHuman(result) {
332
393
  }
333
394
  if (result.oauth) {
334
395
  const rules = [...result.oauth.allowEmails, ...result.oauth.allowDomains];
335
- lines.push(`edge auth: ${result.oauth.provider} oauth${rules.length > 0 ? ` (allow: ${rules.join(", ")})` : " (no allow rule — any Google account)"}`);
396
+ lines.push(`edge auth: ${result.oauth.provider} oauth${rules.length > 0 ? ` (allow: ${rules.join(", ")})` : " (no allow rule: any Google account can sign in)"}`);
336
397
  }
337
398
  if (result.entryRunId) {
338
399
  lines.push(`entry: ${result.entryRunId}`);
@@ -0,0 +1,10 @@
1
+ import type { Command } from "commander";
2
+ import { type CliIo, type LabCommandOptions as RunOptions } from "../io.js";
3
+ /** The parsed flags of `run`, `watch` and the `lab run` alias. */
4
+ export type { RunOptions };
5
+ /** The flags a run takes, whichever command starts it. */
6
+ export declare function addRunOptions(command: Command): Command;
7
+ /** The flags that only a study file can use, as typed on the command line, when they are set. */
8
+ export declare function studyOnlyFlags(options: RunOptions): string[];
9
+ /** `humanish run [study]`: the named study, or the synthetic preview when no study is given. */
10
+ export declare function handleRun(io: CliIo, named: string | undefined, options: RunOptions, command: Command): Promise<void>;
@@ -0,0 +1,85 @@
1
+ import { runDryRun } from "../../run/dry-run.js";
2
+ import { runLabCommand } from "./lab-run.js";
3
+ import { applyEnvFileOption, CWD_OPTION_DESCRIPTION, ENV_FILE_OPTION_DESCRIPTION, formatRunHuman, freePortOption, JSON_OPTION_DESCRIPTION, parsePositiveInteger, writeResult, } from "../io.js";
4
+ /** The flags a run takes, whichever command starts it. */
5
+ export function addRunOptions(command) {
6
+ return command
7
+ .option("--dry-run", "Do a dry run: a synthetic run with no browser, keys or provider spend.")
8
+ .option("--open", "Open the Observer in the default browser.")
9
+ .option("--no-open", "Render without opening a browser.")
10
+ .option("--detach", "Render/open once and exit without an attached watch server.")
11
+ .addOption(freePortOption())
12
+ .option("--count <count>", "Override the participant count of a preview or computer-use study, or of the synthetic run without a study.")
13
+ .option("--rerun-failed-from <run>", "Computer-use studies only: start a new run for the failed participants of a prior run.")
14
+ .option("--participants <ids>", "With --rerun-failed-from: comma-separated ids of the participants to rerun. The study's participants decide who takes part; ids are their id, or lane-01, lane-02, … by position.")
15
+ .option("--scorer <path>", "Score with this .mjs module, a path inside the repo, in place of review.scorer.ref. It runs as code, so review it first. Terminal, computer-use and shared-world studies only.")
16
+ .option("--cwd <path>", CWD_OPTION_DESCRIPTION, ".")
17
+ .option("--env-file <path>", ENV_FILE_OPTION_DESCRIPTION)
18
+ .option("--run-id <id>", "Explicit run id for deterministic fixture tests; refused when that run already exists.")
19
+ .option("--json", JSON_OPTION_DESCRIPTION);
20
+ }
21
+ /** The flags that only a study file can use, as typed on the command line, when they are set. */
22
+ export function studyOnlyFlags(options) {
23
+ return [
24
+ options.scorer === undefined ? [] : ["--scorer"],
25
+ options.rerunFailedFrom === undefined ? [] : ["--rerun-failed-from"],
26
+ options.participants === undefined ? [] : ["--participants"],
27
+ ].flat();
28
+ }
29
+ function refuseRun(command, io, cwd, error) {
30
+ const result = {
31
+ schema: "humanish.run-result.v1",
32
+ ok: false,
33
+ cwd,
34
+ warnings: [],
35
+ ...(error === undefined ? {} : { error }),
36
+ };
37
+ writeResult(command, io, result, formatRunHuman);
38
+ io.setExitCode(2);
39
+ }
40
+ /** `humanish run [study]`: the named study, or the synthetic preview when no study is given. */
41
+ export async function handleRun(io, named, options, command) {
42
+ // An empty argument, as from a script passing an unset variable, is the synthetic run.
43
+ const study = named === "" ? undefined : named;
44
+ const studyOnly = studyOnlyFlags(options);
45
+ if (study === undefined && studyOnly.length > 0) {
46
+ refuseRun(command, io, options.cwd, {
47
+ code: "HUMANISH_RUN_OPTION_CONFLICT",
48
+ message: `${studyOnly.join(", ")} ${studyOnly.length === 1 ? "needs" : "need"} a study: humanish run <study>.`,
49
+ });
50
+ return;
51
+ }
52
+ const loaded = await applyEnvFileOption({
53
+ command,
54
+ cwd: options.cwd,
55
+ envFile: options.envFile,
56
+ io,
57
+ // runLabCommand discovers keys for a live lab; the lab-less preview needs none.
58
+ discoverKeys: false,
59
+ });
60
+ if (!loaded)
61
+ return;
62
+ if (study !== undefined) {
63
+ await runLabCommand({ command, io, lab: study, mode: "run", options });
64
+ return;
65
+ }
66
+ const participantCount = options.count === undefined ? undefined : parsePositiveInteger(options.count);
67
+ if (participantCount === null) {
68
+ refuseRun(command, io, options.cwd, {
69
+ code: "HUMANISH_INVALID_PARTICIPANT_COUNT",
70
+ message: "--count must be a positive integer.",
71
+ });
72
+ return;
73
+ }
74
+ const result = await runDryRun({
75
+ cwd: options.cwd,
76
+ ...(options.dryRun === undefined ? {} : { dryRun: options.dryRun }),
77
+ ...(options.runId === undefined ? {} : { runId: options.runId }),
78
+ ...(participantCount === undefined ? {} : { participantCount }),
79
+ // Rendered the way `watch` renders it, so a bundle is the same bundle whichever command
80
+ // produced it. A render failure is a warning on the result.
81
+ observer: { open: false },
82
+ });
83
+ writeResult(command, io, result, formatRunHuman);
84
+ io.setExitCode(result.ok ? 0 : 2);
85
+ }
@@ -0,0 +1,30 @@
1
+ import { type ReclaimHooks } from "../../run/reclaim.js";
2
+ import type { RunInterruptSignal } from "../../run/status.js";
3
+ import type { CliIo } from "../io.js";
4
+ interface RunSignalTarget {
5
+ on(event: RunInterruptSignal, listener: () => void): unknown;
6
+ removeListener(event: RunInterruptSignal, listener: () => void): unknown;
7
+ }
8
+ /** Seams for tests; the CLI passes none. */
9
+ export interface RunSignalOptions {
10
+ signalTarget?: RunSignalTarget;
11
+ exit?: (code: number) => void;
12
+ reclaim?: ReclaimHooks;
13
+ deadlineMs?: number;
14
+ }
15
+ /**
16
+ * Register work a committed shutdown finishes before it exits, such as closing watch's Observer
17
+ * server and tunnel. It runs within the same deadline as reclaim. The returned function removes it.
18
+ */
19
+ export declare function onRunShutdown(cleanup: () => Promise<void>): () => void;
20
+ /**
21
+ * Install the run's signal handling. `end` removes it. `release` removes it unless a shutdown has
22
+ * begun, which keeps its handlers so a second signal still exits at once.
23
+ */
24
+ export declare function beginRunSignalPhase(io: Pick<CliIo, "writeErr">, options?: RunSignalOptions): {
25
+ end(): void;
26
+ release(): void;
27
+ };
28
+ /** Analysis is starting, and its own cancel handlers take the signals from here. */
29
+ export declare function handOverRunSignals(): void;
30
+ export {};
@@ -0,0 +1,146 @@
1
+ // The run command's signal handling outside post-run analysis. The first interrupt, terminate or
2
+ // hangup signal marks each unfinished run in this process interrupted, kills the E2B sandboxes
3
+ // its create-time receipts name, runs the registered shutdown cleanups (watch's Observer server
4
+ // and tunnel) and exits 128+n, all within one deadline; a second signal exits at once. Routes
5
+ // take no abort signal, so the bundle is not finished, but the record ends at once and no
6
+ // journaled sandbox waits for its timeout. Analysis has its own cancel handlers
7
+ // (analysis-signals.ts) and takes over when it starts.
8
+ import path from "node:path";
9
+ import { activeRuns } from "../../run/active-runs.js";
10
+ import { LATEST_RUN_ALIAS } from "../../run/locate.js";
11
+ import { reclaimPinnedRunSandboxes, } from "../../run/reclaim.js";
12
+ import { SANDBOX_RECEIPTS_ARTIFACT } from "../../run/sandbox-receipts.js";
13
+ import { exitCodeForSignal } from "../observer-follow.js";
14
+ /** How long the handler waits for interrupt, reclaim and cleanups before it exits anyway. */
15
+ const INTERRUPT_RECLAIM_DEADLINE_MS = 10_000;
16
+ /** Each kill's own request timeout, inside the deadline. */
17
+ const KILL_REQUEST_TIMEOUT_MS = 8_000;
18
+ const SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
19
+ let current;
20
+ const shutdownCleanups = new Set();
21
+ /**
22
+ * Register work a committed shutdown finishes before it exits, such as closing watch's Observer
23
+ * server and tunnel. It runs within the same deadline as reclaim. The returned function removes it.
24
+ */
25
+ export function onRunShutdown(cleanup) {
26
+ shutdownCleanups.add(cleanup);
27
+ return () => {
28
+ shutdownCleanups.delete(cleanup);
29
+ };
30
+ }
31
+ /**
32
+ * Install the run's signal handling. `end` removes it. `release` removes it unless a shutdown has
33
+ * begun, which keeps its handlers so a second signal still exits at once.
34
+ */
35
+ export function beginRunSignalPhase(io, options = {}) {
36
+ const target = options.signalTarget ?? process;
37
+ const exit = options.exit ??
38
+ ((code) => {
39
+ process.exit(code);
40
+ });
41
+ const handlers = new Map();
42
+ let stopping = false;
43
+ const end = () => {
44
+ for (const [signal, handler] of handlers)
45
+ target.removeListener(signal, handler);
46
+ handlers.clear();
47
+ if (current?.end === end)
48
+ current = undefined;
49
+ };
50
+ const release = () => {
51
+ if (!stopping)
52
+ end();
53
+ };
54
+ const onSignal = (signal) => {
55
+ if (stopping) {
56
+ exit(exitCodeForSignal(signal));
57
+ return;
58
+ }
59
+ stopping = true;
60
+ void stopActiveRuns(io, signal, options)
61
+ .catch(() => undefined)
62
+ .finally(() => exit(exitCodeForSignal(signal)));
63
+ };
64
+ current?.end();
65
+ for (const signal of SIGNALS) {
66
+ const handler = () => onSignal(signal);
67
+ handlers.set(signal, handler);
68
+ target.on(signal, handler);
69
+ }
70
+ current = { end, release };
71
+ return { end, release };
72
+ }
73
+ /** Analysis is starting, and its own cancel handlers take the signals from here. */
74
+ export function handOverRunSignals() {
75
+ current?.release();
76
+ }
77
+ /**
78
+ * Interrupt, reclaim and the registered cleanups all run inside one deadline that starts before
79
+ * the first status write is awaited, so a stalled write or kill still ends in a bounded exit.
80
+ */
81
+ async function stopActiveRuns(io, signal, options) {
82
+ const deadlineMs = options.deadlineMs ?? INTERRUPT_RECLAIM_DEADLINE_MS;
83
+ const runs = activeRuns();
84
+ // Absent: still pending at the deadline. Null: the run had finished, so there is nothing to say.
85
+ const reports = new Map();
86
+ const work = Promise.all([
87
+ ...runs.map(async (run) => {
88
+ // False when the run had already finished: its route released what it held.
89
+ if (!(await run.status.interrupt(signal))) {
90
+ reports.set(run, null);
91
+ return;
92
+ }
93
+ const reclaimed = await reclaimPinnedRunSandboxes(run.cwd, run.paths, {
94
+ requestTimeoutMs: KILL_REQUEST_TIMEOUT_MS,
95
+ ...options.reclaim,
96
+ }).catch(() => undefined);
97
+ reports.set(run, reclaimSummary(run, reclaimed));
98
+ }),
99
+ ...[...shutdownCleanups].map((cleanup) => cleanup().catch(() => undefined)),
100
+ ]);
101
+ const finished = await withDeadline(work, deadlineMs);
102
+ for (const run of runs) {
103
+ const report = reports.get(run);
104
+ if (report === null)
105
+ continue;
106
+ const text = report ??
107
+ (finished === "deadline"
108
+ ? `stopping did not finish within ${deadlineMs / 1000} s; ${recovery(run)}.`
109
+ : `reclaim failed; ${recovery(run)}.`);
110
+ try {
111
+ io.writeErr(`humanish: ${signal}: run ${run.runId} marked interrupted; ${text}\n`);
112
+ }
113
+ catch {
114
+ // A hung-up terminal cannot take the line; the status record and reclaim receipt hold it.
115
+ }
116
+ }
117
+ }
118
+ function withDeadline(work, ms) {
119
+ let timer;
120
+ const deadline = new Promise((resolve) => {
121
+ timer = setTimeout(() => resolve("deadline"), ms);
122
+ });
123
+ return Promise.race([work, deadline]).finally(() => clearTimeout(timer));
124
+ }
125
+ /**
126
+ * How to finish what the handler could not. A run whose id is the alias `latest` cannot be named
127
+ * to reclaim, which would resolve the newest run instead, so it gets its receipts path.
128
+ */
129
+ function recovery(run) {
130
+ return run.runId === LATEST_RUN_ALIAS
131
+ ? `its id is \`${LATEST_RUN_ALIAS}\`, which \`humanish reclaim --run\` reads as the newest run, so kill the ids in ${path.join(run.paths.relativeRunRoot, SANDBOX_RECEIPTS_ARTIFACT)} by hand`
132
+ : `run \`humanish reclaim --run ${run.runId}\``;
133
+ }
134
+ function reclaimSummary(run, reclaimed) {
135
+ if (reclaimed === undefined)
136
+ return `reclaim failed; ${recovery(run)}.`;
137
+ if (reclaimed.error !== undefined)
138
+ return reclaimed.error.message;
139
+ if (reclaimed.outcomes.length === 0)
140
+ return "no sandbox receipts to reclaim.";
141
+ const counts = new Map();
142
+ for (const outcome of reclaimed.outcomes)
143
+ counts.set(outcome.state, (counts.get(outcome.state) ?? 0) + 1);
144
+ const tally = [...counts].map(([state, count]) => `${count} ${state}`).join(", ");
145
+ return reclaimed.ok ? `sandboxes: ${tally}.` : `sandboxes: ${tally}; ${recovery(run)} to retry.`;
146
+ }