humanish 0.108.0 → 0.109.1

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 (461) hide show
  1. package/ARCHITECTURE.md +58 -59
  2. package/CHANGELOG.md +22 -0
  3. package/CONTEXT.md +44 -44
  4. package/README.md +3 -3
  5. package/TELEMETRY.md +2 -2
  6. package/dist/actors/codex/app-server-trace.js +2 -1
  7. package/dist/actors/codex/restricted-participant.js +12 -12
  8. package/dist/actors/codex/restricted-session.d.ts +2 -2
  9. package/dist/actors/computer-use/actor.d.ts +6 -6
  10. package/dist/actors/computer-use/actor.js +2 -2
  11. package/dist/actors/computer-use/admission-limit.d.ts +2 -2
  12. package/dist/actors/computer-use/admission-limit.js +3 -3
  13. package/dist/actors/computer-use/executor-error.d.ts +2 -2
  14. package/dist/actors/computer-use/executor-error.js +3 -3
  15. package/dist/actors/computer-use/loop/actions.js +5 -5
  16. package/dist/actors/computer-use/loop/debrief.js +2 -2
  17. package/dist/actors/computer-use/loop/ending.d.ts +1 -1
  18. package/dist/actors/computer-use/loop/ending.js +12 -11
  19. package/dist/actors/computer-use/loop/observation.js +6 -5
  20. package/dist/actors/computer-use/loop/provider-call.js +11 -11
  21. package/dist/actors/computer-use/loop/session.d.ts +4 -4
  22. package/dist/actors/computer-use/loop/session.js +2 -2
  23. package/dist/actors/computer-use/loop/trace.js +3 -2
  24. package/dist/actors/computer-use/loop/types.d.ts +24 -24
  25. package/dist/actors/computer-use/loop/usage.d.ts +2 -2
  26. package/dist/actors/computer-use/loop.d.ts +6 -1
  27. package/dist/actors/computer-use/loop.js +26 -4
  28. package/dist/actors/computer-use/openai-provider.d.ts +2 -2
  29. package/dist/actors/computer-use/openai-provider.js +8 -8
  30. package/dist/actors/computer-use/provider-error.d.ts +4 -4
  31. package/dist/actors/computer-use/provider-error.js +6 -6
  32. package/dist/actors/contract.d.ts +4 -4
  33. package/dist/actors/contract.js +1 -1
  34. package/dist/actors/local-agent/claude-session.js +3 -3
  35. package/dist/actors/local-agent/cli.d.ts +1 -1
  36. package/dist/actors/local-agent/cli.js +1 -1
  37. package/dist/actors/reasoning-effort.js +3 -3
  38. package/dist/actors/registry.d.ts +2 -2
  39. package/dist/actors/registry.js +3 -3
  40. package/dist/actors/scripted-browser/actor.d.ts +2 -2
  41. package/dist/actors/scripted-browser/actor.js +1 -1
  42. package/dist/analysis/automatic-completion.d.ts +7 -7
  43. package/dist/analysis/automatic-completion.js +1 -1
  44. package/dist/analysis/automatic-config.d.ts +6 -6
  45. package/dist/analysis/automatic-config.js +1 -1
  46. package/dist/analysis/execute.d.ts +1 -1
  47. package/dist/analysis/execute.js +1 -1
  48. package/dist/analysis/types.d.ts +6 -0
  49. package/dist/browser-control/client.js +16 -16
  50. package/dist/browser-control/dispatcher.js +4 -4
  51. package/dist/browser-control/protocol.js +14 -14
  52. package/dist/browser-control/recording-transfer.js +4 -4
  53. package/dist/browser-control/transport.js +7 -7
  54. package/dist/cli/commands/analysis-signals.d.ts +2 -2
  55. package/dist/cli/commands/comms.js +14 -22
  56. package/dist/cli/commands/migrate.js +15 -4
  57. package/dist/cli/commands/observe.d.ts +0 -1
  58. package/dist/cli/commands/observe.js +0 -15
  59. package/dist/cli/commands/run-command.d.ts +2 -2
  60. package/dist/cli/commands/run-command.js +3 -3
  61. package/dist/cli/commands/runs.js +9 -7
  62. package/dist/cli/commands/setup.js +5 -7
  63. package/dist/cli/commands/study-format.d.ts +9 -0
  64. package/dist/cli/commands/{lab-format.js → study-format.js} +5 -5
  65. package/dist/cli/commands/{lab-route-computer-use.d.ts → study-route-computer-use.d.ts} +6 -6
  66. package/dist/cli/commands/{lab-route-computer-use.js → study-route-computer-use.js} +12 -12
  67. package/dist/cli/commands/{lab-route-open.d.ts → study-route-open.d.ts} +4 -4
  68. package/dist/cli/commands/{lab-route-open.js → study-route-open.js} +2 -2
  69. package/dist/cli/commands/{lab-route-preview.d.ts → study-route-preview.d.ts} +7 -7
  70. package/dist/cli/commands/{lab-route-preview.js → study-route-preview.js} +3 -3
  71. package/dist/cli/commands/study-route-run.d.ts +19 -0
  72. package/dist/cli/commands/{lab-route-run.js → study-route-run.js} +6 -6
  73. package/dist/cli/commands/study-route-scripted.d.ts +17 -0
  74. package/dist/cli/commands/{lab-route-scripted.js → study-route-scripted.js} +4 -4
  75. package/dist/cli/commands/{lab-route-shared-world.d.ts → study-route-shared-world.d.ts} +5 -5
  76. package/dist/cli/commands/{lab-route-shared-world.js → study-route-shared-world.js} +7 -7
  77. package/dist/cli/commands/study-route-terminal.d.ts +17 -0
  78. package/dist/cli/commands/{lab-route-terminal.js → study-route-terminal.js} +4 -4
  79. package/dist/cli/commands/study-run.d.ts +9 -0
  80. package/dist/cli/commands/{lab-run.js → study-run.js} +34 -34
  81. package/dist/cli/commands/{lab-scorer.d.ts → study-scorer.d.ts} +5 -5
  82. package/dist/cli/commands/{lab-scorer.js → study-scorer.js} +1 -1
  83. package/dist/cli/commands/study.js +13 -49
  84. package/dist/cli/commands/tui.js +12 -12
  85. package/dist/cli/commands/watch.js +30 -65
  86. package/dist/cli/deprecations.d.ts +1 -13
  87. package/dist/cli/deprecations.js +0 -30
  88. package/dist/cli/doctor.d.ts +3 -3
  89. package/dist/cli/doctor.js +16 -16
  90. package/dist/cli/first-run-path.d.ts +4 -4
  91. package/dist/cli/first-run-path.js +7 -7
  92. package/dist/cli/io.d.ts +3 -3
  93. package/dist/cli/io.js +2 -2
  94. package/dist/cli/observer-follow.d.ts +2 -2
  95. package/dist/cli/observer-follow.js +2 -2
  96. package/dist/cli/orientation.d.ts +4 -4
  97. package/dist/cli/orientation.js +58 -20
  98. package/dist/cli/program.js +3 -4
  99. package/dist/cli/telemetry.d.ts +1 -1
  100. package/dist/cli/telemetry.js +14 -20
  101. package/dist/comms/catch-host.d.ts +1 -1
  102. package/dist/comms/catch-host.js +3 -3
  103. package/dist/comms/connections.d.ts +1 -1
  104. package/dist/comms/connections.js +2 -2
  105. package/dist/comms/external-evidence.d.ts +5 -5
  106. package/dist/comms/external-evidence.js +4 -3
  107. package/dist/comms/fake-inbox.d.ts +2 -2
  108. package/dist/comms/fake-inbox.js +2 -2
  109. package/dist/comms/receiving-runtime.d.ts +4 -4
  110. package/dist/comms/sandbox-catch.d.ts +2 -2
  111. package/dist/comms/sandbox-catch.js +2 -2
  112. package/dist/comms/setup.d.ts +2 -2
  113. package/dist/comms/setup.js +29 -32
  114. package/dist/evidence/redaction.d.ts +11 -0
  115. package/dist/evidence/redaction.js +43 -0
  116. package/dist/feedback/draft.js +2 -2
  117. package/dist/feedback/export-bundle.js +5 -4
  118. package/dist/feedback/export.js +3 -2
  119. package/dist/feedback/proof.d.ts +1 -1
  120. package/dist/feedback/proof.js +2 -2
  121. package/dist/guest/bootstrap.js +6 -6
  122. package/dist/guest/browser-tools.js +8 -8
  123. package/dist/guest/chromium-text.js +17 -17
  124. package/dist/guest/desktop-executor.d.ts +2 -2
  125. package/dist/guest/desktop-executor.js +20 -20
  126. package/dist/guest/desktop-keys.js +4 -4
  127. package/dist/guest/desktop-media.d.ts +2 -2
  128. package/dist/guest/desktop-media.js +16 -16
  129. package/dist/guest/desktop-native.js +10 -10
  130. package/dist/guest/runtime-desktop.js +2 -2
  131. package/dist/guest/runtime-processes.d.ts +2 -2
  132. package/dist/guest/runtime-processes.js +2 -2
  133. package/dist/guest/runtime.js +5 -5
  134. package/dist/index.d.ts +13 -15
  135. package/dist/index.js +6 -8
  136. package/dist/observer/artifact.d.ts +1 -1
  137. package/dist/observer/artifact.js +1 -1
  138. package/dist/observer/data.d.ts +1 -1
  139. package/dist/observer/library.d.ts +2 -0
  140. package/dist/observer/library.js +4 -1
  141. package/dist/observer/render.js +7 -1
  142. package/dist/observer/run-routes.d.ts +1 -0
  143. package/dist/observer/run-routes.js +37 -12
  144. package/dist/observer/serve.d.ts +1 -1
  145. package/dist/observer-app.html +1 -1
  146. package/dist/routes/computer-use/bundle-parts.js +3 -2
  147. package/dist/routes/computer-use/bundle.d.ts +2 -2
  148. package/dist/routes/computer-use/bundle.js +7 -6
  149. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +5 -5
  150. package/dist/routes/computer-use/e2b-desktop/comms.js +5 -4
  151. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +1 -1
  152. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +1 -1
  153. package/dist/routes/computer-use/e2b-desktop/prepare.js +3 -3
  154. package/dist/routes/computer-use/e2b-desktop/start.js +3 -4
  155. package/dist/routes/computer-use/e2b-desktop/state.d.ts +2 -2
  156. package/dist/routes/computer-use/e2b-desktop/teardown.js +2 -3
  157. package/dist/routes/computer-use/external-comms.d.ts +3 -3
  158. package/dist/routes/computer-use/fanout-bundle.js +11 -10
  159. package/dist/routes/computer-use/fanout-records.js +2 -2
  160. package/dist/routes/computer-use/in-process-desktop.js +1 -1
  161. package/dist/routes/computer-use/live-flush.d.ts +3 -3
  162. package/dist/routes/computer-use/live-phase.d.ts +2 -3
  163. package/dist/routes/computer-use/live-phase.js +3 -3
  164. package/dist/routes/computer-use/local-tree-pack.d.ts +5 -5
  165. package/dist/routes/computer-use/local-tree-pack.js +1 -1
  166. package/dist/routes/computer-use/local-vm.d.ts +8 -8
  167. package/dist/routes/computer-use/local-vm.js +2 -2
  168. package/dist/routes/computer-use/participant-desktop.d.ts +3 -3
  169. package/dist/routes/computer-use/participant-desktop.js +1 -1
  170. package/dist/routes/computer-use/participant-execution.js +1 -1
  171. package/dist/routes/computer-use/participant-model.js +3 -3
  172. package/dist/routes/computer-use/participant-prompt.d.ts +5 -5
  173. package/dist/routes/computer-use/participant-prompt.js +3 -3
  174. package/dist/routes/computer-use/participant-runs.d.ts +10 -10
  175. package/dist/routes/computer-use/participant-runs.js +14 -13
  176. package/dist/routes/computer-use/plan.d.ts +12 -12
  177. package/dist/routes/computer-use/plan.js +27 -27
  178. package/dist/routes/computer-use/preflight.d.ts +5 -5
  179. package/dist/routes/computer-use/preflight.js +5 -5
  180. package/dist/routes/computer-use/rerun-selection.d.ts +1 -1
  181. package/dist/routes/computer-use/rerun-selection.js +3 -2
  182. package/dist/routes/computer-use/result.d.ts +4 -4
  183. package/dist/routes/computer-use/result.js +13 -12
  184. package/dist/routes/computer-use/route.d.ts +12 -12
  185. package/dist/routes/computer-use/route.js +19 -19
  186. package/dist/routes/computer-use/self-report.js +1 -1
  187. package/dist/routes/computer-use/setup.d.ts +22 -22
  188. package/dist/routes/computer-use/setup.js +15 -15
  189. package/dist/routes/computer-use/single-bundle.d.ts +4 -4
  190. package/dist/routes/computer-use/single-bundle.js +14 -13
  191. package/dist/routes/computer-use/subject-projection.d.ts +3 -3
  192. package/dist/routes/computer-use/types.d.ts +34 -34
  193. package/dist/routes/computer-use/types.js +3 -3
  194. package/dist/routes/preview.d.ts +6 -6
  195. package/dist/routes/preview.js +5 -5
  196. package/dist/routes/scripted/bundle.d.ts +6 -6
  197. package/dist/routes/scripted/bundle.js +10 -9
  198. package/dist/routes/scripted/plan.d.ts +7 -7
  199. package/dist/routes/scripted/plan.js +6 -6
  200. package/dist/routes/scripted/result.d.ts +3 -3
  201. package/dist/routes/scripted/result.js +9 -9
  202. package/dist/routes/scripted/route.d.ts +9 -9
  203. package/dist/routes/scripted/route.js +11 -11
  204. package/dist/routes/scripted/scenario.d.ts +1 -1
  205. package/dist/routes/scripted/scenario.js +3 -3
  206. package/dist/routes/scripted/setup.d.ts +6 -6
  207. package/dist/routes/scripted/setup.js +4 -4
  208. package/dist/routes/scripted/subject.d.ts +5 -5
  209. package/dist/routes/scripted/subject.js +3 -3
  210. package/dist/routes/scripted/surface-records.d.ts +1 -1
  211. package/dist/routes/scripted/surface-records.js +2 -2
  212. package/dist/routes/scripted/surface-sessions.d.ts +3 -3
  213. package/dist/routes/scripted/types.d.ts +17 -17
  214. package/dist/routes/scripted/types.js +1 -1
  215. package/dist/routes/shared-world/bundle-records.js +3 -3
  216. package/dist/routes/shared-world/bundle.js +15 -14
  217. package/dist/routes/shared-world/checkpoints.d.ts +3 -3
  218. package/dist/routes/shared-world/checkpoints.js +1 -1
  219. package/dist/routes/shared-world/comms.d.ts +9 -9
  220. package/dist/routes/shared-world/comms.js +6 -5
  221. package/dist/routes/shared-world/participant-specs.d.ts +3 -3
  222. package/dist/routes/shared-world/participant-specs.js +7 -7
  223. package/dist/routes/shared-world/plan.d.ts +9 -9
  224. package/dist/routes/shared-world/plan.js +9 -9
  225. package/dist/routes/shared-world/provisioned.d.ts +8 -8
  226. package/dist/routes/shared-world/provisioned.js +4 -4
  227. package/dist/routes/shared-world/result.d.ts +6 -6
  228. package/dist/routes/shared-world/result.js +11 -10
  229. package/dist/routes/shared-world/route.d.ts +11 -11
  230. package/dist/routes/shared-world/route.js +19 -19
  231. package/dist/routes/shared-world/setup.d.ts +13 -13
  232. package/dist/routes/shared-world/setup.js +19 -19
  233. package/dist/routes/shared-world/types.d.ts +27 -27
  234. package/dist/routes/terminal/adapter.d.ts +2 -2
  235. package/dist/routes/terminal/adapter.js +4 -4
  236. package/dist/routes/terminal/bundle.d.ts +11 -11
  237. package/dist/routes/terminal/bundle.js +12 -12
  238. package/dist/routes/terminal/credentials.d.ts +4 -4
  239. package/dist/routes/terminal/credentials.js +5 -5
  240. package/dist/routes/terminal/dry-run.d.ts +4 -4
  241. package/dist/routes/terminal/dry-run.js +9 -9
  242. package/dist/routes/terminal/ledger.d.ts +2 -2
  243. package/dist/routes/terminal/lifetime.d.ts +1 -1
  244. package/dist/routes/terminal/lifetime.js +1 -1
  245. package/dist/routes/terminal/live-finish.d.ts +2 -2
  246. package/dist/routes/terminal/live-finish.js +7 -7
  247. package/dist/routes/terminal/live-sandbox.d.ts +2 -2
  248. package/dist/routes/terminal/live-sandbox.js +3 -2
  249. package/dist/routes/terminal/participant-text.js +2 -1
  250. package/dist/routes/terminal/persona.d.ts +2 -2
  251. package/dist/routes/terminal/persona.js +2 -2
  252. package/dist/routes/terminal/plan.d.ts +7 -7
  253. package/dist/routes/terminal/plan.js +5 -5
  254. package/dist/routes/terminal/result.d.ts +5 -5
  255. package/dist/routes/terminal/result.js +7 -7
  256. package/dist/routes/terminal/route.d.ts +9 -9
  257. package/dist/routes/terminal/route.js +14 -14
  258. package/dist/routes/terminal/session.d.ts +5 -5
  259. package/dist/routes/terminal/session.js +7 -7
  260. package/dist/routes/terminal/trace.d.ts +2 -2
  261. package/dist/routes/terminal/types.d.ts +24 -24
  262. package/dist/routes/terminal/types.js +2 -2
  263. package/dist/run/bundle.d.ts +7 -7
  264. package/dist/run/bundle.js +2 -2
  265. package/dist/run/costs.d.ts +23 -0
  266. package/dist/run/costs.js +72 -43
  267. package/dist/run/dry-run-inputs.d.ts +1 -1
  268. package/dist/run/dry-run-inputs.js +1 -1
  269. package/dist/run/dry-run.js +2 -2
  270. package/dist/run/outcomes.d.ts +1 -1
  271. package/dist/run/participant.d.ts +1 -1
  272. package/dist/run/preflight-receipts.js +1 -1
  273. package/dist/run/pricing.js +2 -2
  274. package/dist/run/projection.d.ts +32 -32
  275. package/dist/run/projection.js +44 -44
  276. package/dist/run/reclaim.d.ts +1 -1
  277. package/dist/run/reclaim.js +1 -1
  278. package/dist/run/results.d.ts +2 -2
  279. package/dist/run/run-cost.d.ts +53 -0
  280. package/dist/run/run-cost.js +105 -0
  281. package/dist/run/run-index-analysis.d.ts +15 -0
  282. package/dist/run/run-index-analysis.js +77 -0
  283. package/dist/run/run-index.d.ts +11 -1
  284. package/dist/run/run-index.js +63 -49
  285. package/dist/run/run.d.ts +3 -3
  286. package/dist/run/run.js +2 -2
  287. package/dist/run/shared-world-evidence.d.ts +1 -1
  288. package/dist/run/shared-world-shape.js +1 -1
  289. package/dist/run/stats.d.ts +3 -3
  290. package/dist/run/stats.js +14 -14
  291. package/dist/run/status.d.ts +10 -2
  292. package/dist/run/status.js +6 -3
  293. package/dist/run/streams.d.ts +2 -2
  294. package/dist/run/study-provenance.d.ts +4 -2
  295. package/dist/run/study-provenance.js +7 -4
  296. package/dist/run/study-result.d.ts +0 -5
  297. package/dist/run/study-result.js +1 -1
  298. package/dist/run-study.d.ts +112 -0
  299. package/dist/{run-lab.js → run-study.js} +52 -45
  300. package/dist/{lab → study}/adapter-extension.d.ts +8 -20
  301. package/dist/{lab → study}/adapter-extension.js +2 -14
  302. package/dist/{lab → study}/adapter-scorer-loader.d.ts +10 -10
  303. package/dist/{lab → study}/adapter-scorer-loader.js +3 -3
  304. package/dist/study/composition-rules.d.ts +7 -0
  305. package/dist/{lab → study}/composition-rules.js +12 -12
  306. package/dist/study/config.d.ts +15 -0
  307. package/dist/{lab → study}/config.js +37 -20
  308. package/dist/study/convert.d.ts +1 -1
  309. package/dist/study/convert.js +15 -15
  310. package/dist/{lab → study}/device-presets.d.ts +2 -2
  311. package/dist/{lab → study}/discover.d.ts +29 -23
  312. package/dist/{lab → study}/discover.js +97 -118
  313. package/dist/{lab → study}/doctor.d.ts +11 -11
  314. package/dist/{lab → study}/doctor.js +18 -18
  315. package/dist/study/files.d.ts +2 -2
  316. package/dist/study/files.js +6 -5
  317. package/dist/{lab → study}/init-templates.d.ts +2 -2
  318. package/dist/{lab → study}/init-templates.js +16 -11
  319. package/dist/{lab → study}/init.d.ts +1 -1
  320. package/dist/{lab → study}/init.js +7 -4
  321. package/dist/{lab → study}/keys.d.ts +2 -2
  322. package/dist/{lab → study}/keys.js +10 -10
  323. package/dist/study/migrate.d.ts +8 -3
  324. package/dist/study/migrate.js +60 -4
  325. package/dist/{lab → study}/parse/actors.d.ts +5 -5
  326. package/dist/{lab → study}/parse/actors.js +5 -5
  327. package/dist/study/parse/comms.d.ts +12 -0
  328. package/dist/study/parse/execution.d.ts +19 -0
  329. package/dist/{lab → study}/parse/study-v3.d.ts +3 -5
  330. package/dist/{lab → study}/parse/study-v3.js +3 -3
  331. package/dist/{lab → study}/parse/subject-state.d.ts +8 -8
  332. package/dist/{lab → study}/parse/subject-state.js +4 -4
  333. package/dist/{lab → study}/parse/subject.d.ts +3 -3
  334. package/dist/{lab → study}/parse/subject.js +8 -8
  335. package/dist/{lab → study}/parse/values.d.ts +2 -2
  336. package/dist/{lab → study}/persona-resolve.d.ts +4 -4
  337. package/dist/{lab → study}/persona-resolve.js +2 -2
  338. package/dist/{lab → study}/plan-base.d.ts +7 -7
  339. package/dist/{lab → study}/plan-base.js +1 -1
  340. package/dist/{lab → study}/plan-participants.d.ts +10 -10
  341. package/dist/{lab → study}/plan-participants.js +4 -4
  342. package/dist/{lab → study}/plan-types.d.ts +28 -28
  343. package/dist/{lab → study}/plan-types.js +2 -2
  344. package/dist/study/plan.d.ts +13 -0
  345. package/dist/{lab → study}/plan.js +20 -20
  346. package/dist/study/preflight-probes.d.ts +3 -0
  347. package/dist/{lab → study}/preflight-probes.js +9 -8
  348. package/dist/study/preflight-result.d.ts +8 -0
  349. package/dist/{lab → study}/preflight-result.js +3 -3
  350. package/dist/{lab → study}/preflight.d.ts +31 -31
  351. package/dist/{lab → study}/preflight.js +8 -8
  352. package/dist/{lab → study}/requirements.d.ts +3 -3
  353. package/dist/{lab → study}/requirements.js +1 -1
  354. package/dist/study/route-inputs.d.ts +28 -0
  355. package/dist/{lab → study}/route-inputs.js +1 -1
  356. package/dist/{lab → study}/routing.d.ts +12 -12
  357. package/dist/{lab/run-lab-events.d.ts → study/run-study-events.d.ts} +10 -10
  358. package/dist/{lab/run-lab-events.js → study/run-study-events.js} +4 -4
  359. package/dist/{lab/run-lab-homes.d.ts → study/run-study-homes.d.ts} +8 -17
  360. package/dist/study/run-study-homes.js +3 -0
  361. package/dist/study/run-study-options.d.ts +28 -0
  362. package/dist/{lab/run-lab-options.js → study/run-study-options.js} +16 -15
  363. package/dist/{lab/lab-deps.d.ts → study/study-deps.d.ts} +2 -2
  364. package/dist/{lab/lab-deps.js → study/study-deps.js} +2 -2
  365. package/dist/{lab → study}/summary.d.ts +10 -10
  366. package/dist/{lab → study}/summary.js +15 -15
  367. package/dist/{lab → study}/tasks.d.ts +3 -3
  368. package/dist/{lab → study}/tasks.js +1 -1
  369. package/dist/{lab → study}/types.d.ts +104 -104
  370. package/dist/{lab → study}/types.js +1 -1
  371. package/dist/{lab → study}/validation.d.ts +19 -19
  372. package/dist/{lab → study}/validation.js +13 -13
  373. package/dist/{lab → study}/warnings.d.ts +4 -4
  374. package/dist/{lab → study}/warnings.js +1 -1
  375. package/dist/subject/clone.d.ts +6 -6
  376. package/dist/subject/clone.js +2 -2
  377. package/dist/subject/local-tree-archive.d.ts +2 -2
  378. package/dist/subject/local-tree-archive.js +3 -3
  379. package/dist/subject/local-tree.d.ts +3 -3
  380. package/dist/subject/runtime.js +2 -2
  381. package/dist/subject/serve.d.ts +4 -4
  382. package/dist/subject/state.d.ts +3 -3
  383. package/dist/subject/state.js +1 -1
  384. package/dist/subject/steps.d.ts +1 -1
  385. package/dist/subject/steps.js +1 -1
  386. package/dist/substrates/desktop-session.js +2 -2
  387. package/dist/substrates/detached.d.ts +1 -1
  388. package/dist/substrates/e2b/desktop-browser.d.ts +4 -4
  389. package/dist/substrates/e2b/desktop-browser.js +1 -1
  390. package/dist/substrates/e2b/desktop-cdp.d.ts +1 -1
  391. package/dist/substrates/e2b/desktop-cdp.js +1 -1
  392. package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
  393. package/dist/substrates/e2b/desktop-executor.js +12 -12
  394. package/dist/substrates/e2b/desktop-geometry.d.ts +1 -1
  395. package/dist/substrates/e2b/desktop-geometry.js +1 -1
  396. package/dist/substrates/e2b/desktop-media.d.ts +3 -3
  397. package/dist/substrates/e2b/lifetime.js +1 -1
  398. package/dist/substrates/e2b/sandbox.d.ts +3 -3
  399. package/dist/substrates/e2b/sandbox.js +1 -1
  400. package/dist/substrates/e2b/sdk.d.ts +1 -1
  401. package/dist/substrates/e2b/sdk.js +1 -1
  402. package/dist/substrates/local/runtime-config.d.ts +4 -4
  403. package/dist/substrates/local/runtime-config.js +4 -4
  404. package/dist/tui/contract.d.ts +8 -8
  405. package/dist/tui/contract.js +2 -2
  406. package/dist/tui/launch.d.ts +3 -3
  407. package/dist/tui/launch.js +22 -16
  408. package/dist/tui-app.js +139 -139
  409. package/dist/verify/subject.d.ts +1 -1
  410. package/dist/verify/subject.js +1 -1
  411. package/dist/verify/verify.js +2 -1
  412. package/docs/architecture/actor-contract.md +5 -5
  413. package/docs/architecture/browser-control.md +1 -1
  414. package/docs/architecture/external-public-shared-world.md +8 -7
  415. package/docs/architecture/github-feedback-loop.md +1 -1
  416. package/docs/architecture/task-protocol-support.md +1 -1
  417. package/docs/architecture/terminal-product-route.md +18 -18
  418. package/docs/contracts/adapter-fixtures.md +2 -2
  419. package/docs/contracts/errors.md +8 -8
  420. package/docs/contracts/run-bundle.md +6 -4
  421. package/docs/contracts/schemas.md +61 -42
  422. package/docs/contracts/study-analysis.md +4 -1
  423. package/docs/contracts/study-costs.md +17 -2
  424. package/examples/README.md +1 -1
  425. package/examples/scorer/scorer.mjs +3 -3
  426. package/package.json +2 -1
  427. package/skills/humanish/SKILL.md +8 -6
  428. package/skills/humanish/agents/openai.yaml +1 -1
  429. package/dist/cli/commands/lab-format.d.ts +0 -9
  430. package/dist/cli/commands/lab-route-run.d.ts +0 -19
  431. package/dist/cli/commands/lab-route-scripted.d.ts +0 -17
  432. package/dist/cli/commands/lab-route-terminal.d.ts +0 -17
  433. package/dist/cli/commands/lab-run.d.ts +0 -9
  434. package/dist/lab/composition-rules.d.ts +0 -7
  435. package/dist/lab/config.d.ts +0 -7
  436. package/dist/lab/deprecated-fields.d.ts +0 -10
  437. package/dist/lab/deprecated-fields.js +0 -24
  438. package/dist/lab/parse/comms.d.ts +0 -12
  439. package/dist/lab/parse/execution.d.ts +0 -19
  440. package/dist/lab/plan.d.ts +0 -13
  441. package/dist/lab/preflight-probes.d.ts +0 -3
  442. package/dist/lab/preflight-result.d.ts +0 -8
  443. package/dist/lab/route-inputs.d.ts +0 -28
  444. package/dist/lab/run-lab-homes.js +0 -7
  445. package/dist/lab/run-lab-options.d.ts +0 -28
  446. package/dist/library-aliases.d.ts +0 -56
  447. package/dist/library-aliases.js +0 -22
  448. package/dist/run-lab.d.ts +0 -112
  449. /package/dist/{lab → study}/device-presets.js +0 -0
  450. /package/dist/{lab → study}/init-paths.d.ts +0 -0
  451. /package/dist/{lab → study}/init-paths.js +0 -0
  452. /package/dist/{lab → study}/init-plan.d.ts +0 -0
  453. /package/dist/{lab → study}/init-plan.js +0 -0
  454. /package/dist/{lab → study}/parse/comms.js +0 -0
  455. /package/dist/{lab → study}/parse/execution.js +0 -0
  456. /package/dist/{lab → study}/parse/values.js +0 -0
  457. /package/dist/{lab → study}/participant-assignment.d.ts +0 -0
  458. /package/dist/{lab → study}/participant-assignment.js +0 -0
  459. /package/dist/{lab → study}/persona.d.ts +0 -0
  460. /package/dist/{lab → study}/persona.js +0 -0
  461. /package/dist/{lab → study}/routing.js +0 -0
