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
@@ -8,12 +8,12 @@ export interface LabRollup {
8
8
  live: number;
9
9
  /** The newest run of this lab, whatever its state. */
10
10
  latest?: RunIndexEntry;
11
- /** Live runs, newest first — the labs list shows the first one inline. */
11
+ /** Live runs, newest first; the labs list shows the first one inline. */
12
12
  liveRuns: RunIndexEntry[];
13
13
  }
14
14
  /**
15
15
  * Group runs by lab, newest-first within each lab and by recency between labs. Runs with no lab
16
- * attribution are collected under `unattributed` rather than invented into a lab — the honest
16
+ * attribution are collected under `unattributed` rather than invented into a study. That is the
17
17
  * home for pre-contract runs and library callers.
18
18
  */
19
19
  export declare function groupRunsByLab(entries: readonly RunIndexEntry[]): {
@@ -35,17 +35,17 @@ export interface LabExpectation {
35
35
  max: number;
36
36
  };
37
37
  medianCostUsd?: number;
38
- /** Completed runs whose cost was declared absent — excluded from the median, reported here so
38
+ /** Completed runs whose cost was declared absent: excluded from the median, reported here so
39
39
  * a partial sample can never masquerade as a full one. */
40
40
  costUnknown: number;
41
41
  }
42
42
  /**
43
- * Derive what to expect from a lab's own history. Only FINISHED runs count: an interrupted run's
43
+ * Derive what to expect from a lab's own history. Only finished runs count: an interrupted run's
44
44
  * duration is the length of an accident, not of a study, and including it would quietly bias the
45
45
  * estimate the operator uses to decide whether to press Start.
46
46
  *
47
- * MODE MATTERS, and mixing modes is a lie rather than an imprecision. A dry run spends nothing and
48
- * takes no time, so a median over nine dry runs and one live one reports that a live run is free —
47
+ * The mode matters: mixing modes produces a false figure. A dry run spends nothing and
48
+ * takes no time, so a median over nine dry runs and one live one reports that a live run is free,
49
49
  * next to a control that spends money. Pass the mode the figure is about; omit it only for a
50
50
  * summary that is not attached to an action.
51
51
  */
