humanish 0.107.0 → 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 (521) hide show
  1. package/ARCHITECTURE.md +22 -17
  2. package/CHANGELOG.md +14 -0
  3. package/CONTEXT.md +51 -44
  4. package/README.md +145 -172
  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-ui.js +1 -1
  14. package/dist/actors/codex/codex-admission.d.ts +91 -0
  15. package/dist/actors/codex/codex-admission.js +150 -0
  16. package/dist/actors/codex/restricted-executable.d.ts +4 -4
  17. package/dist/actors/codex/restricted-executable.js +8 -8
  18. package/dist/actors/codex/restricted-launch.d.ts +2 -1
  19. package/dist/actors/codex/restricted-launch.js +1 -1
  20. package/dist/actors/codex/restricted-participant.js +8 -6
  21. package/dist/actors/codex/restricted-policy.d.ts +2 -2
  22. package/dist/actors/codex/restricted-policy.js +2 -2
  23. package/dist/actors/codex/restricted-session.d.ts +2 -2
  24. package/dist/actors/codex/restricted-session.js +10 -5
  25. package/dist/actors/computer-use/actor.d.ts +16 -16
  26. package/dist/actors/computer-use/actor.js +2 -2
  27. package/dist/actors/computer-use/admission-limit.d.ts +1 -1
  28. package/dist/actors/computer-use/admission-limit.js +1 -1
  29. package/dist/actors/computer-use/loop/actions.d.ts +3 -3
  30. package/dist/actors/computer-use/loop/actions.js +10 -10
  31. package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
  32. package/dist/actors/computer-use/loop/backstop.js +14 -12
  33. package/dist/actors/computer-use/loop/ending.d.ts +5 -5
  34. package/dist/actors/computer-use/loop/ending.js +7 -7
  35. package/dist/actors/computer-use/loop/observation.d.ts +2 -2
  36. package/dist/actors/computer-use/loop/observation.js +9 -9
  37. package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
  38. package/dist/actors/computer-use/loop/provider-call.js +1 -1
  39. package/dist/actors/computer-use/loop/session.js +3 -3
  40. package/dist/actors/computer-use/loop/spend.d.ts +1 -1
  41. package/dist/actors/computer-use/loop/spend.js +1 -1
  42. package/dist/actors/computer-use/loop/trace.js +9 -8
  43. package/dist/actors/computer-use/loop/types.d.ts +25 -23
  44. package/dist/actors/computer-use/loop/usage.js +2 -2
  45. package/dist/actors/computer-use/openai-context.d.ts +37 -0
  46. package/dist/actors/computer-use/openai-context.js +214 -0
  47. package/dist/actors/computer-use/openai-provider.d.ts +11 -8
  48. package/dist/actors/computer-use/openai-provider.js +45 -34
  49. package/dist/actors/computer-use/openai-requests.d.ts +36 -10
  50. package/dist/actors/computer-use/openai-requests.js +82 -15
  51. package/dist/actors/computer-use/openai-wire.d.ts +19 -7
  52. package/dist/actors/computer-use/openai-wire.js +36 -34
  53. package/dist/actors/contract.d.ts +78 -43
  54. package/dist/actors/contract.js +29 -23
  55. package/dist/actors/local-agent/claude-session.d.ts +1 -1
  56. package/dist/actors/local-agent/claude-session.js +10 -9
  57. package/dist/actors/local-agent/cli.d.ts +8 -6
  58. package/dist/actors/local-agent/cli.js +24 -28
  59. package/dist/actors/local-agent/readiness.d.ts +2 -2
  60. package/dist/actors/local-agent/readiness.js +4 -4
  61. package/dist/actors/reasoning-effort.js +6 -6
  62. package/dist/actors/registry.d.ts +10 -10
  63. package/dist/actors/registry.js +18 -17
  64. package/dist/actors/scripted-browser/actor.d.ts +8 -8
  65. package/dist/actors/scripted-browser/actor.js +16 -16
  66. package/dist/actors/scripted-browser/browser-command.js +1 -1
  67. package/dist/actors/scripted-browser/steps.js +1 -1
  68. package/dist/actors/scripted-browser/types.d.ts +1 -1
  69. package/dist/actors/stop-conditions.d.ts +1 -1
  70. package/dist/analysis/codex-config.d.ts +6 -2
  71. package/dist/analysis/codex-config.js +22 -14
  72. package/dist/analysis/service.js +5 -5
  73. package/dist/cli/commands/analyze.js +19 -16
  74. package/dist/cli/commands/codex.js +9 -9
  75. package/dist/cli/commands/comms.js +54 -33
  76. package/dist/cli/commands/feedback.js +20 -21
  77. package/dist/cli/commands/lab-format.d.ts +5 -4
  78. package/dist/cli/commands/lab-format.js +35 -23
  79. package/dist/cli/commands/lab-route-computer-use.js +6 -7
  80. package/dist/cli/commands/lab-route-preview.js +4 -3
  81. package/dist/cli/commands/lab-route-shared-world.js +3 -3
  82. package/dist/cli/commands/lab-run.js +10 -11
  83. package/dist/cli/commands/lab-scorer.d.ts +2 -2
  84. package/dist/cli/commands/lab-scorer.js +1 -1
  85. package/dist/cli/commands/migrate.d.ts +4 -0
  86. package/dist/cli/commands/migrate.js +65 -0
  87. package/dist/cli/commands/observe.js +147 -108
  88. package/dist/cli/commands/run-command.d.ts +10 -0
  89. package/dist/cli/commands/run-command.js +85 -0
  90. package/dist/cli/commands/runs.js +137 -138
  91. package/dist/cli/commands/setup.d.ts +2 -2
  92. package/dist/cli/commands/setup.js +26 -21
  93. package/dist/cli/commands/study.d.ts +3 -0
  94. package/dist/cli/commands/study.js +182 -0
  95. package/dist/cli/commands/tui.d.ts +4 -4
  96. package/dist/cli/commands/tui.js +21 -21
  97. package/dist/cli/commands/watch.js +60 -75
  98. package/dist/cli/deprecations.d.ts +18 -0
  99. package/dist/cli/deprecations.js +48 -0
  100. package/dist/cli/doctor.d.ts +15 -5
  101. package/dist/cli/doctor.js +103 -48
  102. package/dist/cli/first-run-path.d.ts +12 -10
  103. package/dist/cli/first-run-path.js +30 -28
  104. package/dist/cli/io.d.ts +41 -6
  105. package/dist/cli/io.js +97 -22
  106. package/dist/cli/observer-follow.d.ts +2 -2
  107. package/dist/cli/observer-follow.js +5 -6
  108. package/dist/cli/orientation.d.ts +6 -3
  109. package/dist/cli/orientation.js +43 -39
  110. package/dist/cli/product-sentence.d.ts +6 -0
  111. package/dist/cli/product-sentence.js +6 -0
  112. package/dist/cli/program.d.ts +6 -1
  113. package/dist/cli/program.js +109 -40
  114. package/dist/cli/telemetry.d.ts +15 -15
  115. package/dist/cli/telemetry.js +48 -40
  116. package/dist/cli.js +1 -1
  117. package/dist/comms/capture-surface.d.ts +13 -12
  118. package/dist/comms/capture-surface.js +23 -22
  119. package/dist/comms/catch-host.d.ts +7 -7
  120. package/dist/comms/catch-host.js +14 -14
  121. package/dist/comms/email-catch.d.ts +3 -3
  122. package/dist/comms/email-catch.js +8 -8
  123. package/dist/comms/external-evidence.js +2 -2
  124. package/dist/comms/extract.js +2 -2
  125. package/dist/comms/fake-inbox.d.ts +2 -2
  126. package/dist/comms/fake-inbox.js +2 -2
  127. package/dist/comms/receiving-render.d.ts +1 -1
  128. package/dist/comms/receiving-render.js +2 -2
  129. package/dist/comms/sandbox-catch-script.d.ts +6 -6
  130. package/dist/comms/sandbox-catch-script.js +6 -6
  131. package/dist/comms/sandbox-catch.d.ts +36 -37
  132. package/dist/comms/sandbox-catch.js +34 -35
  133. package/dist/comms/setup.js +42 -8
  134. package/dist/comms/thread-evidence.d.ts +1 -1
  135. package/dist/comms/thread-evidence.js +6 -6
  136. package/dist/comms/types.d.ts +6 -6
  137. package/dist/comms/types.js +3 -3
  138. package/dist/evidence/frame-signature.d.ts +1 -1
  139. package/dist/evidence/frame-signature.js +4 -4
  140. package/dist/evidence/redaction.d.ts +3 -3
  141. package/dist/evidence/redaction.js +4 -4
  142. package/dist/feedback/draft.js +36 -78
  143. package/dist/feedback/export-bundle.js +1 -1
  144. package/dist/feedback/export.d.ts +5 -1
  145. package/dist/feedback/export.js +7 -8
  146. package/dist/feedback/feedback.d.ts +2 -2
  147. package/dist/feedback/feedback.js +21 -3
  148. package/dist/guest/chromium-text.js +2 -2
  149. package/dist/guest/desktop-native.d.ts +1 -1
  150. package/dist/guest/runtime.js +1 -1
  151. package/dist/index.d.ts +12 -10
  152. package/dist/index.js +8 -6
  153. package/dist/keys/key-resolution.d.ts +5 -5
  154. package/dist/keys/key-resolution.js +23 -23
  155. package/dist/lab/adapter-extension.d.ts +7 -7
  156. package/dist/lab/adapter-extension.js +13 -36
  157. package/dist/lab/adapter-scorer-loader.d.ts +7 -7
  158. package/dist/lab/adapter-scorer-loader.js +32 -32
  159. package/dist/lab/composition-rules.js +42 -42
  160. package/dist/lab/config.js +65 -25
  161. package/dist/lab/deprecated-fields.d.ts +10 -0
  162. package/dist/lab/deprecated-fields.js +24 -0
  163. package/dist/lab/device-presets.d.ts +8 -8
  164. package/dist/lab/device-presets.js +11 -11
  165. package/dist/lab/discover.d.ts +13 -9
  166. package/dist/lab/discover.js +117 -57
  167. package/dist/lab/doctor.d.ts +10 -3
  168. package/dist/lab/doctor.js +47 -9
  169. package/dist/lab/init-templates.js +147 -147
  170. package/dist/lab/init.d.ts +1 -1
  171. package/dist/lab/init.js +41 -9
  172. package/dist/lab/keys.d.ts +2 -0
  173. package/dist/lab/keys.js +42 -8
  174. package/dist/lab/lab-deps.d.ts +7 -12
  175. package/dist/lab/parse/actors.js +9 -9
  176. package/dist/lab/parse/comms.js +5 -5
  177. package/dist/lab/parse/execution.js +13 -13
  178. package/dist/lab/parse/study-v3.d.ts +23 -0
  179. package/dist/lab/parse/study-v3.js +259 -0
  180. package/dist/lab/parse/subject-state.d.ts +7 -7
  181. package/dist/lab/parse/subject-state.js +16 -16
  182. package/dist/lab/parse/subject.js +28 -28
  183. package/dist/lab/parse/values.d.ts +1 -1
  184. package/dist/lab/parse/values.js +3 -3
  185. package/dist/lab/persona-resolve.d.ts +4 -4
  186. package/dist/lab/persona-resolve.js +4 -4
  187. package/dist/lab/plan-participants.d.ts +2 -2
  188. package/dist/lab/plan-types.d.ts +4 -4
  189. package/dist/lab/plan.d.ts +1 -7
  190. package/dist/lab/plan.js +10 -41
  191. package/dist/lab/preflight-probes.js +11 -11
  192. package/dist/lab/preflight-result.d.ts +2 -1
  193. package/dist/lab/preflight-result.js +5 -4
  194. package/dist/lab/preflight.d.ts +7 -5
  195. package/dist/lab/preflight.js +5 -5
  196. package/dist/lab/routing.d.ts +31 -25
  197. package/dist/lab/routing.js +60 -29
  198. package/dist/lab/run-lab-events.d.ts +0 -3
  199. package/dist/lab/run-lab-events.js +0 -6
  200. package/dist/lab/run-lab-homes.d.ts +22 -10
  201. package/dist/lab/run-lab-homes.js +5 -1
  202. package/dist/lab/run-lab-options.d.ts +1 -1
  203. package/dist/lab/run-lab-options.js +16 -13
  204. package/dist/lab/summary.d.ts +7 -6
  205. package/dist/lab/summary.js +10 -10
  206. package/dist/lab/tasks.d.ts +15 -15
  207. package/dist/lab/tasks.js +14 -14
  208. package/dist/lab/types.d.ts +101 -95
  209. package/dist/lab/types.js +2 -0
  210. package/dist/lab/validation.d.ts +13 -13
  211. package/dist/lab/validation.js +44 -42
  212. package/dist/lab/warnings.d.ts +10 -0
  213. package/dist/lab/warnings.js +61 -33
  214. package/dist/library-aliases.d.ts +56 -0
  215. package/dist/library-aliases.js +22 -0
  216. package/dist/observer/artifact.d.ts +1 -1
  217. package/dist/observer/artifact.js +6 -6
  218. package/dist/observer/data.d.ts +6 -6
  219. package/dist/observer/data.js +5 -4
  220. package/dist/observer/exposure.d.ts +1 -1
  221. package/dist/observer/exposure.js +11 -11
  222. package/dist/observer/http.js +1 -1
  223. package/dist/observer/library.d.ts +1 -1
  224. package/dist/observer/library.js +4 -2
  225. package/dist/observer/listen.js +5 -4
  226. package/dist/observer/render.d.ts +1 -1
  227. package/dist/observer/render.js +10 -5
  228. package/dist/observer/run-routes.d.ts +3 -3
  229. package/dist/observer/run-routes.js +1 -1
  230. package/dist/observer/serve.js +7 -3
  231. package/dist/observer/tunnel.js +1 -1
  232. package/dist/observer-app.html +4 -4
  233. package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
  234. package/dist/routes/computer-use/bundle-parts.js +15 -15
  235. package/dist/routes/computer-use/bundle.js +3 -3
  236. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +1 -1
  237. package/dist/routes/computer-use/e2b-desktop/comms.js +14 -14
  238. package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -4
  239. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +4 -3
  240. package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -10
  241. package/dist/routes/computer-use/e2b-desktop/prepare.js +7 -7
  242. package/dist/routes/computer-use/e2b-desktop/start.js +9 -8
  243. package/dist/routes/computer-use/e2b-desktop/teardown.js +5 -4
  244. package/dist/routes/computer-use/external-comms.d.ts +1 -1
  245. package/dist/routes/computer-use/external-comms.js +1 -1
  246. package/dist/routes/computer-use/fanout-bundle.js +18 -18
  247. package/dist/routes/computer-use/fanout-records.js +10 -11
  248. package/dist/routes/computer-use/live-flush.d.ts +1 -1
  249. package/dist/routes/computer-use/live-flush.js +6 -6
  250. package/dist/routes/computer-use/live-phase.d.ts +4 -2
  251. package/dist/routes/computer-use/live-phase.js +6 -6
  252. package/dist/routes/computer-use/local-vm.js +1 -1
  253. package/dist/routes/computer-use/participant-desktop.d.ts +4 -4
  254. package/dist/routes/computer-use/participant-desktop.js +4 -4
  255. package/dist/routes/computer-use/participant-execution.d.ts +4 -4
  256. package/dist/routes/computer-use/participant-execution.js +9 -9
  257. package/dist/routes/computer-use/participant-model.d.ts +6 -0
  258. package/dist/routes/computer-use/participant-model.js +31 -13
  259. package/dist/routes/computer-use/participant-prompt.d.ts +11 -11
  260. package/dist/routes/computer-use/participant-prompt.js +6 -6
  261. package/dist/routes/computer-use/participant-runs.d.ts +7 -7
  262. package/dist/routes/computer-use/participant-runs.js +13 -13
  263. package/dist/routes/computer-use/plan.js +22 -22
  264. package/dist/routes/computer-use/preflight.js +21 -21
  265. package/dist/routes/computer-use/rerun-selection.js +1 -1
  266. package/dist/routes/computer-use/result.js +11 -11
  267. package/dist/routes/computer-use/route.d.ts +2 -1
  268. package/dist/routes/computer-use/route.js +15 -14
  269. package/dist/routes/computer-use/self-report.d.ts +7 -7
  270. package/dist/routes/computer-use/self-report.js +31 -31
  271. package/dist/routes/computer-use/setup.d.ts +1 -1
  272. package/dist/routes/computer-use/setup.js +17 -18
  273. package/dist/routes/computer-use/single-bundle.d.ts +7 -7
  274. package/dist/routes/computer-use/single-bundle.js +28 -30
  275. package/dist/routes/computer-use/subject-projection.d.ts +1 -1
  276. package/dist/routes/computer-use/subject-projection.js +6 -6
  277. package/dist/routes/computer-use/types.d.ts +40 -42
  278. package/dist/routes/computer-use/types.js +10 -10
  279. package/dist/routes/preview.d.ts +8 -2
  280. package/dist/routes/preview.js +8 -4
  281. package/dist/routes/scripted/bundle.d.ts +2 -2
  282. package/dist/routes/scripted/bundle.js +13 -12
  283. package/dist/routes/scripted/plan.d.ts +1 -1
  284. package/dist/routes/scripted/plan.js +9 -9
  285. package/dist/routes/scripted/result.js +5 -5
  286. package/dist/routes/scripted/route.js +5 -6
  287. package/dist/routes/scripted/scenario.js +2 -2
  288. package/dist/routes/scripted/setup.js +7 -7
  289. package/dist/routes/scripted/subject.js +1 -1
  290. package/dist/routes/scripted/surface-records.js +3 -3
  291. package/dist/routes/scripted/types.d.ts +3 -5
  292. package/dist/routes/scripted/types.js +1 -1
  293. package/dist/routes/shared-world/bundle-records.js +9 -8
  294. package/dist/routes/shared-world/bundle.d.ts +5 -5
  295. package/dist/routes/shared-world/bundle.js +40 -38
  296. package/dist/routes/shared-world/checkpoints.d.ts +1 -1
  297. package/dist/routes/shared-world/checkpoints.js +1 -1
  298. package/dist/routes/shared-world/comms.d.ts +5 -5
  299. package/dist/routes/shared-world/comms.js +14 -14
  300. package/dist/routes/shared-world/external-public.d.ts +4 -3
  301. package/dist/routes/shared-world/external-public.js +16 -12
  302. package/dist/routes/shared-world/handoff.d.ts +7 -6
  303. package/dist/routes/shared-world/handoff.js +65 -57
  304. package/dist/routes/shared-world/lobby-code.d.ts +2 -2
  305. package/dist/routes/shared-world/lobby-code.js +9 -9
  306. package/dist/routes/shared-world/participant-specs.d.ts +7 -6
  307. package/dist/routes/shared-world/participant-specs.js +31 -24
  308. package/dist/routes/shared-world/plan.js +7 -7
  309. package/dist/routes/shared-world/provenance.d.ts +2 -2
  310. package/dist/routes/shared-world/provenance.js +2 -2
  311. package/dist/routes/shared-world/provisioned.js +14 -13
  312. package/dist/routes/shared-world/result.js +20 -21
  313. package/dist/routes/shared-world/route.js +23 -22
  314. package/dist/routes/shared-world/setup.d.ts +3 -3
  315. package/dist/routes/shared-world/setup.js +4 -4
  316. package/dist/routes/shared-world/types.d.ts +30 -28
  317. package/dist/routes/shared-world/types.js +4 -4
  318. package/dist/routes/terminal/adapter.d.ts +3 -3
  319. package/dist/routes/terminal/adapter.js +5 -5
  320. package/dist/routes/terminal/bundle.d.ts +3 -3
  321. package/dist/routes/terminal/bundle.js +22 -21
  322. package/dist/routes/terminal/credentials.d.ts +4 -4
  323. package/dist/routes/terminal/credentials.js +7 -7
  324. package/dist/routes/terminal/dry-run.js +4 -4
  325. package/dist/routes/terminal/encoding.js +2 -2
  326. package/dist/routes/terminal/ledger.d.ts +3 -3
  327. package/dist/routes/terminal/ledger.js +14 -14
  328. package/dist/routes/terminal/live-finish.js +3 -3
  329. package/dist/routes/terminal/live-sandbox.js +12 -13
  330. package/dist/routes/terminal/persona.js +1 -1
  331. package/dist/routes/terminal/plan.js +11 -11
  332. package/dist/routes/terminal/recorder.js +2 -2
  333. package/dist/routes/terminal/result.js +8 -8
  334. package/dist/routes/terminal/route.js +6 -7
  335. package/dist/routes/terminal/sandbox.d.ts +1 -1
  336. package/dist/routes/terminal/sandbox.js +1 -1
  337. package/dist/routes/terminal/session.js +8 -7
  338. package/dist/routes/terminal/token-usage.d.ts +1 -1
  339. package/dist/routes/terminal/token-usage.js +7 -8
  340. package/dist/routes/terminal/trace.d.ts +2 -2
  341. package/dist/routes/terminal/trace.js +2 -2
  342. package/dist/routes/terminal/types.d.ts +26 -28
  343. package/dist/routes/terminal/types.js +3 -3
  344. package/dist/run/bundle-shape.js +3 -3
  345. package/dist/run/bundle.d.ts +46 -46
  346. package/dist/run/bundle.js +2 -1
  347. package/dist/run/cost-summary.js +3 -3
  348. package/dist/run/costs.js +7 -1
  349. package/dist/run/detail.d.ts +6 -6
  350. package/dist/run/detail.js +4 -4
  351. package/dist/run/dry-run-inputs.js +1 -1
  352. package/dist/run/dry-run.js +18 -18
  353. package/dist/run/judge.d.ts +19 -13
  354. package/dist/run/judge.js +18 -8
  355. package/dist/run/paths.d.ts +1 -1
  356. package/dist/run/paths.js +1 -1
  357. package/dist/run/pricing.d.ts +11 -6
  358. package/dist/run/pricing.js +20 -13
  359. package/dist/run/projection.d.ts +14 -14
  360. package/dist/run/projection.js +15 -15
  361. package/dist/run/reclaim.js +2 -2
  362. package/dist/run/results.d.ts +5 -5
  363. package/dist/run/run-index.d.ts +8 -6
  364. package/dist/run/run-index.js +15 -16
  365. package/dist/run/run-not-found.d.ts +5 -0
  366. package/dist/run/run-not-found.js +15 -0
  367. package/dist/run/run.d.ts +5 -4
  368. package/dist/run/run.js +1 -1
  369. package/dist/run/sandbox-receipts.d.ts +2 -2
  370. package/dist/run/sandbox-receipts.js +3 -3
  371. package/dist/run/shared-world-evidence.d.ts +36 -35
  372. package/dist/run/shared-world-evidence.js +4 -4
  373. package/dist/run/shared-world-shape.d.ts +1 -1
  374. package/dist/run/shared-world-shape.js +6 -6
  375. package/dist/run/stats.d.ts +12 -6
  376. package/dist/run/stats.js +116 -58
  377. package/dist/run/status.d.ts +8 -29
  378. package/dist/run/status.js +5 -27
  379. package/dist/run/stored-runs.js +2 -1
  380. package/dist/run/stream-shape.js +1 -1
  381. package/dist/run/streams.d.ts +6 -6
  382. package/dist/run/study-provenance.d.ts +47 -0
  383. package/dist/run/study-provenance.js +63 -0
  384. package/dist/run/study-result.d.ts +16 -0
  385. package/dist/run/study-result.js +9 -0
  386. package/dist/run/text.d.ts +2 -0
  387. package/dist/run/text.js +4 -0
  388. package/dist/run-lab.d.ts +7 -7
  389. package/dist/run-lab.js +1 -3
  390. package/dist/study/convert.d.ts +33 -0
  391. package/dist/study/convert.js +432 -0
  392. package/dist/study/field-paths.d.ts +12 -0
  393. package/dist/study/field-paths.js +126 -0
  394. package/dist/study/files.d.ts +26 -0
  395. package/dist/study/files.js +43 -0
  396. package/dist/study/migrate.d.ts +48 -0
  397. package/dist/study/migrate.js +408 -0
  398. package/dist/study/owned-files.d.ts +38 -0
  399. package/dist/study/owned-files.js +182 -0
  400. package/dist/subject/clone.d.ts +1 -1
  401. package/dist/subject/desktop-cli.d.ts +1 -1
  402. package/dist/subject/desktop-cli.js +2 -2
  403. package/dist/subject/local-tree-archive.js +1 -1
  404. package/dist/subject/local-tree.d.ts +1 -1
  405. package/dist/subject/node-bootstrap.js +1 -1
  406. package/dist/subject/runtime.js +8 -9
  407. package/dist/subject/serve.d.ts +1 -1
  408. package/dist/subject/serve.js +3 -3
  409. package/dist/subject/state.d.ts +1 -1
  410. package/dist/subject/steps.d.ts +5 -5
  411. package/dist/subject/steps.js +4 -4
  412. package/dist/substrates/command-failure.d.ts +3 -3
  413. package/dist/substrates/command-failure.js +3 -3
  414. package/dist/substrates/detached.d.ts +6 -6
  415. package/dist/substrates/detached.js +7 -7
  416. package/dist/substrates/e2b/cdp-probe.d.ts +9 -9
  417. package/dist/substrates/e2b/cdp-probe.js +14 -17
  418. package/dist/substrates/e2b/desktop-browser.d.ts +2 -2
  419. package/dist/substrates/e2b/desktop-browser.js +8 -8
  420. package/dist/substrates/e2b/desktop-cdp.d.ts +9 -9
  421. package/dist/substrates/e2b/desktop-cdp.js +8 -8
  422. package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
  423. package/dist/substrates/e2b/desktop-executor.js +1 -1
  424. package/dist/substrates/e2b/desktop-geometry.d.ts +3 -3
  425. package/dist/substrates/e2b/desktop-geometry.js +7 -7
  426. package/dist/substrates/e2b/desktop-media.d.ts +1 -1
  427. package/dist/substrates/e2b/desktop-media.js +1 -1
  428. package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
  429. package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
  430. package/dist/substrates/e2b/sandbox.d.ts +1 -1
  431. package/dist/substrates/e2b/sandbox.js +1 -1
  432. package/dist/substrates/e2b/sdk.d.ts +11 -11
  433. package/dist/substrates/e2b/sdk.js +6 -6
  434. package/dist/tui/actions.d.ts +1 -1
  435. package/dist/tui/actions.js +13 -13
  436. package/dist/tui/contract.d.ts +16 -16
  437. package/dist/tui/contract.js +10 -10
  438. package/dist/tui/launch.d.ts +4 -4
  439. package/dist/tui/launch.js +18 -19
  440. package/dist/tui/project.js +5 -5
  441. package/dist/tui-app.js +82 -82
  442. package/dist/verify/actor.d.ts +8 -8
  443. package/dist/verify/actor.js +36 -36
  444. package/dist/verify/artifacts.d.ts +2 -2
  445. package/dist/verify/artifacts.js +3 -3
  446. package/dist/verify/context-growth.d.ts +9 -0
  447. package/dist/verify/context-growth.js +62 -0
  448. package/dist/verify/costs.d.ts +6 -6
  449. package/dist/verify/costs.js +8 -8
  450. package/dist/verify/shared-world-concurrent.d.ts +2 -2
  451. package/dist/verify/shared-world-concurrent.js +79 -76
  452. package/dist/verify/shared-world.d.ts +2 -2
  453. package/dist/verify/shared-world.js +16 -16
  454. package/dist/verify/subject.d.ts +4 -4
  455. package/dist/verify/subject.js +18 -18
  456. package/dist/verify/verify.js +92 -43
  457. package/docs/README.md +25 -32
  458. package/docs/architecture/actor-contract.md +56 -87
  459. package/docs/architecture/desktop-sessions.md +7 -7
  460. package/docs/architecture/external-public-shared-world.md +61 -59
  461. package/docs/architecture/github-feedback-loop.md +1 -4
  462. package/docs/architecture/guest-desktop.md +2 -2
  463. package/docs/architecture/observer.md +34 -34
  464. package/docs/architecture/restricted-codex-analysis.md +34 -28
  465. package/docs/architecture/serve.md +34 -37
  466. package/docs/architecture/state-driven-executor.md +55 -58
  467. package/docs/architecture/task-protocol-support.md +5 -5
  468. package/docs/architecture/terminal-product-route.md +67 -107
  469. package/docs/contracts/README.md +24 -0
  470. package/docs/contracts/adapter-admission.md +3 -3
  471. package/docs/contracts/adapter-fixtures.md +2 -5
  472. package/docs/contracts/core.md +1 -3
  473. package/docs/contracts/errors.md +62 -0
  474. package/docs/contracts/feedback.md +8 -9
  475. package/docs/contracts/policy.md +7 -12
  476. package/docs/contracts/run-bundle.md +45 -44
  477. package/docs/contracts/schemas.md +421 -362
  478. package/docs/contracts/study-analysis.md +3 -3
  479. package/docs/contracts/study-costs.md +11 -7
  480. package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
  481. package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
  482. package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
  483. package/docs/principles/actor-fidelity.md +4 -4
  484. package/docs/principles/engineering.md +3 -3
  485. package/docs/principles/invariants-and-defaults.md +38 -38
  486. package/docs/principles/self-driving-harness.md +1 -5
  487. package/docs/principles/three-roles.md +1 -1
  488. package/docs/product/automatic-analysis.md +7 -7
  489. package/examples/participant/README.md +5 -5
  490. package/examples/participant/run.mjs +11 -10
  491. package/examples/scorer/README.md +3 -3
  492. package/examples/scorer/run.mjs +11 -12
  493. package/package.json +16 -17
  494. package/skills/humanish/SKILL.md +60 -58
  495. package/skills/humanish/agents/openai.yaml +1 -1
  496. package/AGENTS.md +0 -99
  497. package/CONTRIBUTING.md +0 -148
  498. package/dist/actors/codex/qualified-versions.d.ts +0 -72
  499. package/dist/actors/codex/qualified-versions.js +0 -132
  500. package/dist/cli/commands/lab.d.ts +0 -3
  501. package/dist/cli/commands/lab.js +0 -199
  502. package/dist/cli/renamed-options.d.ts +0 -11
  503. package/dist/cli/renamed-options.js +0 -18
  504. package/dist/observer/static.d.ts +0 -39
  505. package/dist/observer/static.js +0 -369
  506. package/docs/architecture/comms-inbox.md +0 -122
  507. package/docs/architecture/desktop-recording.md +0 -80
  508. package/docs/architecture/local-browser-runtime.md +0 -178
  509. package/docs/architecture/observer-review.md +0 -144
  510. package/docs/architecture/participant-media.md +0 -90
  511. package/docs/architecture/project-layout.md +0 -62
  512. package/docs/architecture/real-email-receiving.md +0 -136
  513. package/docs/assets/humanish-drawdb-hero.png +0 -0
  514. package/docs/assets/humanish-observer-hero.png +0 -0
  515. package/docs/goals/current.md +0 -207
  516. package/docs/product/lobby-trivia-3player-external-public.md +0 -77
  517. package/docs/product/open-source-install-experience.md +0 -240
  518. package/docs/ramp/README.md +0 -295
  519. package/docs/release/open-source-readiness.md +0 -222
  520. package/docs/release/public-readiness-standard.md +0 -210
  521. package/docs/roadmap/world-class-open-source-v0.md +0 -311
