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
@@ -6,7 +6,7 @@ export interface BlockerFacts {
6
6
  completionReason: ActorCompletionReason;
7
7
  /** A harness-owned stop condition ended the session: a matched stopWhen or a completed dwell window. */
8
8
  stopConditionMatched: boolean;
9
- /** What the participant declared in a field, when its provider has one (#570). */
9
+ /** What the participant declared in a field, when its provider has one. */
10
10
  declaredOutcome?: ParticipantDeclaredOutcome;
11
11
  /** The route's reading of the closing report: it describes a blocker or asks for instructions. */
12
12
  closingReportReadsBlocked: boolean;
@@ -23,7 +23,7 @@ export interface SessionEnding extends BlockerFacts {
23
23
  export declare function hollowCompletion(ending: SessionEnding): boolean;
24
24
  /**
25
25
  * The participant said it reached the goal but reported a blocker. A declared outcome is its own
26
- * word and wins (#570). Without one, the closing report is read, unless a stop condition ended the
26
+ * word and wins. Without one, the closing report is read, unless a stop condition ended the
27
27
  * session: a matched stopWhen is structured completion evidence and overrides the text.
28
28
  */
29
29
  export declare function selfReportedBlocker(ending: BlockerFacts): boolean;
@@ -60,12 +60,18 @@ export declare function participantHarnessFailed(participant: ParticipantFacts):
60
60
  * goal_satisfied claim with zero engagement is a session that ran out before anything happened;
61
61
  * one whose final message describes a blocker is a participant who could not proceed and said so.
62
62
  * Both keep their trace status (the claim is evidence); neither is a participant who reached the
63
- * goal. One rule for the single participant and the fan-out roll-up (#476).
63
+ * goal. One rule for the single participant and the fan-out roll-up.
64
64
  */
65
65
  export declare function participantStatus(status: ActorStatus, judgments: {
66
66
  noEngagement: boolean;
67
67
  selfReportedBlocker: boolean;
68
68
  } | undefined): ActorStatus;
69
+ /**
70
+ * A verdict as review.md prints it. The schema keeps `contract_proof_only`, which a dry run always
71
+ * gets and a live run gets while it is in progress or when no participant result came back, so
72
+ * the reader sees "dry run" or "no verdict" by the run's mode.
73
+ */
74
+ export declare function verdictText(verdict: Verdict, mode: "dry-run" | "live"): string;
69
75
  /** The review verdict for one participant's status. */
70
76
  export declare function verdictForStatus(status: ActorStatus): Verdict;
71
77
  declare const judged: unique symbol;
@@ -77,7 +83,7 @@ export interface Judgment {
77
83
  readonly verdict: Verdict;
78
84
  /**
79
85
  * The run met its route's pass rule: every expected participant passed and, on shared-world,
80
- * the seats showed the concurrency verify requires. A dry run passes as a contract.
86
+ * the participants showed the concurrency verify requires. A dry run passes as a contract.
81
87
  */
82
88
  readonly passed: boolean;
83
89
  /** A type-only mark that judgmentOf made this judgment; it does not exist at runtime. */
@@ -126,13 +132,13 @@ export interface OutcomePolicy {
126
132
  export type JudgedRoute = "computer-use" | "shared-world" | "terminal" | "scripted" | "preview";
127
133
  /** Each route's outcome policy, in one place. */
128
134
  export declare const OUTCOME_POLICIES: Readonly<Record<JudgedRoute, OutcomePolicy>>;
129
- /** What a shared-world run observed about its one world, beside how each seat ended. */
135
+ /** What a shared-world run observed about its one world, beside how each participant ended. */
130
136
  export interface SharedWorldFacts {
131
- /** Two or more seats were live at the same time. */
137
+ /** Two or more participants were live at the same time. */
132
138
  overlap: boolean;
133
139
  /** Provisioned plane only: the shared state changed at or after the first overlap started. */
134
140
  stateChangedUnderOverlap?: boolean;
135
- /** External-public plane only: every seat reached one lobby. */
141
+ /** External-public plane only: every participant reached one lobby. */
136
142
  lobbyConvergence?: boolean;
137
143
  }
138
144
  /** A shared-world run's judgment, with the world facts its review and result also report. */
@@ -162,15 +168,15 @@ export declare function judgeParticipants(args: {
162
168
  participants: ParticipantFacts[];
163
169
  }): Judgment;
164
170
  /**
165
- * Why a shared-world run whose seats all passed still fails, or undefined when its world facts
166
- * meet what verify's shared-world check requires of a pass: two seats live at the same time and,
167
- * on the provisioned plane, a shared-state change at or after the first overlap started.
171
+ * Why a shared-world run whose participants all passed still fails, or undefined when its world
172
+ * facts meet what verify's shared-world check requires of a pass: two participants live at the same
173
+ * time and, on the provisioned plane, a shared-state change at or after the first overlap started.
168
174
  */
169
175
  export declare function sharedWorldShortfall(world: SharedWorldFacts): string | undefined;
170
176
  /**
171
- * A shared-world run: it passes only when every expected seat passed and the world facts have no
172
- * shortfall, and otherwise fails (this route has no timed_out verdict). A dry run and a run still
173
- * in progress are contracts. Lobby convergence is recorded but not read.
177
+ * A shared-world run: it passes only when every expected participant passed and the world facts
178
+ * have no shortfall, and otherwise fails (this route has no timed_out verdict). A dry run and a run
179
+ * still in progress are contracts. Lobby convergence is recorded but not read.
174
180
  */
175
181
  export declare function judgeSharedWorld(args: {
176
182
  dryRun: boolean;
package/dist/run/judge.js CHANGED
@@ -24,7 +24,7 @@ export function hollowCompletion(ending) {
24
24
  }
25
25
  /**
26
26
  * The participant said it reached the goal but reported a blocker. A declared outcome is its own
27
- * word and wins (#570). Without one, the closing report is read, unless a stop condition ended the
27
+ * word and wins. Without one, the closing report is read, unless a stop condition ended the
28
28
  * session: a matched stopWhen is structured completion evidence and overrides the text.
29
29
  */
30
30
  export function selfReportedBlocker(ending) {
@@ -65,7 +65,7 @@ export function participantHarnessFailed(participant) {
65
65
  * goal_satisfied claim with zero engagement is a session that ran out before anything happened;
66
66
  * one whose final message describes a blocker is a participant who could not proceed and said so.
67
67
  * Both keep their trace status (the claim is evidence); neither is a participant who reached the
68
- * goal. One rule for the single participant and the fan-out roll-up (#476).
68
+ * goal. One rule for the single participant and the fan-out roll-up.
69
69
  */
70
70
  export function participantStatus(status, judgments) {
71
71
  if (status !== "passed" || judgments === undefined)
@@ -76,6 +76,16 @@ export function participantStatus(status, judgments) {
76
76
  return "blocked";
77
77
  return status;
78
78
  }
79
+ /**
80
+ * A verdict as review.md prints it. The schema keeps `contract_proof_only`, which a dry run always
81
+ * gets and a live run gets while it is in progress or when no participant result came back, so
82
+ * the reader sees "dry run" or "no verdict" by the run's mode.
83
+ */
84
+ export function verdictText(verdict, mode) {
85
+ if (verdict !== "contract_proof_only")
86
+ return verdict;
87
+ return mode === "dry-run" ? "dry run" : "no verdict";
88
+ }
79
89
  /** The review verdict for one participant's status. */
80
90
  export function verdictForStatus(status) {
81
91
  switch (status) {
@@ -148,9 +158,9 @@ export function judgeParticipants(args) {
148
158
  return judgmentOf(verdict, args.dryRun);
149
159
  }
150
160
  /**
151
- * Why a shared-world run whose seats all passed still fails, or undefined when its world facts
152
- * meet what verify's shared-world check requires of a pass: two seats live at the same time and,
153
- * on the provisioned plane, a shared-state change at or after the first overlap started.
161
+ * Why a shared-world run whose participants all passed still fails, or undefined when its world
162
+ * facts meet what verify's shared-world check requires of a pass: two participants live at the same
163
+ * time and, on the provisioned plane, a shared-state change at or after the first overlap started.
154
164
  */
155
165
  export function sharedWorldShortfall(world) {
156
166
  if (!world.overlap) {
@@ -162,9 +172,9 @@ export function sharedWorldShortfall(world) {
162
172
  return undefined;
163
173
  }
164
174
  /**
165
- * A shared-world run: it passes only when every expected seat passed and the world facts have no
166
- * shortfall, and otherwise fails (this route has no timed_out verdict). A dry run and a run still
167
- * in progress are contracts. Lobby convergence is recorded but not read.
175
+ * A shared-world run: it passes only when every expected participant passed and the world facts
176
+ * have no shortfall, and otherwise fails (this route has no timed_out verdict). A dry run and a run
177
+ * still in progress are contracts. Lobby convergence is recorded but not read.
168
178
  */
169
179
  export function judgeSharedWorld(args) {
170
180
  const passed = args.participants.length === args.expected &&
@@ -49,7 +49,7 @@ export declare function createRunArtifactPaths(cwdInput: string, runId: string):
49
49
  export declare function validatePreparedRunArtifactPaths(prepared: PreparedRunArtifactPaths): Promise<PreparedRunArtifactPaths>;
50
50
  /**
51
51
  * The physical project directory for a caller's cwd, bound before a run is resolved so a symlinked
52
- * cwd retargeted later cannot move reads or writes to another project (#1012). A cwd that does not
52
+ * cwd retargeted later cannot move reads or writes to another project. A cwd that does not
53
53
  * resolve is returned as given, so the caller still reports it missing.
54
54
  */
55
55
  export declare function resolvePhysicalCwd(cwdInput: string): Promise<string>;
package/dist/run/paths.js CHANGED
@@ -107,7 +107,7 @@ export async function validatePreparedRunArtifactPaths(prepared) {
107
107
  }
108
108
  /**
109
109
  * The physical project directory for a caller's cwd, bound before a run is resolved so a symlinked
110
- * cwd retargeted later cannot move reads or writes to another project (#1012). A cwd that does not
110
+ * cwd retargeted later cannot move reads or writes to another project. A cwd that does not
111
111
  * resolve is returned as given, so the caller still reports it missing.
112
112
  */
113
113
  export async function resolvePhysicalCwd(cwdInput) {
@@ -25,7 +25,7 @@ export interface ModelRate {
25
25
  inputMultiplier: number;
26
26
  outputMultiplier: number;
27
27
  };
28
- /** "YYYY-MM-DD" the entry was last checked against `source`. */
28
+ /** The `YYYY-MM-DD` date the entry was last checked against `source`. */
29
29
  asOf: string;
30
30
  /** Public pricing page the number came from (a comment/URL, never a secret). */
31
31
  source: string;
@@ -83,7 +83,7 @@ export interface ActorEstimatedCost {
83
83
  /** Of `inputTokens`, how many were billed at the reduced cached rate. Present only when the
84
84
  * provider reported cache hits and the rate sheet models a cached rate. */
85
85
  cachedInputTokens?: number;
86
- /** Of `inputTokens`, how many were billed at the cache-WRITE rate (OpenAI 5.6+). */
86
+ /** Of `inputTokens`, how many were billed at the cache-write rate (OpenAI 5.6+). */
87
87
  cacheWriteInputTokens?: number;
88
88
  /** How many requests crossed the long-context threshold and were re-tiered. Present only
89
89
  * when per-request `turns` records made exact tiering possible. */
@@ -104,6 +104,11 @@ export interface DesktopCostEstimate {
104
104
  usdPerSecond?: number;
105
105
  }
106
106
  export declare const MODEL_RATES: Record<string, ModelRate>;
107
+ /**
108
+ * The refusal for a spend cap on a model this table cannot price. It names the priced models,
109
+ * since an npm install cannot edit this file.
110
+ */
111
+ export declare function unpricedCapMessage(model: string): string;
107
112
  export declare const DESKTOP_RATE: DesktopRate;
108
113
  export declare function isDesktopResources(value: unknown): value is DesktopResources;
109
114
  /** Price one observed allocation. Missing quantities/rates stay unknown, never a stock guess. */
@@ -113,8 +118,8 @@ export declare function estimateAllocatedDesktopCost(minutes: number | undefined
113
118
  export declare function round6(n: number): number;
114
119
  /**
115
120
  * Estimate one actor trace's model-token cost from its trace tokenUsage + model id. Deterministic;
116
- * the rate table is injectable (tests pass a fake sheet). Returns a DECLARED-ABSENT estimate
117
- * (estimatedCostUsd: null + a reason) for a missing rate or missing usage — never a guessed cost.
121
+ * the rate table is injectable (tests pass a fake sheet). Returns a declared-absent estimate
122
+ * (estimatedCostUsd: null + a reason) for a missing rate or missing usage, never a guessed cost.
118
123
  */
119
124
  export declare function estimateActorCostForExecution(usage: ActorTokenUsage | undefined, modelId: string | undefined, profile?: {
120
125
  billing?: unknown;
@@ -128,7 +133,7 @@ export declare function estimateAggregatedTurnCost(tokenUsage: ActorTokenUsage |
128
133
  export declare function estimateActorCost(tokenUsage: ActorTokenUsage | undefined, modelId: string | undefined, rates?: Record<string, ModelRate>): ActorEstimatedCost;
129
134
  /**
130
135
  * Estimate the E2B desktop-minute cost from a host-side create->teardown span (minutes). The rate
131
- * is injectable. Returns a DECLARED-ABSENT estimate (null + "no_duration") when no duration was
132
- * measured (no sandbox / unmeasurable span) — never a guessed 0.
136
+ * is injectable. Returns a declared-absent estimate (null + "no_duration") when no duration was
137
+ * measured (no sandbox / unmeasurable span), never a guessed 0.
133
138
  */
134
139
  export declare function estimateDesktopCost(minutes: number | undefined, rate?: DesktopRate): DesktopCostEstimate;
@@ -6,10 +6,10 @@
6
6
  // This module is pure (node builtins only, no deps) and deterministic: the estimator functions take
7
7
  // an optional injected rate table/rate so tests drive assertions with a fake sheet and never depend
8
8
  // on the live numbers below. An unknown model/desktop rate yields a declared-absent estimate
9
- // (estimatedCostUsd: null + a reason) and never a guessed or silent-zero cost (invariant 5). A bare
9
+ // (estimatedCostUsd: null + a reason) and never a guessed or silent-zero cost. A bare
10
10
  // `costUsd` elsewhere in the contract means a provider actually billed that amount; the
11
11
  // token-derived estimate here always lives under `estimatedCostUsd` so a reader can never confuse
12
- // an estimate for an authoritative charge (invariant 6).
12
+ // an estimate for an authoritative charge.
13
13
  export const PRICING_SCHEMA = "humanish.pricing.v1";
14
14
  export const ACTOR_ESTIMATED_COST_SCHEMA = "humanish.actor-estimated-cost.v1";
15
15
  // The gpt-5.6 long-context tier: >272K input tokens re-prices the full request at 2x
@@ -44,14 +44,14 @@ const GPT6_ASTRA_AS_OF = "2026-09-03";
44
44
  // case-insensitive on a trimmed id). An id missing here is declared absent, never guessed.
45
45
  export const MODEL_RATES = {
46
46
  // OpenAI computer-use-preview (the classic CUA model). ~$3 / 1M input, ~$12 / 1M output.
47
- // source: openai.com/api/pricing (verify — providers change without notice).
47
+ // source: openai.com/api/pricing (verify: providers change without notice).
48
48
  "computer-use-preview": {
49
49
  inputUsdPerToken: 3e-6,
50
50
  outputUsdPerToken: 12e-6,
51
51
  asOf: "2026-08-01",
52
52
  source: "openai.com/api/pricing (computer-use-preview)",
53
53
  },
54
- // gpt-5.5: the PREVIOUS-generation CUA default, kept so pinned labs and old bundles still
54
+ // gpt-5.5: the previous-generation CUA default, kept so pinned labs and old bundles still
55
55
  // price. Pre-5.6 models bill no cache-write fee (prompt-caching guide) and no long-context
56
56
  // tier was published for it.
57
57
  "gpt-5.5": {
@@ -59,7 +59,7 @@ export const MODEL_RATES = {
59
59
  outputUsdPerToken: 30e-6,
60
60
  cachedInputUsdPerToken: 0.5e-6,
61
61
  asOf: "2026-08-05",
62
- source: "openrouter.ai/openai/gpt-5.5 (gpt-5.5 no longer on openai.com/api/pricing; see #334)",
62
+ source: "openrouter.ai/openai/gpt-5.5 (gpt-5.5 is no longer listed on openai.com/api/pricing)",
63
63
  },
64
64
  // The gpt-5.6 family (live sheet 2026-08-18, standard tier, short-context base rates;
65
65
  // the longContext block prices the >272K re-tier when per-request turns are recorded).
@@ -96,6 +96,13 @@ const DESKTOP_RESOURCE_RATE = {
96
96
  // 2026-09-05 had 8 vCPU / 8 GiB. This is the largest CPU/RAM combination on that public sheet, not
97
97
  // a provider billing ceiling or a claim about custom/enterprise templates. Runtime CUA estimates
98
98
  // use observed allocation resources through estimateAllocatedDesktopCost instead of this fallback.
99
+ /**
100
+ * The refusal for a spend cap on a model this table cannot price. It names the priced models,
101
+ * since an npm install cannot edit this file.
102
+ */
103
+ export function unpricedCapMessage(model) {
104
+ return `execution.caps sets a spend cap (maxUsd or maxTotalUsd), but humanish has no rate for model "${model}", so it cannot enforce the cap and refuses to start. Priced models: ${Object.keys(MODEL_RATES).sort().join(", ")}. Use one of them, or remove maxUsd and maxTotalUsd to run without a cap.`;
105
+ }
99
106
  export const DESKTOP_RATE = {
100
107
  usdPerMinute: 0.00888,
101
108
  asOf: "2026-09-05",
@@ -158,8 +165,8 @@ export function round6(n) {
158
165
  }
159
166
  /**
160
167
  * Estimate one actor trace's model-token cost from its trace tokenUsage + model id. Deterministic;
161
- * the rate table is injectable (tests pass a fake sheet). Returns a DECLARED-ABSENT estimate
162
- * (estimatedCostUsd: null + a reason) for a missing rate or missing usage — never a guessed cost.
168
+ * the rate table is injectable (tests pass a fake sheet). Returns a declared-absent estimate
169
+ * (estimatedCostUsd: null + a reason) for a missing rate or missing usage, never a guessed cost.
163
170
  */
164
171
  export function estimateActorCostForExecution(usage, modelId, profile) {
165
172
  return profile?.billing === "account-unknown"
@@ -207,7 +214,7 @@ export function estimateActorCost(tokenUsage, modelId, rates = MODEL_RATES) {
207
214
  const outTok = tokenUsage.output ?? 0;
208
215
  // Long-context tiering needs to know each request's input size (the provider re-prices whole
209
216
  // requests past the threshold), so it engages only when per-turn usage records exist and their
210
- // input sums to the reported total — a partial turn ledger must not silently price the missing
217
+ // input sums to the reported total, because a partial turn ledger must not silently price the missing
211
218
  // remainder at the wrong tier. Otherwise totals price on the base (short-context) rate, which is
212
219
  // the under-estimate direction and never trips a cap early.
213
220
  const turns = tokenUsage.turns ?? [];
@@ -232,12 +239,12 @@ export function estimateActorCost(tokenUsage, modelId, rates = MODEL_RATES) {
232
239
  // and on a session that threads provider state it is the majority of input, and pricing it at the
233
240
  // full rate overstates real spend by up to ~10x. Cache writes bill at their own rate (1.25x on
234
241
  // OpenAI 5.6+) as the total rate for those tokens; a sheet without a write rate prices writes as
235
- // plain input (pre-5.6: writes are free-of-extra-fee, i.e. plain input). Every piece is honestly
236
- // absent: no reported split means no discount and no surcharge assumed.
242
+ // plain input (pre-5.6: writes are free-of-extra-fee, i.e. plain input). An unreported piece
243
+ // stays absent: no reported split means no discount and no surcharge assumed.
237
244
  const priceRequest = (usage, tierable) => {
238
245
  const reqIn = usage.input ?? 0;
239
246
  const reqOut = usage.output ?? 0;
240
- // Tiering applies only to a real per-REQUEST record: session totals crossing the threshold
247
+ // Tiering applies only to a real per-request record: session totals crossing the threshold
241
248
  // say nothing about any single request, so totals always price on the base tier.
242
249
  const long = tierable && rate.longContext !== undefined && reqIn > rate.longContext.thresholdInputTokens;
243
250
  const inMul = long ? rate.longContext.inputMultiplier : 1;
@@ -293,8 +300,8 @@ export function estimateActorCost(tokenUsage, modelId, rates = MODEL_RATES) {
293
300
  }
294
301
  /**
295
302
  * Estimate the E2B desktop-minute cost from a host-side create->teardown span (minutes). The rate
296
- * is injectable. Returns a DECLARED-ABSENT estimate (null + "no_duration") when no duration was
297
- * measured (no sandbox / unmeasurable span) — never a guessed 0.
303
+ * is injectable. Returns a declared-absent estimate (null + "no_duration") when no duration was
304
+ * measured (no sandbox / unmeasurable span), never a guessed 0.
298
305
  */
299
306
  export function estimateDesktopCost(minutes, rate = DESKTOP_RATE) {
300
307
  if (minutes === undefined || !Number.isFinite(minutes) || minutes < 0) {
@@ -8,12 +8,12 @@ export interface LabRollup {
8
8
  live: number;
9
9
  /** The newest run of this lab, whatever its state. */
10
10
  latest?: RunIndexEntry;
11
- /** Live runs, newest first — the labs list shows the first one inline. */
11
+ /** Live runs, newest first; the labs list shows the first one inline. */
12
12
  liveRuns: RunIndexEntry[];
13
13
  }
14
14
  /**
15
15
  * Group runs by lab, newest-first within each lab and by recency between labs. Runs with no lab
16
- * attribution are collected under `unattributed` rather than invented into a lab — the honest
16
+ * attribution are collected under `unattributed` rather than invented into a study. That is the
17
17
  * home for pre-contract runs and library callers.
18
18
  */
19
19
  export declare function groupRunsByLab(entries: readonly RunIndexEntry[]): {
@@ -35,7 +35,7 @@ export interface LabExpectation {
35
35
  max: number;
36
36
  };
37
37
  medianCostUsd?: number;
38
- /** Completed runs whose cost was declared absent — excluded from the median, reported here so
38
+ /** Completed runs whose cost was declared absent: excluded from the median, reported here so
39
39
  * a partial sample can never masquerade as a full one. */
40
40
  costUnknown: number;
41
41
  }
@@ -45,7 +45,7 @@ export interface LabExpectation {
45
45
  * estimate the operator uses to decide whether to press Start.
46
46
  *
47
47
  * The mode matters: mixing modes produces a false figure. A dry run spends nothing and
48
- * takes no time, so a median over nine dry runs and one live one reports that a live run is free —
48
+ * takes no time, so a median over nine dry runs and one live one reports that a live run is free,
49
49
  * next to a control that spends money. Pass the mode the figure is about; omit it only for a
50
50
  * summary that is not attached to an action.
51
51
  */
@@ -53,7 +53,7 @@ export declare function expectationFor(entries: readonly RunIndexEntry[], mode?:
53
53
  /**
54
54
  * The one sentence the launch screen shows about time and money, with its denominator attached.
55
55
  * A lab with no history says so plainly instead of borrowing another lab's numbers or inventing
56
- * a range — "no runs yet" is information, and the operator can still press Start.
56
+ * a range. "No runs yet" is information, and the operator can still press Start.
57
57
  */
58
58
  export declare function expectationLine(expectation: LabExpectation): string;
59
59
  /**
@@ -61,7 +61,7 @@ export declare function expectationLine(expectation: LabExpectation): string;
61
61
  *
62
62
  * Prefers live figures: cost and duration are what someone reads before spending, and a median
63
63
  * diluted by dry runs reports a live study as cheaper and faster than it has ever been. With no
64
- * live history it reports the count and claims nothing about time or money — which is why this is
64
+ * live history it reports the count and claims nothing about time or money. That is why this is
65
65
  * shared rather than reimplemented per surface, since the two disagreeing is the whole failure.
66
66
  */
67
67
  export declare function labSummaryLine(row: Pick<LabRow, "runs" | "declared" | "expectation" | "liveExpectation">): string;
@@ -69,7 +69,7 @@ export declare function labSummaryLine(row: Pick<LabRow, "runs" | "declared" | "
69
69
  export declare function formatDuration(ms: number): string;
70
70
  export interface NormalizedThought {
71
71
  lines: string[];
72
- /** True when the source text did not fit and was cut — shown, never silent. */
72
+ /** True when the source text did not fit and was cut; shown, never silent. */
73
73
  truncated: boolean;
74
74
  }
75
75
  /**
@@ -77,7 +77,7 @@ export interface NormalizedThought {
77
77
  * arrive with markdown section leads (`**Thinking through setup**`) and hard newlines; a terminal
78
78
  * needs plain text wrapped to a line budget.
79
79
  *
80
- * The text is never paraphrased or shortened by meaning — only wrapped, and cut at a word boundary
80
+ * The text is never paraphrased or shortened by meaning. It is only wrapped, and cut at a word boundary
81
81
  * with an ellipsis when it does not fit. `truncated` is how the surface says so.
82
82
  */
83
83
  export declare function normalizeThought(text: string, options: {
@@ -122,7 +122,7 @@ export interface LabRow {
122
122
  /**
123
123
  * The shortest label that is unique among the rows it is listed with: the title when no other
124
124
  * lab shares it, else the filename, else the full path. A list is only navigable if every row can
125
- * be told from every other one, and a title is not guaranteed to be distinct — two manifests in
125
+ * be told from every other one, and a title is not guaranteed to be distinct: two manifests in
126
126
  * this repo carry the same title and the same declared id, differing only by filename.
127
127
  */
128
128
  label: string;
@@ -139,7 +139,7 @@ export interface LabRow {
139
139
  declared: boolean;
140
140
  /**
141
141
  * How many other manifests declare this same lab id. Above zero, the run history below is shared
142
- * between them and cannot be attributed to one file — worth saying, because it is a
142
+ * between them and cannot be attributed to one file. That is worth saying, because it is a
143
143
  * misconfiguration the operator almost certainly does not know about.
144
144
  */
145
145
  sharesIdWith: number;
@@ -149,7 +149,7 @@ export interface LabRow {
149
149
  liveRuns: RunIndexEntry[];
150
150
  /** Across every finished run, whatever its mode. A summary, never attached to a spend decision. */
151
151
  expectation: LabExpectation;
152
- /** Live runs only — the figure that belongs beside anything that spends money. */
152
+ /** Live runs only: the figure that belongs beside anything that spends money. */
153
153
  liveExpectation: LabExpectation;
154
154
  }
155
155
  export interface DeclaredLab {
@@ -163,16 +163,16 @@ export interface DeclaredLab {
163
163
  /**
164
164
  * Join declared lab manifests to run history.
165
165
  *
166
- * Neither side alone is the truth. A fresh project has manifests and no runs — those labs are the
166
+ * Neither side alone is the truth. A fresh project has manifests and no runs, and those labs are the
167
167
  * whole screen, and a list built only from history would be empty on exactly the first visit that
168
168
  * matters. A long-lived project accumulates runs from labs whose manifest has since been renamed or
169
- * deleted — that evidence still exists on disk, so dropping those rows would make real runs
169
+ * deleted. That evidence still exists on disk, so dropping those rows would make real runs
170
170
  * unreachable from the surface that is supposed to list them.
171
171
  *
172
172
  * One row per manifest, not per id. The two are not the same thing: a manifest is addressed by its
173
173
  * filename while its runs attribute to the id declared inside it, so several files can legitimately
174
174
  * share an id. Collapsing them hides a real file; keying by id duplicates a row with no way to tell
175
- * the copies apart. Both happen in practice — this repo has exactly that pair.
175
+ * the copies apart. Both happen in practice: this repo has exactly that pair.
176
176
  *
177
177
  * Order puts a lab someone is working in first, then labs by how recently they ran, then declared
178
178
  * labs that have never run (alphabetically by the displayed label, so the order on screen is the
@@ -1,22 +1,22 @@
1
- // The disk→view-model projection (#455 PR 2). Pure functions, no I/O, no rendering: this is where
1
+ // The disk→view-model projection. Pure functions, no I/O, no rendering: this is where
2
2
  // lab grouping, the trust line's arithmetic, thought normalization and list-window math live, so
3
3
  // the parts most likely to be wrong are testable without a terminal.
4
4
  //
5
- // The honesty rules these encode, because they are the ones a UI is most tempted to break:
5
+ // The rules these encode, because they are the ones a UI is most tempted to break:
6
6
  // - a statistic always carries its denominator, and says when it has none;
7
7
  // - an unknown cost is `null` (declared absent), never 0;
8
8
  // - truncation is reported, never silent;
9
9
  // - a participant's reported thinking is quoted, never paraphrased or summarized.
10
10
  /**
11
11
  * Group runs by lab, newest-first within each lab and by recency between labs. Runs with no lab
12
- * attribution are collected under `unattributed` rather than invented into a lab — the honest
12
+ * attribution are collected under `unattributed` rather than invented into a study. That is the
13
13
  * home for pre-contract runs and library callers.
14
14
  */
15
15
  export function groupRunsByLab(entries) {
16
16
  const byLab = new Map();
17
17
  const unattributed = [];
18
18
  for (const entry of entries) {
19
- const labId = entry.lab?.id;
19
+ const labId = entry.study?.id;
20
20
  if (labId === undefined) {
21
21
  unattributed.push(entry);
22
22
  continue;
@@ -63,7 +63,7 @@ function recencyOf(entry) {
63
63
  * estimate the operator uses to decide whether to press Start.
64
64
  *
65
65
  * The mode matters: mixing modes produces a false figure. A dry run spends nothing and
66
- * takes no time, so a median over nine dry runs and one live one reports that a live run is free —
66
+ * takes no time, so a median over nine dry runs and one live one reports that a live run is free,
67
67
  * next to a control that spends money. Pass the mode the figure is about; omit it only for a
68
68
  * summary that is not attached to an action.
69
69
  */
@@ -79,7 +79,7 @@ export function expectationFor(entries, mode) {
79
79
  .filter((value) => typeof value === "number" && Number.isFinite(value))
80
80
  .sort((a, b) => a - b);
81
81
  // A cost is unknown whether it was declared absent (`null`) or never recorded at all
82
- // (`undefined` — every fail-closed exit finalized with no outcome). Counting only the first
82
+ // (`undefined`: every fail-closed exit finalized with no outcome). Counting only the first
83
83
  // reports "~$1.20 median · 3 runs" for a sample where two runs were never priced, which claims a
84
84
  // denominator the figure does not have.
85
85
  const costUnknown = finished.filter((entry) => entry.estimatedCostUsd === null || entry.estimatedCostUsd === undefined).length;
@@ -104,7 +104,7 @@ function median(sorted) {
104
104
  /**
105
105
  * The one sentence the launch screen shows about time and money, with its denominator attached.
106
106
  * A lab with no history says so plainly instead of borrowing another lab's numbers or inventing
107
- * a range — "no runs yet" is information, and the operator can still press Start.
107
+ * a range. "No runs yet" is information, and the operator can still press Start.
108
108
  */
109
109
  export function expectationLine(expectation) {
110
110
  if (expectation.sample === 0)
@@ -136,7 +136,7 @@ export function expectationLine(expectation) {
136
136
  *
137
137
  * Prefers live figures: cost and duration are what someone reads before spending, and a median
138
138
  * diluted by dry runs reports a live study as cheaper and faster than it has ever been. With no
139
- * live history it reports the count and claims nothing about time or money — which is why this is
139
+ * live history it reports the count and claims nothing about time or money. That is why this is
140
140
  * shared rather than reimplemented per surface, since the two disagreeing is the whole failure.
141
141
  */
142
142
  export function labSummaryLine(row) {
@@ -162,7 +162,7 @@ export function formatDuration(ms) {
162
162
  * arrive with markdown section leads (`**Thinking through setup**`) and hard newlines; a terminal
163
163
  * needs plain text wrapped to a line budget.
164
164
  *
165
- * The text is never paraphrased or shortened by meaning — only wrapped, and cut at a word boundary
165
+ * The text is never paraphrased or shortened by meaning. It is only wrapped, and cut at a word boundary
166
166
  * with an ellipsis when it does not fit. `truncated` is how the surface says so.
167
167
  */
168
168
  export function normalizeThought(text, options) {
@@ -247,16 +247,16 @@ function labNameFromPath(manifestPath) {
247
247
  /**
248
248
  * Join declared lab manifests to run history.
249
249
  *
250
- * Neither side alone is the truth. A fresh project has manifests and no runs — those labs are the
250
+ * Neither side alone is the truth. A fresh project has manifests and no runs, and those labs are the
251
251
  * whole screen, and a list built only from history would be empty on exactly the first visit that
252
252
  * matters. A long-lived project accumulates runs from labs whose manifest has since been renamed or
253
- * deleted — that evidence still exists on disk, so dropping those rows would make real runs
253
+ * deleted. That evidence still exists on disk, so dropping those rows would make real runs
254
254
  * unreachable from the surface that is supposed to list them.
255
255
  *
256
256
  * One row per manifest, not per id. The two are not the same thing: a manifest is addressed by its
257
257
  * filename while its runs attribute to the id declared inside it, so several files can legitimately
258
258
  * share an id. Collapsing them hides a real file; keying by id duplicates a row with no way to tell
259
- * the copies apart. Both happen in practice — this repo has exactly that pair.
259
+ * the copies apart. Both happen in practice: this repo has exactly that pair.
260
260
  *
261
261
  * Order puts a lab someone is working in first, then labs by how recently they ran, then declared
262
262
  * labs that have never run (alphabetically by the displayed label, so the order on screen is the
@@ -267,7 +267,7 @@ export function labRows(declared, entries) {
267
267
  const byId = new Map(labs.map((lab) => [lab.labId, lab]));
268
268
  const runsOf = new Map();
269
269
  for (const entry of entries) {
270
- const labId = entry.lab?.id;
270
+ const labId = entry.study?.id;
271
271
  if (labId === undefined)
272
272
  continue;
273
273
  const bucket = runsOf.get(labId);
@@ -332,8 +332,8 @@ export function labRows(declared, entries) {
332
332
  /**
333
333
  * Give every row the shortest label that distinguishes it: title, else filename, else path.
334
334
  *
335
- * Falling straight back to the filename whenever a title repeats — rather than decorating the
336
- * duplicate with a suffix — keeps the label something the operator can act on, because the filename
335
+ * Falling straight back to the filename whenever a title repeats, instead of decorating the
336
+ * duplicate with a suffix, keeps the label something the operator can act on, because the filename
337
337
  * is exactly what `humanish lab run` takes.
338
338
  */
339
339
  function assignLabels(rows) {
@@ -49,8 +49,8 @@ async function reclaimRun(cwd, runInput, locate, hooks) {
49
49
  const runId = runIdOf(runPaths);
50
50
  const journal = await reclaimJournal(runPaths, hooks);
51
51
  if (journal.kind === "empty") {
52
- // Honest empty: nothing journaled means either no sandbox was ever created (cheap interrupt —
53
- // nothing to reclaim) or the run predates receipts (0.35.x and earlier — the create-time TTL
52
+ // Empty: nothing journaled means either no sandbox was ever created (cheap interrupt:
53
+ // nothing to reclaim) or the run predates receipts (0.35.x and earlier, where the create-time TTL
54
54
  // is the only backstop for those). Either way there is no id to act on, and saying so beats
55
55
  // pretending a scan happened.
56
56
  warnings.push("No sandbox-receipts.ndjson in this run dir: either no sandbox was created before the interrupt, or the run predates create-time receipts. Nothing to reclaim by id; server-side kill-on-timeout covers anything that did exist.");
@@ -1,14 +1,14 @@
1
1
  import type { ObserverResult } from "../observer/render.js";
2
2
  import type { RunProviderResource } from "./bundle.js";
3
- import type { RunLabProvenance } from "./status.js";
3
+ import type { RunStudyProvenance } from "./study-provenance.js";
4
4
  export declare const CLEANUP_SCHEMA = "humanish.cleanup-result.v1";
5
5
  export interface RunOptions {
6
- /** Which manifest produced this run (#455). */
7
- lab?: RunLabProvenance;
6
+ /** Which manifest produced this run. */
7
+ lab?: RunStudyProvenance;
8
8
  cwd: string;
9
9
  dryRun?: boolean;
10
10
  runId?: string;
11
- simCount?: number;
11
+ participantCount?: number;
12
12
  /** Render the run's Observer through the finished run, opening the page when `open` is true.
13
13
  * Without it the preview writes no observer/index.html. */
14
14
  observer?: {
@@ -30,7 +30,7 @@ export interface RunResult {
30
30
  observer?: ObserverResult;
31
31
  warnings: string[];
32
32
  error?: {
33
- code: "HUMANISH_LAB_ANALYSIS_INVALID" | "HUMANISH_LAB_ANALYSIS_UNSUPPORTED" | "HUMANISH_LAB_TASKS_UNSUPPORTED" | "HUMANISH_LAB_OPTION_UNSUPPORTED" | "HUMANISH_LAB_COMMS_UNSUPPORTED" | "HUMANISH_LIVE_RUN_UNIMPLEMENTED" | "HUMANISH_INVALID_CWD" | "HUMANISH_RUN_ID_IN_USE" | "HUMANISH_INVALID_SIM_COUNT" | "HUMANISH_INVALID_PORT" | "HUMANISH_UNSUPPORTED_RERUN_FLAGS" | "HUMANISH_WATCH_OPTION_CONFLICT" | "HUMANISH_WATCH_SAFE_NOT_APPLICABLE" | "HUMANISH_APP_URL_REMOVED" | "HUMANISH_LAB_SCORER_BAD_REF" | "HUMANISH_LAB_SCORER_NOT_FOUND" | "HUMANISH_LAB_SCORER_LOAD_FAILED" | "HUMANISH_LAB_SCORER_NO_HOOKS" | "HUMANISH_LAB_SCORER_UNSUPPORTED_BACKEND";
33
+ code: "HUMANISH_STUDY_ANALYSIS_INVALID" | "HUMANISH_STUDY_ANALYSIS_UNSUPPORTED" | "HUMANISH_STUDY_TASKS_UNSUPPORTED" | "HUMANISH_STUDY_OPTION_UNSUPPORTED" | "HUMANISH_STUDY_COMMS_UNSUPPORTED" | "HUMANISH_LIVE_RUN_UNIMPLEMENTED" | "HUMANISH_INVALID_CWD" | "HUMANISH_RUN_ID_IN_USE" | "HUMANISH_INVALID_PARTICIPANT_COUNT" | "HUMANISH_INVALID_PORT" | "HUMANISH_UNSUPPORTED_RERUN_FLAGS" | "HUMANISH_WATCH_OPTION_CONFLICT" | "HUMANISH_WATCH_SAFE_NOT_APPLICABLE" | "HUMANISH_RUN_OPTION_CONFLICT" | "HUMANISH_OBSERVE_OPTION_CONFLICT" | "HUMANISH_STUDY_SCORER_BAD_REF" | "HUMANISH_STUDY_SCORER_NOT_FOUND" | "HUMANISH_STUDY_SCORER_LOAD_FAILED" | "HUMANISH_STUDY_SCORER_NO_HOOKS" | "HUMANISH_STUDY_SCORER_UNSUPPORTED_BACKEND";
34
34
  message: string;
35
35
  };
36
36
  }
@@ -1,4 +1,5 @@
1
- import { type RunLabProvenance, type RunLiveness, type RunStatusRecord } from "./status.js";
1
+ import { type RunLiveness, type RunStatusRecord } from "./status.js";
2
+ import { type RunStudyProvenance } from "./study-provenance.js";
2
3
  declare const RUN_INDEX_SCHEMA = "humanish.run-index.v1";
3
4
  export interface RunIndexEntry {
4
5
  runId: string;
@@ -12,7 +13,7 @@ export interface RunIndexEntry {
12
13
  * one run's record carries that pid.
13
14
  */
14
15
  pid?: number;
15
- lab?: RunLabProvenance;
16
+ study?: RunStudyProvenance;
16
17
  startedAt?: string;
17
18
  updatedAt?: string;
18
19
  completedAt?: string;
@@ -31,7 +32,7 @@ export interface RunIndexResult {
31
32
  cwd: string;
32
33
  /** Newest first, by the best timestamp each entry has. */
33
34
  runs: RunIndexEntry[];
34
- /** Directories that could not be read at all, by name — surfaced, never silently dropped. */
35
+ /** Directories that could not be read at all, by name: surfaced, never silently dropped. */
35
36
  unreadable: string[];
36
37
  }
37
38
  /** What a cached entry was derived from, so a changed file invalidates exactly that entry. */
@@ -59,7 +60,8 @@ interface BundleFacts {
59
60
  runId?: string;
60
61
  mode?: string;
61
62
  createdAt?: string;
62
- lab?: RunLabProvenance;
63
+ study?: unknown;
64
+ lab?: unknown;
63
65
  persona?: {
64
66
  source?: string;
65
67
  };
@@ -95,8 +97,8 @@ export interface ReadRunIndexOptions {
95
97
  cache?: RunIndexCache;
96
98
  /** Injectable clock, so liveness classification is reproducible in tests. */
97
99
  nowMs?: number;
98
- /** Cap the number of runs returned (newest first). The full directory is still enumerated —
99
- * a cap on reads, not on truth — and the count reflects what was read. */
100
+ /** Cap the number of runs returned (newest first). The full directory is still enumerated;
101
+ * the cap limits reads, and the count reflects what was read. */
100
102
  limit?: number;
101
103
  }
102
104
  /**