@@ -53,15 +53,15 @@ export declare function expectationFor(entries: readonly RunIndexEntry[], mode?:
53
53
  /**
54
54
  * The one sentence the launch screen shows about time and money, with its denominator attached.
55
55
  * A lab with no history says so plainly instead of borrowing another lab's numbers or inventing
56
- * a range — "no runs yet" is information, and the operator can still press Start.
56
+ * a range. "No runs yet" is information, and the operator can still press Start.
57
57
  */
58
58
  export declare function expectationLine(expectation: LabExpectation): string;
59
59
  /**
60
60
  * The one line a lab may say about itself, wherever it is shown.
61
61
  *
62
- * Prefers LIVE figures: cost and duration are what someone reads before spending, and a median
62
+ * Prefers live figures: cost and duration are what someone reads before spending, and a median
63
63
  * diluted by dry runs reports a live study as cheaper and faster than it has ever been. With no
64
- * live history it reports the count and claims nothing about time or money — which is why this is
64
+ * live history it reports the count and claims nothing about time or money. That is why this is
65
65
  * shared rather than reimplemented per surface, since the two disagreeing is the whole failure.
66
66
  */
67
67
  export declare function labSummaryLine(row: Pick<LabRow, "runs" | "declared" | "expectation" | "liveExpectation">): string;
@@ -69,7 +69,7 @@ export declare function labSummaryLine(row: Pick<LabRow, "runs" | "declared" | "
69
69
  export declare function formatDuration(ms: number): string;
70
70
  export interface NormalizedThought {
71
71
  lines: string[];
72
- /** True when the source text did not fit and was cut — shown, never silent. */
72
+ /** True when the source text did not fit and was cut; shown, never silent. */
73
73
  truncated: boolean;
74
74
  }
75
75
  /**
@@ -77,7 +77,7 @@ export interface NormalizedThought {
77
77
  * arrive with markdown section leads (`**Thinking through setup**`) and hard newlines; a terminal
78
78
  * needs plain text wrapped to a line budget.
79
79
  *
80
- * The text is never paraphrased or shortened by meaning — only wrapped, and cut at a word boundary
80
+ * The text is never paraphrased or shortened by meaning. It is only wrapped, and cut at a word boundary
81
81
  * with an ellipsis when it does not fit. `truncated` is how the surface says so.
82
82
  */
83
83
  export declare function normalizeThought(text: string, options: {
@@ -104,15 +104,15 @@ export declare function livenessLabel(entry: Pick<RunIndexEntry, "liveness" | "v
104
104
  /** A lab as the labs list shows it: what is declared, joined to what actually happened. */
105
105
  export interface LabRow {
106
106
  /**
107
- * Stable identity for THIS ROW. A manifest's path when it has one, else the lab id — because two
107
+ * Stable identity for this row. A manifest's path when it has one, else the lab id, because two
108
108
  * manifests can declare the same id, and keying rows by id makes them collapse into a pair of
109
109
  * indistinguishable duplicates.
110
110
  */
111
111
  key: string;
112
- /** The declared id. Run history attributes to this, so it is NOT unique across manifests. */
112
+ /** The declared id. Run history attributes to this, so it is not unique across manifests. */
113
113
  labId: string;
114
114
  /**
115
- * The handle an operator would actually type. Lab resolution is by FILENAME, so the manifest
115
+ * The handle an operator would actually type. Lab resolution is by filename, so the manifest
116
116
  * `\`.humanish/labs/persona-contrast-live.yaml\`` is reached as `persona-contrast-live` even when
117
117
  * the id inside it says something else.
118
118
  */
@@ -120,26 +120,26 @@ export interface LabRow {
120
120
  /** The manifest's own title, when it has one. */
121
121
  title?: string;
122
122
  /**
123
- * The shortest label that is UNIQUE among the rows it is listed with: the title when no other
123
+ * The shortest label that is unique among the rows it is listed with: the title when no other
124
124
  * lab shares it, else the filename, else the full path. A list is only navigable if every row can
125
- * be told from every other one, and a title is not guaranteed to be distinct — two manifests in
126
- * this repo carry the same title AND the same declared id, differing only by filename.
125
+ * be told from every other one, and a title is not guaranteed to be distinct: two manifests in
126
+ * this repo carry the same title and the same declared id, differing only by filename.
127
127
  */
128
128
  label: string;
129
- /** The manifest's own words, for the list to say what this study IS. */
129
+ /** The manifest's own words, for the list to say what this study is. */
130
130
  description?: string;
131
131
  /** Repo-relative manifest path, absent for a lab known only from run history. */
132
132
  path?: string;
133
133
  origin?: "committed" | "ignored" | "explicit";
134
134
  /**
135
- * False for a lab that has runs but NO manifest here — renamed, deleted, or run from a path that
135
+ * False for a lab that has runs but no manifest here: renamed, deleted, or run from a path that
136
136
  * is gone. Its runs are still evidence and must stay reachable, so it is listed and marked rather
137
137
  * than dropped.
138
138
  */
139
139
  declared: boolean;
140
140
  /**
141
- * How many OTHER manifests declare this same lab id. Above zero, the run history below is shared
142
- * between them and cannot be attributed to one file — worth saying, because it is a
141
+ * How many other manifests declare this same lab id. Above zero, the run history below is shared
142
+ * between them and cannot be attributed to one file. That is worth saying, because it is a
143
143
  * misconfiguration the operator almost certainly does not know about.
144
144
  */
145
145
  sharesIdWith: number;
@@ -149,7 +149,7 @@ export interface LabRow {
149
149
  liveRuns: RunIndexEntry[];
150
150
  /** Across every finished run, whatever its mode. A summary, never attached to a spend decision. */
151
151
  expectation: LabExpectation;
152
- /** Live runs only — the figure that belongs beside anything that spends money. */
152
+ /** Live runs only: the figure that belongs beside anything that spends money. */
153
153
  liveExpectation: LabExpectation;
154
154
  }
155
155
  export interface DeclaredLab {
@@ -163,19 +163,19 @@ export interface DeclaredLab {
163
163
  /**
164
164
  * Join declared lab manifests to run history.
165
165
  *
166
- * Neither side alone is the truth. A fresh project has manifests and no runs — those labs are the
166
+ * Neither side alone is the truth. A fresh project has manifests and no runs, and those labs are the
167
167
  * whole screen, and a list built only from history would be empty on exactly the first visit that
168
168
  * matters. A long-lived project accumulates runs from labs whose manifest has since been renamed or
169
- * deleted — that evidence still exists on disk, so dropping those rows would make real runs
169
+ * deleted. That evidence still exists on disk, so dropping those rows would make real runs
170
170
  * unreachable from the surface that is supposed to list them.
171
171
  *
172
- * ONE ROW PER MANIFEST, not per id. The two are not the same thing: a manifest is addressed by its
172
+ * One row per manifest, not per id. The two are not the same thing: a manifest is addressed by its
173
173
  * filename while its runs attribute to the id declared inside it, so several files can legitimately
174
174
  * share an id. Collapsing them hides a real file; keying by id duplicates a row with no way to tell
175
- * the copies apart. Both happen in practice — this repo has exactly that pair.
175
+ * the copies apart. Both happen in practice: this repo has exactly that pair.
176
176
  *
177
177
  * Order puts a lab someone is working in first, then labs by how recently they ran, then declared
178
- * labs that have never run (alphabetically BY WHAT IS DISPLAYED, so the order on screen is the
178
+ * labs that have never run (alphabetically by the displayed label, so the order on screen is the
179
179
  * order a reader can predict), then labs known only from history.
180
180
  */
181
181
  export declare function labRows(declared: readonly DeclaredLab[], entries: readonly RunIndexEntry[]): {
@@ -1,22 +1,22 @@
1
- // The disk→view-model projection (#455 PR 2). Pure functions, no I/O, no rendering: this is where
1
+ // The disk→view-model projection. Pure functions, no I/O, no rendering: this is where
2
2
  // lab grouping, the trust line's arithmetic, thought normalization and list-window math live, so
3
3
  // the parts most likely to be wrong are testable without a terminal.
4
4
  //
5
- // The honesty rules these encode, because they are the ones a UI is most tempted to break:
6
- // - a statistic ALWAYS carries its denominator, and says when it has none;
5
+ // The rules these encode, because they are the ones a UI is most tempted to break:
6
+ // - a statistic always carries its denominator, and says when it has none;
7
7
  // - an unknown cost is `null` (declared absent), never 0;
8
8
  // - truncation is reported, never silent;
9
9
  // - a participant's reported thinking is quoted, never paraphrased or summarized.
10
10
  /**
11
11
  * Group runs by lab, newest-first within each lab and by recency between labs. Runs with no lab
12
- * attribution are collected under `unattributed` rather than invented into a lab — the honest
12
+ * attribution are collected under `unattributed` rather than invented into a study. That is the
13
13
  * home for pre-contract runs and library callers.
14
14
  */
15
15
  export function groupRunsByLab(entries) {
16
16
  const byLab = new Map();
17
17
  const unattributed = [];
18
18
  for (const entry of entries) {
19
- const labId = entry.lab?.id;
19
+ const labId = entry.study?.id;
20
20
  if (labId === undefined) {
21
21
  unattributed.push(entry);
22
22
  continue;
@@ -58,12 +58,12 @@ function recencyOf(entry) {
58
58
  return 0;
59
59
  }
60
60
  /**
61
- * Derive what to expect from a lab's own history. Only FINISHED runs count: an interrupted run's
61
+ * Derive what to expect from a lab's own history. Only finished runs count: an interrupted run's
62
62
  * duration is the length of an accident, not of a study, and including it would quietly bias the
63
63
  * estimate the operator uses to decide whether to press Start.
64
64
  *
65
- * MODE MATTERS, and mixing modes is a lie rather than an imprecision. A dry run spends nothing and
66
- * takes no time, so a median over nine dry runs and one live one reports that a live run is free —
65
+ * The mode matters: mixing modes produces a false figure. A dry run spends nothing and
66
+ * takes no time, so a median over nine dry runs and one live one reports that a live run is free,
67
67
  * next to a control that spends money. Pass the mode the figure is about; omit it only for a
68
68
  * summary that is not attached to an action.
69
69
  */
@@ -78,8 +78,8 @@ export function expectationFor(entries, mode) {
78
78
  .map((entry) => entry.estimatedCostUsd)
79
79
  .filter((value) => typeof value === "number" && Number.isFinite(value))
80
80
  .sort((a, b) => a - b);
81
- // A cost is unknown whether it was DECLARED absent (`null`) or never recorded at all
82
- // (`undefined` — every fail-closed exit finalized with no outcome). Counting only the first
81
+ // A cost is unknown whether it was declared absent (`null`) or never recorded at all
82
+ // (`undefined`: every fail-closed exit finalized with no outcome). Counting only the first
83
83
  // reports "~$1.20 median · 3 runs" for a sample where two runs were never priced, which claims a
84
84
  // denominator the figure does not have.
85
85
  const costUnknown = finished.filter((entry) => entry.estimatedCostUsd === null || entry.estimatedCostUsd === undefined).length;
@@ -104,7 +104,7 @@ function median(sorted) {
104
104
  /**
105
105
  * The one sentence the launch screen shows about time and money, with its denominator attached.
106
106
  * A lab with no history says so plainly instead of borrowing another lab's numbers or inventing
107
- * a range — "no runs yet" is information, and the operator can still press Start.
107
+ * a range. "No runs yet" is information, and the operator can still press Start.
108
108
  */
109
109
  export function expectationLine(expectation) {
110
110
  if (expectation.sample === 0)
@@ -134,9 +134,9 @@ export function expectationLine(expectation) {
134
134
  /**
135
135
  * The one line a lab may say about itself, wherever it is shown.
136
136
  *
137
- * Prefers LIVE figures: cost and duration are what someone reads before spending, and a median
137
+ * Prefers live figures: cost and duration are what someone reads before spending, and a median
138
138
  * diluted by dry runs reports a live study as cheaper and faster than it has ever been. With no
139
- * live history it reports the count and claims nothing about time or money — which is why this is
139
+ * live history it reports the count and claims nothing about time or money. That is why this is
140
140
  * shared rather than reimplemented per surface, since the two disagreeing is the whole failure.
141
141
  */
142
142
  export function labSummaryLine(row) {
@@ -162,7 +162,7 @@ export function formatDuration(ms) {
162
162
  * arrive with markdown section leads (`**Thinking through setup**`) and hard newlines; a terminal
163
163
  * needs plain text wrapped to a line budget.
164
164
  *
165
- * The text is never paraphrased or shortened by meaning — only wrapped, and cut at a word boundary
165
+ * The text is never paraphrased or shortened by meaning. It is only wrapped, and cut at a word boundary
166
166
  * with an ellipsis when it does not fit. `truncated` is how the surface says so.
167
167
  */
168
168
  export function normalizeThought(text, options) {
@@ -247,19 +247,19 @@ function labNameFromPath(manifestPath) {
247
247
  /**
248
248
  * Join declared lab manifests to run history.
249
249
  *
250
- * Neither side alone is the truth. A fresh project has manifests and no runs — those labs are the
250
+ * Neither side alone is the truth. A fresh project has manifests and no runs, and those labs are the
251
251
  * whole screen, and a list built only from history would be empty on exactly the first visit that
252
252
  * matters. A long-lived project accumulates runs from labs whose manifest has since been renamed or
253
- * deleted — that evidence still exists on disk, so dropping those rows would make real runs
253
+ * deleted. That evidence still exists on disk, so dropping those rows would make real runs
254
254
  * unreachable from the surface that is supposed to list them.
255
255
  *
256
- * ONE ROW PER MANIFEST, not per id. The two are not the same thing: a manifest is addressed by its
256
+ * One row per manifest, not per id. The two are not the same thing: a manifest is addressed by its
257
257
  * filename while its runs attribute to the id declared inside it, so several files can legitimately
258
258
  * share an id. Collapsing them hides a real file; keying by id duplicates a row with no way to tell
259
- * the copies apart. Both happen in practice — this repo has exactly that pair.
259
+ * the copies apart. Both happen in practice: this repo has exactly that pair.
260
260
  *
261
261
  * Order puts a lab someone is working in first, then labs by how recently they ran, then declared
262
- * labs that have never run (alphabetically BY WHAT IS DISPLAYED, so the order on screen is the
262
+ * labs that have never run (alphabetically by the displayed label, so the order on screen is the
263
263
  * order a reader can predict), then labs known only from history.
264
264
  */
265
265
  export function labRows(declared, entries) {
@@ -267,7 +267,7 @@ export function labRows(declared, entries) {
267
267
  const byId = new Map(labs.map((lab) => [lab.labId, lab]));
268
268
  const runsOf = new Map();
269
269
  for (const entry of entries) {
270
- const labId = entry.lab?.id;
270
+ const labId = entry.study?.id;
271
271
  if (labId === undefined)
272
272
  continue;
273
273
  const bucket = runsOf.get(labId);
@@ -310,7 +310,7 @@ export function labRows(declared, entries) {
310
310
  .filter((lab) => !declaredIds.has(lab.labId))
311
311
  .map((lab) => build(lab.labId, undefined, false)),
312
312
  ];
313
- // Resolve each row's label BEFORE sorting, so the list is ordered by what a reader actually sees.
313
+ // Resolve each row's label before sorting, so the list is ordered by what a reader actually sees.
314
314
  assignLabels(rows);
315
315
  const label = (row) => row.label;
316
316
  rows.sort((left, right) => {
@@ -332,8 +332,8 @@ export function labRows(declared, entries) {
332
332
  /**
333
333
  * Give every row the shortest label that distinguishes it: title, else filename, else path.
334
334
  *
335
- * Falling straight back to the filename whenever a title repeats — rather than decorating the
336
- * duplicate with a suffix — keeps the label something the operator can act on, because the filename
335
+ * Falling straight back to the filename whenever a title repeats, instead of decorating the
336
+ * duplicate with a suffix, keeps the label something the operator can act on, because the filename
337
337
  * is exactly what `humanish lab run` takes.
338
338
  */
339
339
  function assignLabels(rows) {
@@ -1,4 +1,5 @@
1
1
  import { type E2BDesktopModule } from "../substrates/e2b/sdk.js";
2
+ import { type PreparedRunArtifactPaths } from "./paths.js";
2
3
  declare const RECLAIM_RESULT_SCHEMA = "humanish.reclaim-result.v1";
3
4
  export declare const RECLAIM_RECEIPT_ARTIFACT = "reclaim-receipt.json";
4
5
  interface ReclaimOutcome {
@@ -31,6 +32,11 @@ export interface ReclaimHooks {
31
32
  requestTimeoutMs?: number;
32
33
  }
33
34
  export declare function reclaimRunSandboxes(cwd: string, runInput: string, hooks?: ReclaimHooks): Promise<ReclaimResult>;
35
+ /**
36
+ * Reclaim the run whose directory the caller already holds. Nothing is resolved, so an id that is
37
+ * also an alias (a run named `latest`) cannot reach another run's receipts.
38
+ */
39
+ export declare function reclaimPinnedRunSandboxes(cwd: string, runPaths: PreparedRunArtifactPaths, hooks?: ReclaimHooks): Promise<ReclaimResult>;
34
40
  /**
35
41
  * Kill the sandboxes left by interrupted `humanish lab preflight` probes. A probe journals under
36
42
  * .humanish/preflight/<probe-id>/ and removes the journal after a confirmed kill, so what is left
@@ -1,4 +1,4 @@
1
- // `humanish reclaim`: kill an interrupted run's sandboxes by the EXACT ids the run journaled at
1
+ // `humanish reclaim`: kill an interrupted run's sandboxes by the exact ids the run journaled at
2
2
  // create time (sandbox-receipts.ndjson), and report what happened to each. It reads one file inside
3
3
  // the managed run dir, kills by id, and never lists the account: an account-wide operation once
4
4
  // destroyed unrelated infrastructure. Without it, orphaned sandboxes run until the server-side
@@ -13,7 +13,17 @@ import { redactText, toErrorMessage } from "../evidence/redaction.js";
13
13
  import { runIdOf } from "./paths.js";
14
14
  const RECLAIM_RESULT_SCHEMA = "humanish.reclaim-result.v1";
15
15
  export const RECLAIM_RECEIPT_ARTIFACT = "reclaim-receipt.json";
16
- export async function reclaimRunSandboxes(cwd, runInput, hooks = {}) {
16
+ export function reclaimRunSandboxes(cwd, runInput, hooks = {}) {
17
+ return reclaimRun(cwd, runInput, () => resolveRunPath(cwd, runInput), hooks);
18
+ }
19
+ /**
20
+ * Reclaim the run whose directory the caller already holds. Nothing is resolved, so an id that is
21
+ * also an alias (a run named `latest`) cannot reach another run's receipts.
22
+ */
23
+ export function reclaimPinnedRunSandboxes(cwd, runPaths, hooks = {}) {
24
+ return reclaimRun(cwd, runIdOf(runPaths), () => Promise.resolve(runPaths), hooks);
25
+ }
26
+ async function reclaimRun(cwd, runInput, locate, hooks) {
17
27
  const warnings = [];
18
28
  const base = {
19
29
  schema: RECLAIM_RESULT_SCHEMA,
@@ -25,7 +35,7 @@ export async function reclaimRunSandboxes(cwd, runInput, hooks = {}) {
25
35
  };
26
36
  if (e2bDebugMode())
27
37
  return { ...base, ok: false, error: E2B_DEBUG_REFUSAL };
28
- const runPaths = await resolveRunPath(cwd, runInput);
38
+ const runPaths = await locate();
29
39
  if (!runPaths) {
30
40
  return {
31
41
  ...base,
@@ -39,8 +49,8 @@ export async function reclaimRunSandboxes(cwd, runInput, hooks = {}) {
39
49
  const runId = runIdOf(runPaths);
40
50
  const journal = await reclaimJournal(runPaths, hooks);
41
51
  if (journal.kind === "empty") {
42
- // Honest empty: nothing journaled means either no sandbox was ever created (cheap interrupt —
43
- // nothing to reclaim) or the run predates receipts (0.35.x and earlier — the create-time TTL
52
+ // Empty: nothing journaled means either no sandbox was ever created (cheap interrupt:
53
+ // nothing to reclaim) or the run predates receipts (0.35.x and earlier, where the create-time TTL
44
54
  // is the only backstop for those). Either way there is no id to act on, and saying so beats
45
55
  // pretending a scan happened.
46
56
  warnings.push("No sandbox-receipts.ndjson in this run dir: either no sandbox was created before the interrupt, or the run predates create-time receipts. Nothing to reclaim by id; server-side kill-on-timeout covers anything that did exist.");
@@ -1,14 +1,14 @@
1
1
  import type { ObserverResult } from "../observer/render.js";
2
2
  import type { RunProviderResource } from "./bundle.js";
3
- import type { RunLabProvenance } from "./status.js";
3
+ import type { RunStudyProvenance } from "./study-provenance.js";
4
4
  export declare const CLEANUP_SCHEMA = "humanish.cleanup-result.v1";
5
5
  export interface RunOptions {
6
- /** Which manifest produced this run (#455). */
7
- lab?: RunLabProvenance;
6
+ /** Which manifest produced this run. */
7
+ lab?: RunStudyProvenance;
8
8
  cwd: string;
9
9
  dryRun?: boolean;
10
10
  runId?: string;
11
- simCount?: number;
11
+ participantCount?: number;
12
12
  /** Render the run's Observer through the finished run, opening the page when `open` is true.
13
13
  * Without it the preview writes no observer/index.html. */
14
14
  observer?: {
@@ -30,7 +30,7 @@ export interface RunResult {
30
30
  observer?: ObserverResult;
31
31
  warnings: string[];
32
32
  error?: {
33
- code: "HUMANISH_LAB_ANALYSIS_INVALID" | "HUMANISH_LAB_ANALYSIS_UNSUPPORTED" | "HUMANISH_LAB_TASKS_UNSUPPORTED" | "HUMANISH_LAB_OPTION_CONFLICT" | "HUMANISH_LAB_OPTION_UNSUPPORTED" | "HUMANISH_LAB_COMMS_UNSUPPORTED" | "HUMANISH_LIVE_RUN_UNIMPLEMENTED" | "HUMANISH_INVALID_CWD" | "HUMANISH_RUN_ID_IN_USE" | "HUMANISH_INVALID_SIM_COUNT" | "HUMANISH_INVALID_PORT" | "HUMANISH_UNSUPPORTED_RERUN_FLAGS" | "HUMANISH_WATCH_OPTION_CONFLICT" | "HUMANISH_WATCH_SAFE_NOT_APPLICABLE" | "HUMANISH_APP_URL_REMOVED" | "HUMANISH_LAB_SCORER_BAD_REF" | "HUMANISH_LAB_SCORER_NOT_FOUND" | "HUMANISH_LAB_SCORER_LOAD_FAILED" | "HUMANISH_LAB_SCORER_NO_HOOKS" | "HUMANISH_LAB_SCORER_UNSUPPORTED_BACKEND";
33
+ code: "HUMANISH_STUDY_ANALYSIS_INVALID" | "HUMANISH_STUDY_ANALYSIS_UNSUPPORTED" | "HUMANISH_STUDY_TASKS_UNSUPPORTED" | "HUMANISH_STUDY_OPTION_UNSUPPORTED" | "HUMANISH_STUDY_COMMS_UNSUPPORTED" | "HUMANISH_LIVE_RUN_UNIMPLEMENTED" | "HUMANISH_INVALID_CWD" | "HUMANISH_RUN_ID_IN_USE" | "HUMANISH_INVALID_PARTICIPANT_COUNT" | "HUMANISH_INVALID_PORT" | "HUMANISH_UNSUPPORTED_RERUN_FLAGS" | "HUMANISH_WATCH_OPTION_CONFLICT" | "HUMANISH_WATCH_SAFE_NOT_APPLICABLE" | "HUMANISH_RUN_OPTION_CONFLICT" | "HUMANISH_OBSERVE_OPTION_CONFLICT" | "HUMANISH_STUDY_SCORER_BAD_REF" | "HUMANISH_STUDY_SCORER_NOT_FOUND" | "HUMANISH_STUDY_SCORER_LOAD_FAILED" | "HUMANISH_STUDY_SCORER_NO_HOOKS" | "HUMANISH_STUDY_SCORER_UNSUPPORTED_BACKEND";
34
34
  message: string;
35
35
  };
36
36
  }
@@ -1,4 +1,5 @@
1
- import { type RunLabProvenance, type RunLiveness, type RunStatusRecord } from "./status.js";
1
+ import { type RunLiveness, type RunStatusRecord } from "./status.js";
2
+ import { type RunStudyProvenance } from "./study-provenance.js";
2
3
  declare const RUN_INDEX_SCHEMA = "humanish.run-index.v1";
3
4
  export interface RunIndexEntry {
4
5
  runId: string;
@@ -7,12 +8,12 @@ export interface RunIndexEntry {
7
8
  liveness: RunLiveness;
8
9
  mode?: "dry-run" | "live";
9
10
  /**
10
- * The pid that owns a run, when it recorded one. This is how a surface identifies the run IT just
11
+ * The pid that owns a run, when it recorded one. This is how a surface identifies the run it just
11
12
  * started without minting an id or guessing at a new directory: it spawned a process, and exactly
12
13
  * one run's record carries that pid.
13
14
  */
14
15
  pid?: number;
15
- lab?: RunLabProvenance;
16
+ study?: RunStudyProvenance;
16
17
  startedAt?: string;
17
18
  updatedAt?: string;
18
19
  completedAt?: string;
@@ -31,7 +32,7 @@ export interface RunIndexResult {
31
32
  cwd: string;
32
33
  /** Newest first, by the best timestamp each entry has. */
33
34
  runs: RunIndexEntry[];
34
- /** Directories that could not be read at all, by name — surfaced, never silently dropped. */
35
+ /** Directories that could not be read at all, by name: surfaced, never silently dropped. */
35
36
  unreadable: string[];
36
37
  }
37
38
  /** What a cached entry was derived from, so a changed file invalidates exactly that entry. */
@@ -59,7 +60,8 @@ interface BundleFacts {
59
60
  runId?: string;
60
61
  mode?: string;
61
62
  createdAt?: string;
62
- lab?: RunLabProvenance;
63
+ study?: unknown;
64
+ lab?: unknown;
63
65
  persona?: {
64
66
  source?: string;
65
67
  };
@@ -95,8 +97,8 @@ export interface ReadRunIndexOptions {
95
97
  cache?: RunIndexCache;
96
98
  /** Injectable clock, so liveness classification is reproducible in tests. */
97
99
  nowMs?: number;
98
- /** Cap the number of runs returned (newest first). The full directory is still enumerated —
99
- * a cap on reads, not on truth — and the count reflects what was read. */
100
+ /** Cap the number of runs returned (newest first). The full directory is still enumerated;
101
+ * the cap limits reads, and the count reflects what was read. */
100
102
  limit?: number;
101
103
  }
102
104
  /**
@@ -1,21 +1,22 @@
1
- // The run index (#455 PR 2): list and classify every run in a project WITHOUT parsing bundles.
1
+ // The run index: list and classify every run in a project without parsing bundles.
2
2
  //
3
- // The existing `listRuns` walks each run tree — screenshots included — validating symlinks and
3
+ // The existing `listRuns` walks each run tree, screenshots included, validating symlinks and
4
4
  // then parses each `run.json`: measured 197ms cold / 152ms warm at 25 runs. That is fine for a
5
5
  // command that prints once and exits, and much too hot for a surface that refreshes on a cadence
6
6
  // over SSH. This module reads the small `status.json` record each run now writes (586 bytes beside
7
7
  // a 92KB bundle) and caches per-run entries keyed on the stat of the file each was derived from.
8
8
  //
9
- // HONESTY RULES, unchanged from the record itself:
9
+ // Rules, unchanged from the record itself:
10
10
  // - `run.json` is the evidence-of-record. Every field here is a projection for listing and
11
11
  // classification; nothing here is a claim about what a participant did.
12
- // - A run with no status record is NOT assumed finished. It is classified from what is on disk:
13
- // a bundle means finished, receipts without a bundle mean interrupted. That is the honest
14
- // reading of a run whose process died — and, before this contract existed, of every run.
12
+ // - A run with no status record is not assumed finished. It is classified from what is on disk:
13
+ // a bundle means finished, receipts without a bundle mean interrupted. That is the
14
+ // reading of a run whose process died (and, before this contract existed, of every run).
15
15
  // - One unreadable run directory degrades that run, never the listing.
16
16
  import { readdir, readFile, stat } from "node:fs/promises";
17
17
  import path from "node:path";
18
- import { RUN_STATUS_FILE, classifyRunStatus, inferLegacyLabId, isRunStatusRecord, } from "./status.js";
18
+ import { RUN_STATUS_FILE, classifyRunStatus, isRunStatusRecord, } from "./status.js";
19
+ import { studyProvenanceOf } from "./study-provenance.js";
19
20
  import { RUN_BUNDLE_FILE } from "./bundle.js";
20
21
  const RUN_INDEX_SCHEMA = "humanish.run-index.v1";
21
22
  /**
@@ -78,7 +79,7 @@ function entryFromStatus(record, nowMs) {
78
79
  liveness: classifyRunStatus(record, nowMs),
79
80
  mode: record.mode,
80
81
  ...(typeof record.pid === "number" ? { pid: record.pid } : {}),
81
- ...(record.lab === undefined ? {} : { lab: record.lab }),
82
+ ...studyEntry(studyProvenanceOf(record)),
82
83
  startedAt: record.startedAt,
83
84
  updatedAt: record.updatedAt,
84
85
  ...(record.completedAt === undefined ? {} : { completedAt: record.completedAt }),
@@ -97,10 +98,10 @@ function usableStatusRecord(raw, runId) {
97
98
  return isRunStatusRecord(raw) && raw.runId === runId;
98
99
  }
99
100
  /**
100
- * The bundle-only reading, for a run with no usable status record. A bundle on disk USUALLY means
101
- * the run reached its final write. But a live run now flushes an IN-PROGRESS bundle as it goes (so
101
+ * The bundle-only reading, for a run with no usable status record. A bundle on disk usually means
102
+ * the run reached its final write. But a live run now flushes an in-progress bundle as it goes (so
102
103
  * anything asking what a participant is doing has something to read), and that bundle marks its
103
- * simulations `running`. With no status record there is no freshness to judge, and the honest
104
+ * simulations `running`. With no status record there is no freshness to judge, and the
104
105
  * reading of "it started, and nothing here says it finished" is interrupted, not finished.
105
106
  */
106
107
  function bundleLiveness(bundle) {
@@ -117,18 +118,16 @@ export function runLiveness(runId, status, bundle, nowMs) {
117
118
  ? { liveness: classifyRunStatus(status, nowMs), record: status }
118
119
  : { liveness: bundleLiveness(bundle) };
119
120
  }
121
+ function studyEntry(study) {
122
+ return study === undefined ? {} : { study };
123
+ }
120
124
  function entryFromBundle(runId, bundle) {
121
- const legacyLabId = bundle.lab === undefined ? inferLegacyLabId(bundle) : undefined;
122
125
  return {
123
126
  runId,
124
127
  derivedFrom: "bundle",
125
128
  liveness: bundleLiveness(bundle),
126
129
  ...(bundle.mode === "dry-run" || bundle.mode === "live" ? { mode: bundle.mode } : {}),
127
- ...(bundle.lab !== undefined
128
- ? { lab: bundle.lab }
129
- : legacyLabId === undefined
130
- ? {}
131
- : { lab: { id: legacyLabId } }),
130
+ ...studyEntry(studyProvenanceOf(bundle)),
132
131
  ...(bundle.createdAt === undefined ? {} : { startedAt: bundle.createdAt }),
133
132
  ...(bundle.review?.verdict === undefined ? {} : { verdict: bundle.review.verdict }),
134
133
  ...(bundle.review?.participants === undefined
@@ -169,15 +168,15 @@ export async function readRunIndex(cwdInput, options = {}) {
169
168
  if (statusKey !== null) {
170
169
  const cached = cache?.get(runId, statusKey);
171
170
  if (cached !== undefined) {
172
- // Liveness is time-dependent, so it is recomputed even on a cache hit — a record that has
173
- // not changed can still have gone stale since the last read.
174
- runs.push(cached.derivedFrom === "status" && cached.updatedAt !== undefined
171
+ // A running record's liveness is time-dependent, so it is recomputed even on a cache hit:
172
+ // an unchanged record can still have gone stale. An ended record (finished or
173
+ // interrupted, both with completedAt) keeps the liveness it was cached with.
174
+ runs.push(cached.derivedFrom === "status" &&
175
+ cached.updatedAt !== undefined &&
176
+ cached.completedAt === undefined
175
177
  ? {
176
178
  ...cached,
177
- liveness: classifyRunStatus({
178
- state: cached.completedAt === undefined ? "running" : "finished",
179
- updatedAt: cached.updatedAt,
180
- }, nowMs),
179
+ liveness: classifyRunStatus({ state: "running", updatedAt: cached.updatedAt }, nowMs),
181
180
  }
182
181
  : cached);
183
182
  continue;
@@ -210,7 +209,7 @@ export async function readRunIndex(cwdInput, options = {}) {
210
209
  continue;
211
210
  }
212
211
  // Neither record nor bundle: receipts without an outcome. That is precisely an interrupted
213
- // run — the shape a dropped connection leaves — and saying so is more useful than hiding it.
212
+ // run (the shape a dropped connection leaves), and saying so is more useful than hiding it.
214
213
  runs.push({ runId, derivedFrom: "directory", liveness: "interrupted" });
215
214
  }
216
215
  cache?.retain(runIds);
@@ -0,0 +1,5 @@
1
+ /**
2
+ * The message for a run that is not there: how to start one when the project has no runs, or how
3
+ * to list them when it has. Only the runs directory's entry names are read.
4
+ */
5
+ export declare function runNotFoundMessage(cwdInput: string, runInput: string): Promise<string>;
@@ -0,0 +1,15 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { resolveRunsRoot } from "./paths.js";
4
+ /**
5
+ * The message for a run that is not there: how to start one when the project has no runs, or how
6
+ * to list them when it has. Only the runs directory's entry names are read.
7
+ */
8
+ export async function runNotFoundMessage(cwdInput, runInput) {
9
+ const cwd = path.resolve(cwdInput);
10
+ const entries = await readdir(resolveRunsRoot(cwd)).catch(() => []);
11
+ const hasRun = entries.some((name) => !name.startsWith(".") && !name.endsWith(".json"));
12
+ return hasRun
13
+ ? `No run ${runInput}; humanish runs lists them.`
14
+ : `No runs in ${cwd} yet; start one with humanish run first-run.`;
15
+ }
package/dist/run/run.d.ts CHANGED
@@ -2,7 +2,8 @@ import { renderObserver, type ObserverResult } from "../observer/render.js";
2
2
  import { type RunBundle } from "./bundle.js";
3
3
  import type { ExecutionOutcome } from "./judge.js";
4
4
  import { type PreparedRunArtifactPaths, type RunIdInUse } from "./paths.js";
5
- import { type RunLabProvenance, type RunStatusHandle } from "./status.js";
5
+ import { type RunStatusHandle } from "./status.js";
6
+ import type { RunStudyProvenance } from "./study-provenance.js";
6
7
  interface StartRunOptions {
7
8
  /** Project directory, in the form the route resolved it. */
8
9
  cwd: string;
@@ -10,10 +11,10 @@ interface StartRunOptions {
10
11
  runId?: string | undefined;
11
12
  mintRunId: () => string;
12
13
  mode: "dry-run" | "live";
13
- lab?: RunLabProvenance | undefined;
14
+ lab?: RunStudyProvenance | undefined;
14
15
  /** review.md for the published bundle. */
15
16
  renderReview: (bundle: RunBundle) => string;
16
- /** Used by `FinishedRun.renderObserver`; `render` is the routes' `renderObserverFn` seam. */
17
+ /** Used by `FinishedRun.renderObserver`; `render` is the `LabDeps.renderObserver` seam. */
17
18
  observer?: {
18
19
  open: boolean;
19
20
  render?: typeof renderObserver | undefined;
@@ -25,7 +26,9 @@ interface Run {
25
26
  readonly runId: string;
26
27
  readonly createdAt: string;
27
28
  readonly mode: "dry-run" | "live";
28
- /** Routes write their evidence files through these and hand them to lanes. */
29
+ /** The manifest the run came from; bundleHead copies it into the bundle. */
30
+ readonly lab?: RunStudyProvenance;
31
+ /** Routes write their evidence files through these and hand them to participants. */
29
32
  readonly paths: PreparedRunArtifactPaths;
30
33
  /**
31
34
  * Publish an in-progress bundle: run.json, review.json, review.md, events.ndjson and