@@ -5,16 +5,12 @@ import { lstat, open, readdir, realpath } from "node:fs/promises";
5
5
  import path from "node:path";
6
6
  import { parse } from "yaml";
7
7
  import { parseLabConfig } from "./config.js";
8
- import {} from "./types.js";
8
+ import { STUDY_SCHEMA } from "./types.js";
9
9
  import { assertPreparedSelectedOutputDirectory, assertSafeOutputPathSegment, prepareSelectedOutputDirectory, readContainedRegularFile, } from "../run/contained-output.js";
10
10
  import { isNodeError } from "../run/type-guards.js";
11
- const LAB_LIST_SCHEMA = "humanish.lab-list.v1";
12
- const LAB_INSPECT_SCHEMA = "humanish.lab-inspect.v1";
13
- const committedLabsDir = path.join("humanish", "labs");
14
- const ignoredLabsDirs = [
15
- path.join(".humanish", "labs"),
16
- path.join(".humanish", "local", "labs"),
17
- ];
11
+ import { studyFileCandidates, studyFileStem, STUDY_DIRECTORIES } from "../study/files.js";
12
+ const STUDY_LIST_SCHEMA = "humanish.study-list.v1";
13
+ const STUDY_SHOW_SCHEMA = "humanish.study-show.v1";
18
14
  export async function resolveLabManifest(cwd, lab) {
19
15
  const resolvedCwd = path.resolve(cwd);
20
16
  const warnings = [];
@@ -40,16 +36,10 @@ export async function resolveLabManifest(cwd, lab) {
40
36
  contents: read.contents,
41
37
  });