@@ -1,8 +1,9 @@
1
+ import { DEFAULT_ANALYSIS_MAX_COST_USD } from "../analysis/automatic-config.js";
1
2
  export const DEFAULT_LOCAL_BROWSER_STARTER = {
2
3
  appUrl: "http://127.0.0.1:3000",
3
4
  mission: "Use the app's primary flow. Explain anything confusing and stop when the task is complete or you are stuck.",
4
5
  };
5
- function localBrowserLab(starter = DEFAULT_LOCAL_BROWSER_STARTER) {
6
+ function localBrowserStudy(starter = DEFAULT_LOCAL_BROWSER_STARTER) {
6
7
  return {
7
8
  path: "humanish/studies/local-browser.yaml",
8
9
  plane: "source",
@@ -34,19 +35,23 @@ defaults:
34
35
  };
35
36
  }
36
37
  /**
37
- * The flagship live lab. A ChatGPT-account Codex participant has no API-dollar price, so preflight
38
+ * The flagship live study. A ChatGPT-account Codex participant has no API-dollar price, so preflight
38
39
  * refuses a dollar cap on it (HUMANISH_COMPUTER_USE_UNPRICED_CAP); that variant is bounded by the
39
40
  * session timeout instead of a cap it could never enforce.
40
41
  */
41
- function tryLiveLab(actor, localAgent = "codex") {
42
+ function tryLiveStudy(actor, localAgent = "codex") {
42
43
  const account = actor === "local-agent";
43
44
  const needs = account
44
45
  ? ` Needs E2B_API_KEY and the coding agent signed in on this machine. Cost: one small task, a few
45
46
  E2B desktop minutes and the agent's account usage. humanish cannot put a dollar cap on account
46
- usage, so the ten-minute session limit below bounds the run.`
47
+ usage, so the ten-minute session limit below bounds the run. When OPENAI_API_KEY is set, the
48
+ analysis after the run bills it: humanish refuses that request before it starts if its estimate
49
+ is over $${DEFAULT_ANALYSIS_MAX_COST_USD}. Set review.analysis: false to skip it.`
47
50
  : ` Needs E2B_API_KEY and OPENAI_API_KEY. Cost: one small task with a $2 cap on estimated model
48
51
  spend. The run stops before its next model request once the estimate passes $2, so the last
49
- request can go slightly over, and hosted desktop time is billed separately.`;
52
+ request can go slightly over, and hosted desktop time is billed separately. The analysis after
53
+ the run bills the same key outside that cap: humanish refuses it before it starts if its
54
+ estimate is over $${DEFAULT_ANALYSIS_MAX_COST_USD}. Set review.analysis: false to skip it.`;
50
55
  const participant = account
51
56
  ? `# Your machine has a coding agent signed in, so this study uses it: no provider API key, only
52
57
  # E2B. To use a provider key instead, swap to \`type: openai-computer-use\` and add caps.maxUsd.
@@ -229,8 +234,8 @@ defaults:
229
234
  open: true
230
235
  `,
231
236
  },
232
- tryLiveLab("openai-computer-use"),
233
- localBrowserLab(),
237
+ tryLiveStudy("openai-computer-use"),
238
+ localBrowserStudy(),
234
239
  {
235
240
  path: "humanish/studies/cua-browser.yaml",
236
241
  plane: "source",
@@ -401,16 +406,16 @@ export const humanishScripts = {
401
406
  "humanish:verify": "humanish verify",
402
407
  };
403
408
  /**
404
- * The starter files, with the live lab written for the brain this machine can use.
409
+ * The starter files, with the live study written for the brain this machine can use.
405
410
  *
406
- * `local-agent` is not a variant of the lab so much as a different participant: on a machine with
411
+ * `local-agent` is not a variant of the study so much as a different participant: on a machine with
407
412
  * a signed-in Codex and no provider key, the study runs with the operator's own agent and needs
408
413
  * only E2B. Writing the other one there would hand someone homework instead of a first run.
409
414
  */
410
415
  export function starterFilesFor(actor, localBrowser = DEFAULT_LOCAL_BROWSER_STARTER, localAgent) {
411
416
  return starterFiles.map((file) => file.path === "humanish/studies/local-browser.yaml"
412
- ? localBrowserLab(localBrowser)
417
+ ? localBrowserStudy(localBrowser)
413
418
  : file.path === "humanish/studies/try-live.yaml"
414
- ? tryLiveLab(actor, localAgent)
419
+ ? tryLiveStudy(actor, localAgent)
415
420
  : file);
416
421
  }
@@ -5,7 +5,7 @@ export interface InitOptions {
5
5
  yes?: boolean;
6
6
  /** Injected so a test can decide what credentials this machine appears to have. */
7
7
  env?: NodeJS.ProcessEnv;
8
- /** Configure the starter local-browser lab without making the operator edit YAML. */
8
+ /** Configure the starter local-browser study without making the operator edit YAML. */
9
9
  localBrowser?: {
10
10
  appUrl: string;
11
11
  mission?: string;
@@ -8,7 +8,7 @@ import { assertPreparedSelectedOutputDirectory, prepareContainedOutputDirectory,
8
8
  import { validateCwd } from "../run/project.js";
9
9
  import { pathExists, readTextIfExists, validateInitProjectPaths } from "./init-paths.js";
10
10
  import { planGitignore, planPackageJson } from "./init-plan.js";
11
- import { otherStudyFiles, STUDY_DIRECTORIES, studyFileStem } from "../study/files.js";
11
+ import { otherStudyFiles, STUDY_DIRECTORIES, studyFileStem } from "./files.js";
12
12
  const INIT_RESPONSE_SCHEMA = "humanish.init-result.v1";
13
13
  export async function runInit(options) {
14
14
  const requestedCwd = path.resolve(options.cwd);
@@ -38,7 +38,7 @@ export async function runInit(options) {
38
38
  return failed(initialPathCheck);
39
39
  }
40
40
  await planAgentsFile(preparedProjectRoot, cwd, plan);
41
- // The starter live lab is written for the brain this machine can actually use. Shipping it as
41
+ // The starter live study is written for the brain this machine can actually use. Shipping it as
42
42
  // openai-computer-use on a machine with no provider key but a signed-in Codex would hand someone
43
43
  // a file that asks for a credential they were just told they do not need.
44
44
  const machine = await firstRunEnvironment(options.env ?? process.env, requestedCwd);
@@ -149,8 +149,11 @@ async function planStarterFiles(preparedProjectRoot, cwd, files, localBrowserReq
149
149
  target: file.plane,
150
150
  reason: `${others.join(", ")} already uses the name ${stem}`,
151
151
  });
152
+ // humanish no longer reads a labs/ file, but migrate needs its name free to move it.
152
153
  const legacy = others.some((other) => other.split(path.sep).includes("labs"));
153
- plan.warnings.push(`Skipped ${file.path}: ${others.join(", ")} already uses the name ${stem}, and a second file with that name would make \`run ${stem}\` fail.${legacy ? " Run humanish migrate to move it to a studies/ directory." : ""}`);
154
+ plan.warnings.push(legacy
155
+ ? `Skipped ${file.path}: ${others.join(", ")} already uses the name ${stem}. Move it to a studies/ directory; humanish migrate converts and moves a v2 file.`
156
+ : `Skipped ${file.path}: ${others.join(", ")} already uses the name ${stem}, and a second file with that name would make \`run ${stem}\` fail.`);
154
157
  }
155
158
  else if (existing === null) {
156
159
  plan.changes.push({
@@ -268,7 +271,7 @@ function validateLocalBrowserStarter(input) {
268
271
  return { ok: true, value };
269
272
  }
270
273
  /**
271
- * What this machine can run, for the starter lab and the next steps. Local CLI status is
274
+ * What this machine can run, for the starter study and the next steps. Local CLI status is
272
275
  * classified without returning its output or reading its credential file. Provider keys go
273
276
  * through the same discovery chain as every other command (process env, the project overlay,
274
277
  * `e2b auth login`, the `humanish keys set` store) and only their presence is read, never a value.
@@ -1,4 +1,4 @@
1
- /** The first key in `raw` that LAB_KEYS does not list, as an error message; undefined if none. */
2
- export declare function findUnknownLabKey(raw: unknown): string | undefined;
1
+ /** The first key in `raw` that V2_KEYS does not list, as an error message; undefined if none. */
2
+ export declare function findUnknownV2Key(raw: unknown): string | undefined;
3
3
  /** The first key in a humanish.study.v3 document that the format does not have; undefined if none. */
4
4
  export declare function findUnknownStudyKey(raw: unknown): string | undefined;
@@ -1,4 +1,4 @@
1
- // Every mapping key parseLabConfig reads, by path. A key that is not listed fails the lab as
1
+ // Every mapping key parseStudy reads, by path. A key that is not listed fails the study as
2
2
  // unknown, so a typo stops the run instead of being dropped. `true` marks a leaf: its parser
3
3
  // checks the value (scalars, lists, and mappings that check their own keys). Each level satisfies
4
4
  // the parsed type's keys, so a field added to a Lab* interface must be added here too.
@@ -166,7 +166,7 @@ const EMAIL = {
166
166
  allowedOrigins: true,
167
167
  recipients: { lane: true, address: true },
168
168
  };
169
- const LAB_KEYS = {
169
+ const V2_KEYS = {
170
170
  schema: true,
171
171
  id: true,
172
172
  title: true,
@@ -225,14 +225,14 @@ const STUDY_KEYS = {
225
225
  caps: CAPS,
226
226
  execution: without(EXECUTION, "caps"),
227
227
  scenario: true,
228
- policies: LAB_KEYS.policies,
229
- review: LAB_KEYS.review,
230
- defaults: LAB_KEYS.defaults,
231
- comms: LAB_KEYS.comms,
228
+ policies: V2_KEYS.policies,
229
+ review: V2_KEYS.review,
230
+ defaults: V2_KEYS.defaults,
231
+ comms: V2_KEYS.comms,
232
232
  };
233
- /** The first key in `raw` that LAB_KEYS does not list, as an error message; undefined if none. */
234
- export function findUnknownLabKey(raw) {
235
- return walk(raw, LAB_KEYS, "", "lab");
233
+ /** The first key in `raw` that V2_KEYS does not list, as an error message; undefined if none. */
234
+ export function findUnknownV2Key(raw) {
235
+ return walk(raw, V2_KEYS, "", "study");
236
236
  }
237
237
  /** The first key in a humanish.study.v3 document that the format does not have; undefined if none. */
238
238
  export function findUnknownStudyKey(raw) {
@@ -270,7 +270,7 @@ function unknownKeysMessage(path, unknown, known, noun) {
270
270
  const suggestion = closest(key, known);
271
271
  return suggestion ? `${key} (did you mean \`${suggestion}\`?)` : key;
272
272
  });
273
- return `Unknown ${noun} field(s)${path ? ` in \`${path}\`` : ""}: ${named.join(", ")}. Known fields: ${known.join(", ")}.`;
273
+ return `Unknown ${noun} ${unknown.length === 1 ? "field" : "fields"}${path ? ` in \`${path}\`` : ""}: ${named.join(", ")}. Known fields: ${known.join(", ")}.`;
274
274
  }
275
275
  // The known key within edit distance 2, or one that differs only in case.
276
276
  function closest(key, known) {
@@ -1,4 +1,4 @@
1
- import type { StudyRoute } from "../lab/parse/study-v3.js";
1
+ import type { StudyRoute } from "./routing.js";
2
2
  import { type DroppedKey, type MovedKey } from "./convert.js";
3
3
  /** The schema of `humanish migrate --json`. */
4
4
  declare const MIGRATE_SCHEMA = "humanish.migrate-result.v1";
@@ -21,6 +21,8 @@ export interface MigrateResult {
21
21
  readonly files: readonly MigrateFile[];
22
22
  /** Files left behind after a clean-up step found them changed: sources, backups or temp files. */
23
23
  readonly unresolved?: readonly string[];
24
+ /** The labs/ directories the moves emptied and migrate removed, or with `--dry-run` would remove. */
25
+ readonly removedDirectories?: readonly string[];
24
26
  readonly error?: {
25
27
  readonly code: "HUMANISH_MIGRATE_REFUSED" | "HUMANISH_MIGRATE_FAILED";
26
28
  readonly phase: "plan" | "stage" | "commit" | "clean-up";
@@ -34,8 +36,11 @@ export interface MigrateOptions {
34
36
  /** Files to convert. Without any, the six study directories are scanned. */
35
37
  readonly paths?: readonly string[];
36
38
  readonly dryRun?: boolean;
37
- /** Called with the plan before anything is written, so a caller can print every destination. */
38
- readonly onPlan?: (files: readonly MigrateFile[]) => void;
39
+ /**
40
+ * Called with the plan before anything is written, so a caller can print every destination and
41
+ * each labs/ directory the moves empty, which migrate then removes.
42
+ */
43
+ readonly onPlan?: (files: readonly MigrateFile[], emptied: readonly string[]) => void;
39
44
  /** Replaces `fs.link`. Tests use it to stand in for a filesystem without hard links. */
40
45
  readonly link?: (from: string, to: string) => Promise<void>;
41
46
  /** Called between stage and commit, and between commit and clean-up. Tests change files there. */
@@ -8,6 +8,8 @@
8
8
  // name, so no file this run did not write is ever overwritten. A failure undoes the commits.
9
9
  // 4. Clean up: delete each moved source and each rewrite's original, once checked (owned-files.ts).
10
10
  // A file that changed since the plan is kept and listed; a rewrite's original as <name>.v2.bak.
11
+ // Then a labs/ directory whose every entry moved is removed with a plain rmdir, which fails, and
12
+ // keeps the directory, when anything else is in it by then.
11
13
  import { randomUUID } from "node:crypto";
12
14
  import { link, lstat, readdir, readFile, realpath, rename, rmdir } from "node:fs/promises";
13
15
  import path from "node:path";
@@ -317,6 +319,46 @@ async function undoCommits(root, writes, linkFile) {
317
319
  }
318
320
  return unrestored;
319
321
  }
322
+ // Each labs/ directory whose every entry, a dotfile or a subdirectory included, is a file this run
323
+ // moves out. Only these are removed after the move.
324
+ async function emptiedRetiredDirectories(root, writes) {
325
+ const moving = new Map();
326
+ for (const write of writes) {
327
+ if (write.file.action !== "move")
328
+ continue;
329
+ const directory = path.dirname(write.sourcePath);
330
+ const relative = path.relative(root, directory);
331
+ const retired = STUDY_DIRECTORIES.some((entry) => entry.family === "labs" && entry.relativeDir === relative);
332
+ if (!retired)
333
+ continue;
334
+ const entry = moving.get(directory) ?? { write, names: new Set() };
335
+ entry.names.add(path.basename(write.sourcePath));
336
+ moving.set(directory, entry);
337
+ }
338
+ const emptied = [];
339
+ for (const [directory, { write, names }] of moving) {
340
+ const entries = await readdir(directory).catch(() => undefined);
341
+ if (entries !== undefined && entries.every((name) => names.has(name)))
342
+ emptied.push(write);
343
+ }
344
+ return emptied;
345
+ }
346
+ // Remove each emptied labs/ directory, if it is still the one the plan read. rmdir is not
347
+ // recursive, so a file that appeared in it since the plan keeps it. Returns the removed paths.
348
+ async function removeEmptiedDirectories(root, emptied) {
349
+ const removed = [];
350
+ for (const write of emptied) {
351
+ try {
352
+ await assertDirectory(write.sourceDirectory, root);
353
+ await rmdir(path.dirname(write.sourcePath));
354
+ removed.push(path.relative(root, path.dirname(write.sourcePath)));
355
+ }
356
+ catch {
357
+ // Not empty, or not the directory the plan read: it stays.
358
+ }
359
+ }
360
+ return removed;
361
+ }
320
362
  // Delete each moved source and each rewrite's original, but only once the v3 file is in place as
321
363
  // written, and only if the old file is still the one the plan read (removeChecked). Anything kept
322
364
  // is listed; a rewrite's original is kept as <name>.v2.bak.
@@ -356,9 +398,17 @@ export async function migrateStudies(options) {
356
398
  const linkFile = options.link ?? link;
357
399
  try {
358
400
  ({ files, writes } = await planWrites(root, options));
359
- options.onPlan?.(files);
360
- if (options.dryRun === true || writes.length === 0)
361
- return { ...base, ok: true, files };
401
+ const emptied = await emptiedRetiredDirectories(root, writes);
402
+ const emptiedPaths = emptied.map((write) => path.relative(root, path.dirname(write.sourcePath)));
403
+ options.onPlan?.(files, emptiedPaths);
404
+ if (options.dryRun === true || writes.length === 0) {
405
+ return {
406
+ ...base,
407
+ ok: true,
408
+ files,
409
+ ...(emptiedPaths.length === 0 ? {} : { removedDirectories: emptiedPaths }),
410
+ };
411
+ }
362
412
  try {
363
413
  await stage(root, writes, created);
364
414
  options.onPhase?.("stage");
@@ -386,7 +436,13 @@ export async function migrateStudies(options) {
386
436
  },
387
437
  };
388
438
  }
389
- return { ...base, ok: true, files };
439
+ const removed = await removeEmptiedDirectories(root, emptied);
440
+ return {
441
+ ...base,
442
+ ok: true,
443
+ files,
444
+ ...(removed.length === 0 ? {} : { removedDirectories: removed }),
445
+ };
390
446
  }
391
447
  catch (error) {
392
448
  const failure = error instanceof MigrateError
@@ -1,14 +1,14 @@
1
- import type { LabActor, LabParticipantEntry, LabParticipantFocus, LabConfigParseFailure } from "../types.js";
1
+ import type { StudyActor, StudyParticipantEntry, StudyParticipantFocus, StudyParseFailure } from "../types.js";
2
2
  export declare const PARTICIPANT_ID_PATTERN: RegExp;
3
3
  export declare const PARTICIPANT_ID_MAX_CHARS = 40;
4
4
  /** The participant entries an actor declares, after roster groups expand into them. The manifest
5
5
  * spells them `actors[].lanes`. Undefined when the actor declares none. */
6
- export declare function rosterOf<Entry = LabParticipantEntry>(actor: {
6
+ export declare function rosterOf<Entry = StudyParticipantEntry>(actor: {
7
7
  readonly lanes?: readonly Entry[];
8
8
  } | undefined): readonly Entry[] | undefined;
9
9
  /** An actor's per-participant focus on the app-url route. The manifest spells it `laneFocus`. */
10
- export declare function focusOf(actor: Pick<LabActor, "laneFocus"> | undefined): LabParticipantFocus | undefined;
10
+ export declare function focusOf(actor: Pick<StudyActor, "laneFocus"> | undefined): StudyParticipantFocus | undefined;
11
11
  export declare function parseActors(raw: unknown): {
12
12
  ok: true;
13
- value: LabActor[];
14
- } | LabConfigParseFailure;
13
+ value: StudyActor[];
14
+ } | StudyParseFailure;
@@ -6,7 +6,7 @@ import { registeredComputerUseActors, registeredScriptedBrowserActors, registere
6
6
  import { invalid, posInt, str } from "./values.js";
7
7
  import { isRecord } from "../../run/type-guards.js";
8
8
  // A participant id interpolates into its evidence paths (screenshots/<id>/, actors/<id>.json), so
9
- // it must be a public-safe path token, same shape as a lab id.
9
+ // it must be a public-safe path token, same shape as a study id.
10
10
  export const PARTICIPANT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
11
11
  export const PARTICIPANT_ID_MAX_CHARS = 40;
12
12
  const METADATA_MAX_CHARS = 80;
@@ -19,7 +19,7 @@ export function rosterOf(actor) {
19
19
  export function focusOf(actor) {
20
20
  return actor?.laneFocus;
21
21
  }
22
- // Actor ids humanish no longer registers. Rejecting them at parse keeps a lab that names one
22
+ // Actor ids humanish no longer registers. Rejecting them at parse keeps a study that names one
23
23
  // from running on a route that ignores actors[0].type, such as a this-repo dry run.
24
24
  const REMOVED_ACTOR_TYPES = new Set(["pi-agent-core", "claude-agent-sdk"]);
25
25
  // Only actors of a run kind a route dispatches. codex-app-server is registered but declares only
@@ -33,7 +33,7 @@ function routableActorTypes() {
33
33
  }
34
34
  export function parseActors(raw) {
35
35
  if (!Array.isArray(raw) || raw.length === 0) {
36
- return invalid("Lab `actors` must be a non-empty array.");
36
+ return invalid("`actors` must be a non-empty array.");
37
37
  }
38
38
  // Multi-actor fan-out is not wired yet (only actors[0] is consumed). Fail closed rather than
39
39
  // silently ignore actors[1..]; multi-actor support lands in a later slice.
@@ -50,7 +50,7 @@ export function parseActors(raw) {
50
50
  return invalid(`actors[${index}].type is required.`);
51
51
  }
52
52
  if (REMOVED_ACTOR_TYPES.has(type)) {
53
- return invalid(`actors[${index}].type "${type}" is no longer a humanish actor. Use an actor a lab route runs (one of: ${routableActorTypes().join(", ")}). To drive a study with a signed-in Claude Code, use type: local-agent with localAgent: claude.`);
53
+ return invalid(`actors[${index}].type "${type}" is no longer a humanish actor. Use an actor a study route runs (one of: ${routableActorTypes().join(", ")}). To drive a study with a signed-in Claude Code, use type: local-agent with localAgent: claude.`);
54
54
  }
55
55
  const actor = { type };
56
56
  const count = posInt(entry.count);
@@ -189,7 +189,7 @@ function parseRosterGroups(raw, actorIndex) {
189
189
  * Participant ids (when declared) must be public-safe path tokens and unique; grouping metadata
190
190
  * must be public-safe tokens; a device must be a known preset name. The
191
191
  * route-scoped cross-validation (`lanes` XOR `count`/`laneFocus`, device XOR raw resolution, cap 16)
192
- * runs in parseLabConfig where the route is known.
192
+ * runs in parseStudy where the route is known.
193
193
  */
194
194
  function parseParticipantEntries(raw, actorIndex) {
195
195
  if (raw === undefined) {
@@ -0,0 +1,12 @@
1
+ import type { StudyComms, StudyCommsEmail, StudyCommsRecipient, StudyParseFailure } from "../types.js";
2
+ export declare function parseComms(raw: unknown): {
3
+ ok: true;
4
+ value: StudyComms | undefined;
5
+ } | StudyParseFailure;
6
+ /** The participant a declared inbox recipient belongs to. The manifest spells it `lane`. */
7
+ export declare function recipientParticipantId(recipient: StudyCommsRecipient): string;
8
+ /** The declared recipients that name an address, in declaration order, by participant id. */
9
+ export declare function addressedRecipients(email: Pick<StudyCommsEmail, "recipients">): {
10
+ participantId: string;
11
+ address: string;
12
+ }[];
@@ -0,0 +1,19 @@
1
+ import type { StudyParseFailure, StudyDefaults, StudyExecution, StudyPolicies, StudyReview, StudyScenario } from "../types.js";
2
+ export declare function parseExecution(raw: unknown): {
3
+ ok: true;
4
+ value: StudyExecution | undefined;
5
+ } | StudyParseFailure;
6
+ export declare function parsePersonas(raw: unknown): Record<string, unknown>[] | undefined;
7
+ export declare function parseScenario(raw: unknown): {
8
+ ok: true;
9
+ value: StudyScenario | undefined;
10
+ } | StudyParseFailure;
11
+ export declare function parsePolicies(raw: unknown): {
12
+ ok: true;
13
+ value: StudyPolicies | undefined;
14
+ } | StudyParseFailure;
15
+ export declare function parseReview(raw: unknown): {
16
+ ok: true;
17
+ value: StudyReview | undefined;
18
+ } | StudyParseFailure;
19
+ export declare function parseDefaults(raw: unknown): StudyDefaults | undefined;
@@ -1,7 +1,5 @@
1
- import { type LabConfigParseFailure } from "../types.js";
2
- declare const ROUTES: readonly ["preview", "computer-use", "shared-world", "terminal", "scripted"];
3
- /** A route a study declares. */
4
- export type StudyRoute = (typeof ROUTES)[number];
1
+ import type { StudyRoute } from "../routing.js";
2
+ import { type StudyParseFailure } from "../types.js";
5
3
  export interface StudyDocument {
6
4
  readonly route: StudyRoute;
7
5
  /** The same document in the humanish.lab.v2 spelling. */
@@ -12,7 +10,7 @@ export interface StudyDocument {
12
10
  type Parsed<T> = {
13
11
  ok: true;
14
12
  value: T;
15
- } | LabConfigParseFailure;
13
+ } | StudyParseFailure;
16
14
  /** Rewrite a humanish.study.v3 document into humanish.lab.v2, or refuse it. */
17
15
  export declare function studyToV2(raw: Record<string, unknown>): Parsed<StudyDocument>;
18
16
  /**
@@ -1,10 +1,10 @@
1
1
  // humanish.study.v3, the study format. A study declares its route, one `actor`, its `participants`
2
2
  // and one `caps` block. studyToV2 rewrites a v3 document into the v2 spelling, so both formats run
3
- // through one parser and parse into the same LabConfig. parseLabConfig then checks the declared
3
+ // through one parser and parse into the same StudyConfig. parseStudy then checks the declared
4
4
  // route against the one the config takes, and refuses any field that route does not read.
5
5
  import { isRecord } from "../../run/type-guards.js";
6
6
  import { findUnknownStudyKey } from "../keys.js";
7
- import { LAB_CONFIG_SCHEMA } from "../types.js";
7
+ import { V2_SCHEMA } from "../types.js";
8
8
  import { PARTICIPANT_ID_MAX_CHARS, PARTICIPANT_ID_PATTERN } from "./actors.js";
9
9
  import { invalid, posInt } from "./values.js";
10
10
  // The values `route:` takes: every route routeOf can return.
@@ -81,7 +81,7 @@ export function studyToV2(raw) {
81
81
  ? withKey(raw.execution, "caps", caps)
82
82
  : raw.execution;
83
83
  const subject = route === "shared-world" ? withKey(raw.subject, "topology", "shared-world") : raw.subject;
84
- const v2 = { schema: LAB_CONFIG_SCHEMA };
84
+ const v2 = { schema: V2_SCHEMA };
85
85
  const fields = [
86
86
  ["id", raw.id],
87
87
  ["title", raw.title],
@@ -1,4 +1,4 @@
1
- import type { LabConfigParseFailure, LabSubjectState } from "../types.js";
1
+ import type { StudyParseFailure, StudySubjectState } from "../types.js";
2
2
  /**
3
3
  * Literal non-secret subject env. Real apps need configuration before they will boot: a public base
4
4
  * URL, a transport selector, a feature flag, and none of that is secret. Routing it through
@@ -10,21 +10,21 @@ import type { LabConfigParseFailure, LabSubjectState } from "../types.js";
10
10
  export declare function parseEnvValues(raw: unknown): {
11
11
  ok: true;
12
12
  value?: Record<string, string>;
13
- } | LabConfigParseFailure;
13
+ } | StudyParseFailure;
14
14
  /**
15
- * Structural parse of `subject.state` into a candidate LabSubjectState. Deliberately keeps
15
+ * Structural parse of `subject.state` into a candidate StudySubjectState. Deliberately keeps
16
16
  * unrecognized `when`/`timeoutMs` values in the candidate (instead of silently dropping
17
17
  * them) so subjectStateInvalidReason rejects them: a state declaration that silently does
18
18
  * less than it says would claim more than its mechanism does.
19
19
  */
20
20
  export declare function parseState(raw: unknown): {
21
21
  ok: true;
22
- value: LabSubjectState | undefined;
23
- } | LabConfigParseFailure;
22
+ value: StudySubjectState | undefined;
23
+ } | StudyParseFailure;
24
24
  /**
25
- * Semantic validation for `subject.state`, shared by parseLabConfig and the engine
26
- * (the route re-enforces it on configs that arrive through runLab). Returns
25
+ * Semantic validation for `subject.state`, shared by parseStudy and the engine
26
+ * (the route re-enforces it on configs that arrive through runStudyWith). Returns
27
27
  * the failure message, or null when the declaration is valid. Reads the candidate
28
28
  * defensively: library callers can hand the engine arbitrarily-shaped objects.
29
29
  */
30
- export declare function subjectStateInvalidReason(state: LabSubjectState, env: readonly string[] | undefined): string | null;
30
+ export declare function subjectStateInvalidReason(state: StudySubjectState, env: readonly string[] | undefined): string | null;
@@ -1,6 +1,6 @@
1
1
  // The state and env channels of a served subject (clone or local-tree): `subject.envValues`,
2
2
  // the structural parse of `subject.state`, and subjectStateInvalidReason, the semantic check
3
- // parseLabConfig and the computer-use route share.
3
+ // parseStudy and the computer-use route share.
4
4
  import { containsSensitive } from "../../evidence/redaction.js";
5
5
  import { ENV_NAME_PATTERN, invalid, posInt, str, strList } from "./values.js";
6
6
  import { isRecord } from "../../run/type-guards.js";
@@ -39,7 +39,7 @@ export function parseEnvValues(raw) {
39
39
  return { ok: true, value: envValues };
40
40
  }
41
41
  /**
42
- * Structural parse of `subject.state` into a candidate LabSubjectState. Deliberately keeps
42
+ * Structural parse of `subject.state` into a candidate StudySubjectState. Deliberately keeps
43
43
  * unrecognized `when`/`timeoutMs` values in the candidate (instead of silently dropping
44
44
  * them) so subjectStateInvalidReason rejects them: a state declaration that silently does
45
45
  * less than it says would claim more than its mechanism does.
@@ -96,8 +96,8 @@ const STATE_STEP_WHENS = [
96
96
  "after-ready",
97
97
  ];
98
98
  /**
99
- * Semantic validation for `subject.state`, shared by parseLabConfig and the engine
100
- * (the route re-enforces it on configs that arrive through runLab). Returns
99
+ * Semantic validation for `subject.state`, shared by parseStudy and the engine
100
+ * (the route re-enforces it on configs that arrive through runStudyWith). Returns
101
101
  * the failure message, or null when the declaration is valid. Reads the candidate
102
102
  * defensively: library callers can hand the engine arbitrarily-shaped objects.
103
103
  */
@@ -1,8 +1,8 @@
1
- import type { LabConfigParseFailure, LabSubject } from "../types.js";
1
+ import type { StudyParseFailure, StudySubject } from "../types.js";
2
2
  export declare function parseSubject(raw: unknown): {
3
3
  ok: true;
4
- value: LabSubject;
5
- } | LabConfigParseFailure;
4
+ value: StudySubject;
5
+ } | StudyParseFailure;
6
6
  export declare const PUBLIC_TARGET_OWNER_PATTERN: RegExp;
7
7
  export declare function isLoopbackUrl(value: string): boolean;
8
8
  /** A well-formed http(s) URL (any host). Shape gate before the loopback/public-target policy. */
@@ -4,7 +4,7 @@ import { parseEnvValues, parseState, subjectStateInvalidReason } from "./subject
4
4
  import { isRecord } from "../../run/type-guards.js";
5
5
  export function parseSubject(raw) {
6
6
  if (!isRecord(raw)) {
7
- return invalid("Lab `subject` is required and must be an object.");
7
+ return invalid("`subject` is required and must be an object.");
8
8
  }
9
9
  const source = str(raw.source);
10
10
  if (source !== "this-repo" &&
@@ -71,19 +71,19 @@ function misplacedFieldFailure(source, raw) {
71
71
  // tree): both routes serve a subject in-sandbox with the same install/build/start/url +
72
72
  // env-name + seed/external/checkpoint shapes.
73
73
  if (source !== "clone" && source !== "local-tree" && raw.serve !== undefined) {
74
- return invalid("`subject.serve` applies only to clone subjects or local-tree subjects (the lab serves the cloned/packed app in-sandbox).");
74
+ return invalid("`subject.serve` applies only to clone subjects or local-tree subjects (humanish serves the cloned or packed app in the sandbox).");
75
75
  }
76
76
  if (source !== "clone" && source !== "local-tree" && raw.env !== undefined) {
77
77
  return invalid("`subject.env` applies only to clone subjects or local-tree subjects (the served app's environment channel).");
78
78
  }
79
79
  if (source !== "clone" && source !== "local-tree" && raw.state !== undefined) {
80
- return invalid("`subject.state` applies only to clone subjects or local-tree subjects (the lab seeds the state it serves).");
80
+ return invalid("`subject.state` applies only to clone subjects or local-tree subjects (humanish seeds the state it serves).");
81
81
  }
82
82
  // repos/clone are clone-only (a fresh-clone subject's git inputs). local-tree packs the
83
83
  // resolution cwd itself, so it has no repo slug to clone and gets its own precise reasons
84
84
  // rather than falling through to the generic clone-only message below.
85
85
  if (source === "local-tree" && raw.repos !== undefined) {
86
- return invalid("`subject.repos` does not apply to local-tree subjects. The local-tree route packs the lab resolution cwd itself; there is no owner/repo slug to clone.");
86
+ return invalid("`subject.repos` does not apply to local-tree subjects. The local-tree route packs the study's working directory itself; there is no owner/repo slug to clone.");
87
87
  }
88
88
  if (source === "local-tree" && raw.clone !== undefined) {
89
89
  return invalid("`subject.clone` does not apply to local-tree subjects. Declare `subject.localTree` instead (keep/exclude/maxArchiveBytes).");
@@ -126,7 +126,7 @@ function parseCloneSubject(raw, subject) {
126
126
  function parseLocalTreeSubject(raw, subject) {
127
127
  // A local-tree subject exists to be packed and served; there is no other way to boot it, so
128
128
  // serve is required here. Clone subjects get the same requirement from each route's checks in
129
- // parseLabConfig.
129
+ // parseStudy.
130
130
  if (raw.serve === undefined) {
131
131
  return invalid("`subject.serve` is required when source is local-tree: a local-tree subject exists to be packed and served, so declare install/build/start/url exactly like the clone route.");
132
132
  }
@@ -175,7 +175,7 @@ function parseServedApp(raw, subject) {
175
175
  return stateResult;
176
176
  }
177
177
  if (stateResult.value) {
178
- // Semantic validation is shared with the engine (runCuaActorLab re-enforces it for
178
+ // Semantic validation is shared with the engine (runCuaActorStudy re-enforces it for
179
179
  // configs that arrive through the library API without the parser).
180
180
  const reason = subjectStateInvalidReason(stateResult.value, subject.env);
181
181
  if (reason) {
@@ -241,7 +241,7 @@ function parsePublicTarget(raw) {
241
241
  return { ok: true, value: { owner, authorized: true } };
242
242
  }
243
243
  // The product name interpolates into evidence labels and the composed prompt; the public-safe
244
- // token shape is the same strict constraint as a lab id.
244
+ // token shape is the same strict constraint as a study id.
245
245
  const PRODUCT_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
246
246
  function parseProduct(raw) {
247
247
  if (!isRecord(raw)) {
@@ -289,7 +289,7 @@ function parseProduct(raw) {
289
289
  },
290
290
  };
291
291
  }
292
- // Public-safe stance: a computer-use actor's entry URL is always an app the lab owner runs on
292
+ // Public-safe stance: a computer-use actor's entry URL is always an app the study owner runs on
293
293
  // loopback (inside the sandbox), never an arbitrary public site. (The constraint binds the
294
294
  // entry point; a navigation watchdog for mid-session escapes is a later slice.) Exported so
295
295
  // the engine re-enforces the same boundary on configs that arrive through the library API.
@@ -1,7 +1,7 @@
1
- import type { LabConfigParseFailure } from "../types.js";
1
+ import type { StudyParseFailure } from "../types.js";
2
2
  export declare const REPO_SLUG_PATTERN: RegExp;
3
3
  export declare const ENV_NAME_PATTERN: RegExp;
4
- export declare function invalid(message: string): LabConfigParseFailure;
4
+ export declare function invalid(message: string): StudyParseFailure;
5
5
  export declare function str(value: unknown): string | undefined;
6
6
  export declare function optionalStr(key: string, value: unknown): Record<string, string>;
7
7
  export declare function strList(value: unknown): string[] | undefined;
@@ -1,6 +1,6 @@
1
1
  import { type ResolvedPersona } from "./persona.js";
2
2
  import { type PreparedSelectedOutputDirectory } from "../run/contained-output.js";
3
- import type { LabActor } from "./types.js";
3
+ import type { StudyActor } from "./types.js";
4
4
  /** Title-case an id for the fallback display name (`skeptical-power-user` -> `Skeptical Power User`). */
5
5
  export declare function personaTitleFromId(personaId: string): string;
6
6
  /**
@@ -22,11 +22,11 @@ export declare function resolveCommittedPersonas(projectRoot: PreparedSelectedOu
22
22
  warnings: string[];
23
23
  }>;
24
24
  /**
25
- * Every persona id a lab config could put on a browser participant: the roster when one is
25
+ * Every persona id a study config could put on a browser participant: the roster when one is
26
26
  * declared, otherwise the actor-level persona that every fan-out participant inherits.
27
27
  */
28
- export declare function labPersonaIds(config: {
29
- actors?: readonly Pick<LabActor, "persona" | "lanes">[];
28
+ export declare function studyPersonaIds(config: {
29
+ actors?: readonly Pick<StudyActor, "persona" | "lanes">[];
30
30
  }): string[];
31
31
  /**
32
32
  * Same resolution from a plain cwd, for the labs that carry a directory string rather than an
@@ -81,10 +81,10 @@ export async function resolveCommittedPersonas(projectRoot, personaIds) {
81
81
  return { personas, warnings };
82
82
  }
83
83
  /**
84
- * Every persona id a lab config could put on a browser participant: the roster when one is
84
+ * Every persona id a study config could put on a browser participant: the roster when one is
85
85
  * declared, otherwise the actor-level persona that every fan-out participant inherits.
86
86
  */
87
- export function labPersonaIds(config) {
87
+ export function studyPersonaIds(config) {
88
88
  const ids = [];
89
89
  for (const actor of config.actors ?? []) {
90
90
  if (actor.persona)