42
38
  }
43
- const candidates = [
44
- { origin: "committed", relativePath: path.join(committedLabsDir, `${lab}.yaml`) },
45
- { origin: "committed", relativePath: path.join(committedLabsDir, `${lab}.yml`) },
46
- ...ignoredLabsDirs.flatMap((dir) => [
47
- { origin: "ignored", relativePath: path.join(dir, `${lab}.yaml`) },
48
- { origin: "ignored", relativePath: path.join(dir, `${lab}.yml`) },
49
- ]),
50
- ];
39
+ // A studies/ file wins over every labs/ file. The same stem under both families is an error, so
40
+ // neither file silently shadows the other.
41
+ const candidates = studyFileCandidates(lab);
51
42
  for (const candidate of candidates) {
52
- const requestedPath = path.join(resolvedCwd, candidate.relativePath);
53
43
  const read = await readManagedManifest(projectRoot, candidate.relativePath);
54
44
  if (read.status === "missing") {
55
45
  continue;
@@ -57,11 +47,18 @@ export async function resolveLabManifest(cwd, lab) {
57
47
  if (read.status === "unsafe") {
58
48
  return invalidLab({ cwd: resolvedCwd, lab, warnings }, read.message);
59
49
  }
50
+ if (candidate.directory.family === "studies") {
51
+ for (const other of candidates.filter((entry) => entry.directory.family === "labs")) {
52
+ const present = await inspectManagedPath(projectRoot, other.relativePath, "file");
53
+ if (present.status !== "missing")
54
+ return ambiguousStudy(resolvedCwd, lab, [candidate.relativePath, other.relativePath], warnings);
55
+ }
56
+ }
60
57
  return parseResolvedLab({
61
58
  cwd: resolvedCwd,
62
59
  lab,
63
- origin: candidate.origin,
64
- path: requestedPath,
60
+ origin: candidate.directory.origin,
61
+ path: path.join(resolvedCwd, candidate.relativePath),
65
62
  warnings,
66
63
  contents: read.contents,
67
64
  });
@@ -71,22 +68,21 @@ export async function resolveLabManifest(cwd, lab) {
71
68
  export async function listLabManifests(cwd) {
72
69
  const resolvedCwd = path.resolve(cwd);
73
70
  const warnings = [];
74
- const labs = new Map();
71
+ const listed = new Map();
75
72
  const projectRoot = await bindProjectRoot(resolvedCwd);
76
73
  if (!projectRoot) {
77
74
  return {
78
- schema: LAB_LIST_SCHEMA,
75
+ schema: STUDY_LIST_SCHEMA,
79
76
  ok: true,
80
77
  cwd: resolvedCwd,
81
- labs: [],
82
- warnings: ["Project root failed containment validation; managed lab manifests were skipped."],
78
+ studies: [],
79
+ warnings: ["Project root failed containment validation; study files were skipped."],
83
80
  };
84
81
  }
85
- const dirs = [
86
- { origin: "committed", relativeDir: committedLabsDir },
87
- ...ignoredLabsDirs.map((relativeDir) => ({ origin: "ignored", relativeDir })),
88
- ];
89
- for (const entry of dirs) {
82
+ let legacyFiles = 0;
83
+ // Each stem's files by directory family, to mark the stems that name a file in both.
84
+ const stems = new Map();
85
+ for (const entry of STUDY_DIRECTORIES) {
90
86
  const directory = await bindManagedDirectory(projectRoot, entry.relativeDir);
91
87
  if (directory.status === "missing") {
92
88
  continue;
@@ -107,13 +103,15 @@ export async function listLabManifests(cwd) {
107
103
  for (const name of names.filter((value) => value.endsWith(".yaml") || value.endsWith(".yml"))) {
108
104
  let relativePath;
109
105
  try {
110
- assertSafeOutputPathSegment(name, "Lab manifest name");
106
+ assertSafeOutputPathSegment(name, "Study file name");
111
107
  relativePath = path.join(entry.relativeDir, name);
112
108
  }
113
109
  catch {
114
- warnings.push(`${entry.relativeDir}: unsafe lab manifest name; skipped.`);
110
+ warnings.push(`${entry.relativeDir}: unsafe study file name; skipped.`);
115
111
  continue;
116
112
  }
113
+ const stem = stemSlot(stems, studyFileStem(name) ?? name);
114
+ stem[entry.family === "studies" ? "studies" : "legacy"] ??= relativeToCwd(resolvedCwd, path.join(resolvedCwd, relativePath));
117
115
  const requestedPath = path.join(resolvedCwd, relativePath);
118
116
  const read = await readManagedManifest(projectRoot, relativePath);
119
117
  if (read.status !== "ok") {
@@ -132,8 +130,11 @@ export async function listLabManifests(cwd) {
132
130
  warnings.push(`${relativeToCwd(resolvedCwd, requestedPath)}: ${parsed.error.message}`);
133
131
  continue;
134
132
  }
133
+ if (legacyStudyWarning(parsed.path, parsed.config.schema) !== undefined)
134
+ legacyFiles += 1;
135
135
  const key = `${parsed.config.id}:${entry.origin}:${relativeToCwd(resolvedCwd, requestedPath)}`;
136
- labs.set(key, {
136
+ stem.keys.push(key);
137
+ listed.set(key, {
137
138
  id: parsed.config.id,
138
139
  source: parsed.config.subject.source,
139
140
  origin: entry.origin,
@@ -146,11 +147,24 @@ export async function listLabManifests(cwd) {
146
147
  });
147
148
  }
148
149
  }
150
+ if (legacyFiles > 0) {
151
+ warnings.push(`${legacyFiles === 1 ? "One study file uses" : `${legacyFiles} study files use`} humanish.lab.v2 or a labs/ directory, which 0.109 stops reading. humanish migrate converts and moves the v2 files; humanish study show names the fix for each file.`);
152
+ }
153
+ for (const [name, stem] of stems) {
154
+ if (stem.studies === undefined || stem.legacy === undefined)
155
+ continue;
156
+ const error = `${name} names two files, ${stem.studies} and ${stem.legacy}; running it by name fails until you delete one (humanish migrate moves a kept labs/ file).`;
157
+ for (const key of stem.keys) {
158
+ const entry = listed.get(key);
159
+ if (entry)
160
+ entry.error = error;
161
+ }
162
+ }
149
163
  return {
150
- schema: LAB_LIST_SCHEMA,
164
+ schema: STUDY_LIST_SCHEMA,
151
165
  ok: true,
152
166
  cwd: resolvedCwd,
153
- labs: [...labs.values()].sort((left, right) => `${left.origin}:${left.id}`.localeCompare(`${right.origin}:${right.id}`)),
167
+ studies: [...listed.values()].sort((left, right) => `${left.origin}:${left.id}`.localeCompare(`${right.origin}:${right.id}`)),
154
168
  warnings,
155
169
  };
156
170
  }
@@ -158,10 +172,10 @@ export async function inspectLabManifest(cwd, lab) {
158
172
  const resolved = await resolveLabManifest(cwd, lab);
159
173
  if (!resolved.ok) {
160
174
  return {
161
- schema: LAB_INSPECT_SCHEMA,
175
+ schema: STUDY_SHOW_SCHEMA,
162
176
  ok: false,
163
177
  cwd: resolved.cwd,
164
- lab,
178
+ study: lab,
165
179
  error: resolved.error,
166
180
  warnings: resolved.warnings,
167
181
  };
@@ -174,23 +188,23 @@ export async function inspectLabManifest(cwd, lab) {
174
188
  if (!(error instanceof PersonaConfigError))
175
189
  throw error;
176
190
  return {
177
- schema: LAB_INSPECT_SCHEMA,
191
+ schema: STUDY_SHOW_SCHEMA,
178
192
  ok: false,
179
193
  cwd: path.resolve(cwd),
180
- lab,
181
- error: { code: "HUMANISH_LAB_INVALID", message: error.message },
194
+ study: lab,
195
+ error: { code: "HUMANISH_STUDY_INVALID", message: error.message },
182
196
  warnings: resolved.warnings,
183
197
  };
184
198
  }
185
199
  return {
186
- schema: LAB_INSPECT_SCHEMA,
200
+ schema: STUDY_SHOW_SCHEMA,
187
201
  personas: labPersonaIds(resolved.config).map((id) => {
188
202
  const persona = personaResolution.personas.get(id);
189
203
  return { id, resolved: !!persona, ...(persona ? { brief: personaBrief(persona) } : {}) };
190
204
  }),
191
205
  ok: true,
192
206
  cwd: path.resolve(cwd),
193
- lab,
207
+ study: lab,
194
208
  config: resolved.config,
195
209
  origin: resolved.origin,
196
210
  path: resolved.path,
@@ -203,13 +217,16 @@ function parseResolvedLab(args) {
203
217
  raw = parse(args.contents);
204
218
  }
205
219
  catch (error) {
206
- return invalidLab(args, error instanceof Error ? error.message : "Lab YAML could not be parsed.");
220
+ return invalidLab(args, error instanceof Error ? error.message : "The study file's YAML could not be parsed.");
207
221
  }
208
222
  const parsed = parseLabConfig(raw);
209
223
  if (!parsed.ok) {
210
224
  return invalidLab(args, parsed.error.message);
211
225
  }
212
226
  const warnings = [...args.warnings, ...parsed.warnings];
227
+ const legacy = legacyStudyWarning(relativeToCwd(args.cwd, args.path), parsed.config.schema);
228
+ if (legacy !== undefined)
229
+ warnings.push(legacy);
213
230
  if (args.path.endsWith(".yml")) {
214
231
  warnings.push("Prefer .yaml for humanish-authored lab source; .yml is accepted for compatibility only.");
215
232
  }
@@ -221,6 +238,24 @@ function parseResolvedLab(args) {
221
238
  warnings,
222
239
  };
223
240
  }
241
+ /**
242
+ * What 0.109 stops reading in this file: the humanish.lab.v2 format, a labs/ directory, or both, and
243
+ * what to run about it. Undefined for a v3 file outside the labs/ directories.
244
+ */
245
+ function legacyStudyWarning(relativePath, schema) {
246
+ const retiredDirectory = STUDY_DIRECTORIES.find((directory) => directory.family === "labs" && path.dirname(relativePath) === directory.relativeDir);
247
+ // A file discovery parsed has one of two schemas, so not v3 is v2.
248
+ const v2 = schema !== STUDY_SCHEMA;
249
+ if (retiredDirectory !== undefined) {
250
+ const studies = retiredDirectory.relativeDir.replace(/labs$/, "studies");
251
+ return v2
252
+ ? `${relativePath} is a humanish.lab.v2 file in ${retiredDirectory.relativeDir}/, and 0.109 reads neither. Run humanish migrate to convert it and move it to ${studies}/.`
253
+ : `${relativePath} is in ${retiredDirectory.relativeDir}/, which 0.109 stops reading. Move it to ${studies}/.`;
254
+ }
255
+ return v2
256
+ ? `${relativePath} is a humanish.lab.v2 file, which 0.109 stops reading. Run humanish migrate ${relativePath} to convert it.`
257
+ : undefined;
258
+ }
224
259
  async function bindProjectRoot(cwd) {
225
260
  try {
226
261
  const lexical = await lstat(cwd);
@@ -242,7 +277,7 @@ async function readManagedManifest(projectRoot, relativePath) {
242
277
  if (!contents) {
243
278
  return {
244
279
  status: "unsafe",
245
- message: "Managed lab manifest changed or failed containment validation.",
280
+ message: "The study file changed or failed containment validation.",
246
281
  };
247
282
  }
248
283
  return { status: "ok", contents: contents.toString("utf8") };
@@ -264,7 +299,7 @@ async function readExplicitManifest(projectRoot, requestedPath) {
264
299
  if (!before.isFile() || before.isSymbolicLink() || before.nlink !== 1n) {
265
300
  return {
266
301
  status: "unsafe",
267
- message: "Explicit lab manifest must resolve to a single-link regular file.",
302
+ message: "The study file path must resolve to a single-link regular file.",
268
303
  };
269
304
  }
270
305
  const handle = await open(physicalPath, constants.O_RDONLY | constants.O_NOFOLLOW);
@@ -276,7 +311,7 @@ async function readExplicitManifest(projectRoot, requestedPath) {
276
311
  opened.ino !== before.ino) {
277
312
  return {
278
313
  status: "unsafe",
279
- message: "Explicit lab manifest changed before it could be read safely.",
314
+ message: "The study file changed before it could be read safely.",
280
315
  };
281
316
  }
282
317
  const contents = await handle.readFile();
@@ -293,7 +328,7 @@ async function readExplicitManifest(projectRoot, requestedPath) {
293
328
  after.ino !== before.ino) {
294
329
  return {
295
330
  status: "unsafe",
296
- message: "Explicit lab manifest changed while it was being read.",
331
+ message: "The study file changed while it was being read.",
297
332
  };
298
333
  }
299
334
  return { status: "ok", contents: contents.toString("utf8") };
@@ -303,7 +338,7 @@ async function readExplicitManifest(projectRoot, requestedPath) {
303
338
  }
304
339
  }
305
340
  catch {
306
- return { status: "unsafe", message: "Explicit lab manifest failed containment validation." };
341
+ return { status: "unsafe", message: "The study file path failed containment validation." };
307
342
  }
308
343
  }
309
344
  async function bindManagedDirectory(projectRoot, relativePath) {
@@ -327,7 +362,7 @@ async function inspectManagedPath(projectRoot, relativePath, expectedKind) {
327
362
  const segments = relativePath.replace(/\\/g, "/").split("/");
328
363
  let current = projectRoot.physicalPath;
329
364
  for (const [index, segment] of segments.entries()) {
330
- assertSafeOutputPathSegment(segment, "Managed lab path segment");
365
+ assertSafeOutputPathSegment(segment, "Study file path segment");
331
366
  current = path.join(current, segment);
332
367
  let stats;
333
368
  try {
@@ -341,18 +376,21 @@ async function inspectManagedPath(projectRoot, relativePath, expectedKind) {
341
376
  }
342
377
  const leaf = index === segments.length - 1;
343
378
  if (stats.isSymbolicLink()) {
344
- return { status: "unsafe", message: "Managed lab paths must not contain symbolic links." };
379
+ return {
380
+ status: "unsafe",
381
+ message: "Study directory paths must not contain symbolic links.",
382
+ };
345
383
  }
346
384
  if (!leaf && !stats.isDirectory()) {
347
- return { status: "unsafe", message: "Managed lab path parents must be directories." };
385
+ return { status: "unsafe", message: "Study file path parents must be directories." };
348
386
  }
349
387
  if (leaf && expectedKind === "directory" && !stats.isDirectory()) {
350
- return { status: "unsafe", message: "Managed lab directory has an unsafe file type." };
388
+ return { status: "unsafe", message: "A study directory has an unsafe file type." };
351
389
  }
352
390
  if (leaf && expectedKind === "file" && (!stats.isFile() || stats.nlink !== 1n)) {
353
391
  return {
354
392
  status: "unsafe",
355
- message: "Managed lab manifest must be a single-link regular file.",
393
+ message: "A study file must be a single-link regular file.",
356
394
  };
357
395
  }
358
396
  if (leaf) {
@@ -368,7 +406,7 @@ async function inspectManagedPath(projectRoot, relativePath, expectedKind) {
368
406
  }
369
407
  }
370
408
  catch {
371
- return { status: "unsafe", message: "Managed lab path failed containment validation." };
409
+ return { status: "unsafe", message: "A study file path failed containment validation." };
372
410
  }
373
411
  return { status: "missing" };
374
412
  }
@@ -387,22 +425,44 @@ function invalidLab(args, message) {
387
425
  return {
388
426
  ok: false,
389
427
  cwd: args.cwd,
390
- lab: args.lab,
428
+ study: args.lab,
391
429
  error: {
392
- code: "HUMANISH_LAB_INVALID",
430
+ code: "HUMANISH_STUDY_INVALID",
393
431
  message,
394
432
  },
395
433
  warnings: args.warnings,
396
434
  };
397
435
  }
436
+ function stemSlot(stems, name) {
437
+ let slot = stems.get(name);
438
+ if (slot === undefined) {
439
+ slot = { keys: [] };
440
+ stems.set(name, slot);
441
+ }
442
+ return slot;
443
+ }
444
+ /** The same stem under a studies/ and a labs/ directory: discovery reads neither. */
445
+ function ambiguousStudy(cwd, name, paths, warnings) {
446
+ const [studiesPath, labsPath] = paths.map((entry) => entry.replace(/\\/g, "/"));
447
+ return {
448
+ ok: false,
449
+ cwd,
450
+ study: name,
451
+ error: {
452
+ code: "HUMANISH_STUDY_AMBIGUOUS",
453
+ message: `${name} names two files, ${studiesPath} and ${labsPath}. Delete the one you do not want; if you keep ${labsPath}, run humanish migrate to move it. Or pass the path of the one to run.`,
454
+ },
455
+ warnings,
456
+ };
457
+ }
398
458
  function labNotFound(cwd, lab, warnings) {
399
459
  return {
400
460
  ok: false,
401
461
  cwd,
402
- lab,
462
+ study: lab,
403
463
  error: {
404
- code: "HUMANISH_LAB_NOT_FOUND",
405
- message: `Lab not found: ${lab}. Look in humanish/labs/ or pass a .yaml path.`,
464
+ code: "HUMANISH_STUDY_NOT_FOUND",
465
+ message: `Study not found: ${lab}. Look in humanish/studies/ or humanish/labs/, or pass a .yaml path.`,
406
466
  },
407
467
  warnings,
408
468
  };
@@ -3,10 +3,10 @@ import type { LabConfig } from "./types.js";
3
3
  import type { PlanResult } from "./plan-types.js";
4
4
  import type { DetectedLocalAgent } from "../actors/local-agent/cli.js";
5
5
  import type { ReasoningEffort } from "../actors/reasoning-effort.js";
6
- import type { DoctorResult } from "../cli/doctor.js";
7
- import { type CodexInstallation } from "../actors/codex/qualified-versions.js";
6
+ import type { DoctorCheckDraft } from "../cli/doctor.js";
7
+ import { type CodexInstallation } from "../actors/codex/codex-admission.js";
8
8
  import type { RefusedCodexExecutable } from "../actors/codex/restricted-executable.js";
9
- type Check = DoctorResult["checks"][number];
9
+ type Check = DoctorCheckDraft;
10
10
  /**
11
11
  * Read-only Codex account readiness. An unadmitted CLI also reports the release it found, and an
12
12
  * unavailable one the file humanish found and turned down.
@@ -66,6 +66,13 @@ export declare function labSetupChecks(args: LabSetupCheckArgs): Promise<{
66
66
  reads?: ReadonlySet<string>;
67
67
  checks: Check[];
68
68
  }>;
69
+ /**
70
+ * The ids of the project's labs that need each provider key for a live run, from the same plan
71
+ * `doctor --lab` reads. Each listed manifest resolves by its path, since a file name need not match
72
+ * the id inside. A lab that runs dry, that the plain CLI cannot run, or that does not plan needs
73
+ * none.
74
+ */
75
+ export declare function studiesByRequiredKey(cwd: string, keyPresent: (name: string) => boolean): Promise<Map<string, string[]>>;
69
76
  /**
70
77
  * The lab planned with no run options, so its own scenario mode decides dry or live. Doctor and the
71
78
  * TUI read a live run's keys and subject env from this plan's requirements.
@@ -6,7 +6,7 @@ import { protocolAdditionsWarning, protocolIncompatibilityMessage, } from "../ac
6
6
  import { automaticAnalysisBudget } from "../analysis/automatic-config.js";
7
7
  import { externalCatchHealthy } from "../comms/sandbox-catch.js";
8
8
  import { receivingRequiredKey } from "../comms/setup.js";
9
- import { classifyCodexInstallation, codexInstallAdvice, codexVersionRecovery, } from "../actors/codex/qualified-versions.js";
9
+ import { classifyCodexInstallation, codexInstallAdvice, codexVersionRecovery, } from "../actors/codex/codex-admission.js";
10
10
  /** A ready row's message, with the schema values the launch recorded. */
11
11
  function readyMessage(message, readiness) {
12
12
  const additions = protocolAdditionsWarning(readiness.cliVersion, readiness.protocolAdditions);
@@ -110,10 +110,24 @@ export async function localCodexParticipantCheck(args) {
110
110
  name: "local participant authentication",
111
111
  ok: readiness.ready,
112
112
  message: readiness.ready
113
- ? readyMessage("Qualified Codex CLI and ChatGPT login are ready for restricted local browser participants. No E2B or model API key is required; inference is remote, and model access and account quota remain untested.", readiness)
113
+ ? readyMessage("Codex CLI and ChatGPT login are ready for restricted local browser participants. No E2B or model API key is required; inference is remote, and model access and account quota remain untested.", readiness)
114
114
  : `Local Codex participant setup is unavailable (${readiness.errorCode}). ${codexRecovery(readiness, "Install the supported Codex CLI version and sign in with a ChatGPT account.")} No API fallback is used.`,
115
115
  };
116
116
  }
117
+ /**
118
+ * The discovery and planning functions doctor's study checks use, loaded on first use as
119
+ * labSetupChecks always loaded them, so they stay out of this module's static imports.
120
+ */
121
+ async function studyLoaders() {
122
+ const discover = await import("./discover.js");
123
+ const plan = await import("./plan.js");
124
+ return {
125
+ listStudies: discover.listLabManifests,
126
+ resolveStudy: discover.resolveLabManifest,
127
+ resolveDryRun: plan.resolveLabDryRun,
128
+ routeOf: plan.routeOf,
129
+ };
130
+ }
117
131
  /**
118
132
  * Setup checks only: no model turn, browser or desktop creation. CLI startup may use the network.
119
133
  * `keys` are the keys a live run requires. `reads` are the provider keys the lab is known to read,
@@ -121,9 +135,8 @@ export async function localCodexParticipantCheck(args) {
121
135
  * scorer's host code may read any key.
122
136
  */
123
137
  export async function labSetupChecks(args) {
124
- const { resolveLabManifest } = await import("./discover.js");
125
- const { resolveLabDryRun, routeOf } = await import("./plan.js");
126
- const resolved = await resolveLabManifest(args.cwd, args.lab);
138
+ const { resolveStudy, resolveDryRun, routeOf } = await studyLoaders();
139
+ const resolved = await resolveStudy(args.cwd, args.lab);
127
140
  if (!resolved.ok)
128
141
  return {
129
142
  desktop: false,
@@ -131,7 +144,7 @@ export async function labSetupChecks(args) {
131
144
  checks: [{ name: "lab", ok: false, message: resolved.error.message }],
132
145
  };
133
146
  const config = resolved.config, route = routeOf(config);
134
- const dryRun = resolveLabDryRun(config, undefined, true) === true;
147
+ const dryRun = resolveDryRun(config, undefined, true) === true;
135
148
  const checks = [
136
149
  {
137
150
  name: "lab route",
@@ -298,19 +311,21 @@ async function analysisCheck(analysis, args, checkAccount) {
298
311
  ? "Use Linux x64 or the Apple Silicon Mac with a supported Codex CLI, or explicitly select provider: openai with an API key."
299
312
  : readiness.errorCode === "codex_busy"
300
313
  ? "Another restricted Codex analyst or setup check is active in this process. Wait for it to finish, then retry."
301
- : codexRecovery(readiness, "Install the qualified CLI and sign in with a ChatGPT account.");
314
+ : codexRecovery(readiness, "Install the Codex CLI and sign in with a ChatGPT account.");
302
315
  return {
303
316
  name: "post-run analysis",
304
317
  ok: readiness.ready,
305
318
  message: readiness.ready
306
- ? readyMessage("Qualified Codex CLI and ChatGPT account login are ready for a separate restricted analyst. Analysis sends selected evidence to remote inference; model access and account allowance remain untested. Dollar cost and output-token ceilings are unavailable.", readiness)
319
+ ? readyMessage("Codex CLI and ChatGPT account login are ready for a separate restricted analyst. Analysis sends selected evidence to remote inference; model access and account allowance remain untested. Dollar cost and output-token ceilings are unavailable.", readiness)
307
320
  : `Codex account analysis is unavailable (${readiness.errorCode ?? "codex_unavailable"}). ${recovery} No API fallback is used; participant readiness is independent.`,
308
321
  };
309
322
  }
323
+ const keyed = args.keyPresent("OPENAI_API_KEY");
310
324
  return {
311
325
  name: "post-run analysis",
312
326
  ok: true,
313
- message: args.keyPresent("OPENAI_API_KEY")
327
+ ...(keyed ? {} : { status: "note" }),
328
+ message: keyed
314
329
  ? `OPENAI_API_KEY is present for the separate automatic analysis request; model access and quota are not tested. The analysis is refused before it starts if its estimate is over $${analysis.maxCostUsd}; this is not a billing cap. Participant readiness is independent.`
315
330
  : "Will be skipped: OPENAI_API_KEY is missing. The participant may run, but there will be no automatic findings report. Add an OpenAI API key or set review.analysis: false deliberately.",
316
331
  };
@@ -325,6 +340,29 @@ function checkScope(analysis) {
325
340
  : "Local setup only. Provider credentials are not validated, model access/quota and target reachability are untested, and no paid resources were created.",
326
341
  };
327
342
  }
343
+ /**
344
+ * The ids of the project's labs that need each provider key for a live run, from the same plan
345
+ * `doctor --lab` reads. Each listed manifest resolves by its path, since a file name need not match
346
+ * the id inside. A lab that runs dry, that the plain CLI cannot run, or that does not plan needs
347
+ * none.
348
+ */
349
+ export async function studiesByRequiredKey(cwd, keyPresent) {
350
+ const { listStudies, resolveStudy, resolveDryRun, routeOf } = await studyLoaders();
351
+ const users = new Map();
352
+ for (const entry of (await listStudies(cwd)).studies) {
353
+ const resolved = await resolveStudy(cwd, entry.path);
354
+ if (!resolved.ok || resolveDryRun(resolved.config, undefined, true) === true)
355
+ continue;
356
+ if (unsupportedCliRoute(resolved.config, routeOf(resolved.config)))
357
+ continue;
358
+ const planned = await planCliRun(resolved.config, cwd);
359
+ if (!planned.ok)
360
+ continue;
361
+ for (const key of requiredKeys(planned.planned.plan.requirements, keyPresent))
362
+ users.set(key, (users.get(key) ?? new Set()).add(entry.id));
363
+ }
364
+ return new Map([...users].map(([key, ids]) => [key, [...ids]]));
365
+ }
328
366
  /**
329
367
  * The lab planned with no run options, so its own scenario mode decides dry or live. Doctor and the
330
368
  * TUI read a live run's keys and subject env from this plan's requirements.